CVContextData.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. import {
  2. createTypedArray,
  3. } from '../../utils/helpers/arrays';
  4. import Matrix from '../../3rd_party/transformation-matrix';
  5. function CanvasContext() {
  6. this.opacity = -1;
  7. this.transform = createTypedArray('float32', 16);
  8. this.fillStyle = '';
  9. this.strokeStyle = '';
  10. this.lineWidth = '';
  11. this.lineCap = '';
  12. this.lineJoin = '';
  13. this.miterLimit = '';
  14. this.id = Math.random();
  15. }
  16. function CVContextData() {
  17. this.stack = [];
  18. this.cArrPos = 0;
  19. this.cTr = new Matrix();
  20. var i;
  21. var len = 15;
  22. for (i = 0; i < len; i += 1) {
  23. var canvasContext = new CanvasContext();
  24. this.stack[i] = canvasContext;
  25. }
  26. this._length = len;
  27. this.nativeContext = null;
  28. this.transformMat = new Matrix();
  29. this.currentOpacity = 1;
  30. //
  31. this.currentFillStyle = '';
  32. this.appliedFillStyle = '';
  33. //
  34. this.currentStrokeStyle = '';
  35. this.appliedStrokeStyle = '';
  36. //
  37. this.currentLineWidth = '';
  38. this.appliedLineWidth = '';
  39. //
  40. this.currentLineCap = '';
  41. this.appliedLineCap = '';
  42. //
  43. this.currentLineJoin = '';
  44. this.appliedLineJoin = '';
  45. //
  46. this.appliedMiterLimit = '';
  47. this.currentMiterLimit = '';
  48. }
  49. CVContextData.prototype.duplicate = function () {
  50. var newLength = this._length * 2;
  51. var i = 0;
  52. for (i = this._length; i < newLength; i += 1) {
  53. this.stack[i] = new CanvasContext();
  54. }
  55. this._length = newLength;
  56. };
  57. CVContextData.prototype.reset = function () {
  58. this.cArrPos = 0;
  59. this.cTr.reset();
  60. this.stack[this.cArrPos].opacity = 1;
  61. };
  62. CVContextData.prototype.restore = function (forceRestore) {
  63. this.cArrPos -= 1;
  64. var currentContext = this.stack[this.cArrPos];
  65. var transform = currentContext.transform;
  66. var i;
  67. var arr = this.cTr.props;
  68. for (i = 0; i < 16; i += 1) {
  69. arr[i] = transform[i];
  70. }
  71. if (forceRestore) {
  72. this.nativeContext.restore();
  73. var prevStack = this.stack[this.cArrPos + 1];
  74. this.appliedFillStyle = prevStack.fillStyle;
  75. this.appliedStrokeStyle = prevStack.strokeStyle;
  76. this.appliedLineWidth = prevStack.lineWidth;
  77. this.appliedLineCap = prevStack.lineCap;
  78. this.appliedLineJoin = prevStack.lineJoin;
  79. this.appliedMiterLimit = prevStack.miterLimit;
  80. }
  81. this.nativeContext.setTransform(transform[0], transform[1], transform[4], transform[5], transform[12], transform[13]);
  82. if (forceRestore || (currentContext.opacity !== -1 && this.currentOpacity !== currentContext.opacity)) {
  83. this.nativeContext.globalAlpha = currentContext.opacity;
  84. this.currentOpacity = currentContext.opacity;
  85. }
  86. this.currentFillStyle = currentContext.fillStyle;
  87. this.currentStrokeStyle = currentContext.strokeStyle;
  88. this.currentLineWidth = currentContext.lineWidth;
  89. this.currentLineCap = currentContext.lineCap;
  90. this.currentLineJoin = currentContext.lineJoin;
  91. this.currentMiterLimit = currentContext.miterLimit;
  92. };
  93. CVContextData.prototype.save = function (saveOnNativeFlag) {
  94. if (saveOnNativeFlag) {
  95. this.nativeContext.save();
  96. }
  97. var props = this.cTr.props;
  98. if (this._length <= this.cArrPos) {
  99. this.duplicate();
  100. }
  101. var currentStack = this.stack[this.cArrPos];
  102. var i;
  103. for (i = 0; i < 16; i += 1) {
  104. currentStack.transform[i] = props[i];
  105. }
  106. this.cArrPos += 1;
  107. var newStack = this.stack[this.cArrPos];
  108. newStack.opacity = currentStack.opacity;
  109. newStack.fillStyle = currentStack.fillStyle;
  110. newStack.strokeStyle = currentStack.strokeStyle;
  111. newStack.lineWidth = currentStack.lineWidth;
  112. newStack.lineCap = currentStack.lineCap;
  113. newStack.lineJoin = currentStack.lineJoin;
  114. newStack.miterLimit = currentStack.miterLimit;
  115. };
  116. CVContextData.prototype.setOpacity = function (value) {
  117. this.stack[this.cArrPos].opacity = value;
  118. };
  119. CVContextData.prototype.setContext = function (value) {
  120. this.nativeContext = value;
  121. };
  122. CVContextData.prototype.fillStyle = function (value) {
  123. if (this.stack[this.cArrPos].fillStyle !== value) {
  124. this.currentFillStyle = value;
  125. this.stack[this.cArrPos].fillStyle = value;
  126. }
  127. };
  128. CVContextData.prototype.strokeStyle = function (value) {
  129. if (this.stack[this.cArrPos].strokeStyle !== value) {
  130. this.currentStrokeStyle = value;
  131. this.stack[this.cArrPos].strokeStyle = value;
  132. }
  133. };
  134. CVContextData.prototype.lineWidth = function (value) {
  135. if (this.stack[this.cArrPos].lineWidth !== value) {
  136. this.currentLineWidth = value;
  137. this.stack[this.cArrPos].lineWidth = value;
  138. }
  139. };
  140. CVContextData.prototype.lineCap = function (value) {
  141. if (this.stack[this.cArrPos].lineCap !== value) {
  142. this.currentLineCap = value;
  143. this.stack[this.cArrPos].lineCap = value;
  144. }
  145. };
  146. CVContextData.prototype.lineJoin = function (value) {
  147. if (this.stack[this.cArrPos].lineJoin !== value) {
  148. this.currentLineJoin = value;
  149. this.stack[this.cArrPos].lineJoin = value;
  150. }
  151. };
  152. CVContextData.prototype.miterLimit = function (value) {
  153. if (this.stack[this.cArrPos].miterLimit !== value) {
  154. this.currentMiterLimit = value;
  155. this.stack[this.cArrPos].miterLimit = value;
  156. }
  157. };
  158. CVContextData.prototype.transform = function (props) {
  159. this.transformMat.cloneFromProps(props);
  160. // Taking the last transform value from the stored stack of transforms
  161. var currentTransform = this.cTr;
  162. // Applying the last transform value after the new transform to respect the order of transformations
  163. this.transformMat.multiply(currentTransform);
  164. // Storing the new transformed value in the stored transform
  165. currentTransform.cloneFromProps(this.transformMat.props);
  166. var trProps = currentTransform.props;
  167. // Applying the new transform to the canvas
  168. this.nativeContext.setTransform(trProps[0], trProps[1], trProps[4], trProps[5], trProps[12], trProps[13]);
  169. };
  170. CVContextData.prototype.opacity = function (op) {
  171. var currentOpacity = this.stack[this.cArrPos].opacity;
  172. currentOpacity *= op < 0 ? 0 : op;
  173. if (this.stack[this.cArrPos].opacity !== currentOpacity) {
  174. if (this.currentOpacity !== op) {
  175. this.nativeContext.globalAlpha = op;
  176. this.currentOpacity = op;
  177. }
  178. this.stack[this.cArrPos].opacity = currentOpacity;
  179. }
  180. };
  181. CVContextData.prototype.fill = function (rule) {
  182. if (this.appliedFillStyle !== this.currentFillStyle) {
  183. this.appliedFillStyle = this.currentFillStyle;
  184. this.nativeContext.fillStyle = this.appliedFillStyle;
  185. }
  186. this.nativeContext.fill(rule);
  187. };
  188. CVContextData.prototype.fillRect = function (x, y, w, h) {
  189. if (this.appliedFillStyle !== this.currentFillStyle) {
  190. this.appliedFillStyle = this.currentFillStyle;
  191. this.nativeContext.fillStyle = this.appliedFillStyle;
  192. }
  193. this.nativeContext.fillRect(x, y, w, h);
  194. };
  195. CVContextData.prototype.stroke = function () {
  196. if (this.appliedStrokeStyle !== this.currentStrokeStyle) {
  197. this.appliedStrokeStyle = this.currentStrokeStyle;
  198. this.nativeContext.strokeStyle = this.appliedStrokeStyle;
  199. }
  200. if (this.appliedLineWidth !== this.currentLineWidth) {
  201. this.appliedLineWidth = this.currentLineWidth;
  202. this.nativeContext.lineWidth = this.appliedLineWidth;
  203. }
  204. if (this.appliedLineCap !== this.currentLineCap) {
  205. this.appliedLineCap = this.currentLineCap;
  206. this.nativeContext.lineCap = this.appliedLineCap;
  207. }
  208. if (this.appliedLineJoin !== this.currentLineJoin) {
  209. this.appliedLineJoin = this.currentLineJoin;
  210. this.nativeContext.lineJoin = this.appliedLineJoin;
  211. }
  212. if (this.appliedMiterLimit !== this.currentMiterLimit) {
  213. this.appliedMiterLimit = this.currentMiterLimit;
  214. this.nativeContext.miterLimit = this.appliedMiterLimit;
  215. }
  216. this.nativeContext.stroke();
  217. };
  218. export default CVContextData;