CanvasRendererBase.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. import {
  2. extendPrototype,
  3. } from '../utils/functionExtensions';
  4. import {
  5. createSizedArray,
  6. } from '../utils/helpers/arrays';
  7. import createTag from '../utils/helpers/html_elements';
  8. import SVGRenderer from './SVGRenderer';
  9. import BaseRenderer from './BaseRenderer';
  10. import CVShapeElement from '../elements/canvasElements/CVShapeElement';
  11. import CVTextElement from '../elements/canvasElements/CVTextElement';
  12. import CVImageElement from '../elements/canvasElements/CVImageElement';
  13. import CVSolidElement from '../elements/canvasElements/CVSolidElement';
  14. function CanvasRendererBase() {
  15. }
  16. extendPrototype([BaseRenderer], CanvasRendererBase);
  17. CanvasRendererBase.prototype.createShape = function (data) {
  18. return new CVShapeElement(data, this.globalData, this);
  19. };
  20. CanvasRendererBase.prototype.createText = function (data) {
  21. return new CVTextElement(data, this.globalData, this);
  22. };
  23. CanvasRendererBase.prototype.createImage = function (data) {
  24. return new CVImageElement(data, this.globalData, this);
  25. };
  26. CanvasRendererBase.prototype.createSolid = function (data) {
  27. return new CVSolidElement(data, this.globalData, this);
  28. };
  29. CanvasRendererBase.prototype.createNull = SVGRenderer.prototype.createNull;
  30. CanvasRendererBase.prototype.ctxTransform = function (props) {
  31. if (props[0] === 1 && props[1] === 0 && props[4] === 0 && props[5] === 1 && props[12] === 0 && props[13] === 0) {
  32. return;
  33. }
  34. this.canvasContext.transform(props[0], props[1], props[4], props[5], props[12], props[13]);
  35. };
  36. CanvasRendererBase.prototype.ctxOpacity = function (op) {
  37. this.canvasContext.globalAlpha *= op < 0 ? 0 : op;
  38. };
  39. CanvasRendererBase.prototype.ctxFillStyle = function (value) {
  40. this.canvasContext.fillStyle = value;
  41. };
  42. CanvasRendererBase.prototype.ctxStrokeStyle = function (value) {
  43. this.canvasContext.strokeStyle = value;
  44. };
  45. CanvasRendererBase.prototype.ctxLineWidth = function (value) {
  46. this.canvasContext.lineWidth = value;
  47. };
  48. CanvasRendererBase.prototype.ctxLineCap = function (value) {
  49. this.canvasContext.lineCap = value;
  50. };
  51. CanvasRendererBase.prototype.ctxLineJoin = function (value) {
  52. this.canvasContext.lineJoin = value;
  53. };
  54. CanvasRendererBase.prototype.ctxMiterLimit = function (value) {
  55. this.canvasContext.miterLimit = value;
  56. };
  57. CanvasRendererBase.prototype.ctxFill = function (rule) {
  58. this.canvasContext.fill(rule);
  59. };
  60. CanvasRendererBase.prototype.ctxFillRect = function (x, y, w, h) {
  61. this.canvasContext.fillRect(x, y, w, h);
  62. };
  63. CanvasRendererBase.prototype.ctxStroke = function () {
  64. this.canvasContext.stroke();
  65. };
  66. CanvasRendererBase.prototype.reset = function () {
  67. if (!this.renderConfig.clearCanvas) {
  68. this.canvasContext.restore();
  69. return;
  70. }
  71. this.contextData.reset();
  72. };
  73. CanvasRendererBase.prototype.save = function () {
  74. this.canvasContext.save();
  75. };
  76. CanvasRendererBase.prototype.restore = function (actionFlag) {
  77. if (!this.renderConfig.clearCanvas) {
  78. this.canvasContext.restore();
  79. return;
  80. }
  81. if (actionFlag) {
  82. this.globalData.blendMode = 'source-over';
  83. }
  84. this.contextData.restore(actionFlag);
  85. };
  86. CanvasRendererBase.prototype.configAnimation = function (animData) {
  87. if (this.animationItem.wrapper) {
  88. this.animationItem.container = createTag('canvas');
  89. var containerStyle = this.animationItem.container.style;
  90. containerStyle.width = '100%';
  91. containerStyle.height = '100%';
  92. var origin = '0px 0px 0px';
  93. containerStyle.transformOrigin = origin;
  94. containerStyle.mozTransformOrigin = origin;
  95. containerStyle.webkitTransformOrigin = origin;
  96. containerStyle['-webkit-transform'] = origin;
  97. containerStyle.contentVisibility = this.renderConfig.contentVisibility;
  98. this.animationItem.wrapper.appendChild(this.animationItem.container);
  99. this.canvasContext = this.animationItem.container.getContext('2d');
  100. if (this.renderConfig.className) {
  101. this.animationItem.container.setAttribute('class', this.renderConfig.className);
  102. }
  103. if (this.renderConfig.id) {
  104. this.animationItem.container.setAttribute('id', this.renderConfig.id);
  105. }
  106. } else {
  107. this.canvasContext = this.renderConfig.context;
  108. }
  109. this.contextData.setContext(this.canvasContext);
  110. this.data = animData;
  111. this.layers = animData.layers;
  112. this.transformCanvas = {
  113. w: animData.w,
  114. h: animData.h,
  115. sx: 0,
  116. sy: 0,
  117. tx: 0,
  118. ty: 0,
  119. };
  120. this.setupGlobalData(animData, document.body);
  121. this.globalData.canvasContext = this.canvasContext;
  122. this.globalData.renderer = this;
  123. this.globalData.isDashed = false;
  124. this.globalData.progressiveLoad = this.renderConfig.progressiveLoad;
  125. this.globalData.transformCanvas = this.transformCanvas;
  126. this.elements = createSizedArray(animData.layers.length);
  127. this.updateContainerSize();
  128. };
  129. CanvasRendererBase.prototype.updateContainerSize = function (width, height) {
  130. this.reset();
  131. var elementWidth;
  132. var elementHeight;
  133. if (width) {
  134. elementWidth = width;
  135. elementHeight = height;
  136. this.canvasContext.canvas.width = elementWidth;
  137. this.canvasContext.canvas.height = elementHeight;
  138. } else {
  139. if (this.animationItem.wrapper && this.animationItem.container) {
  140. elementWidth = this.animationItem.wrapper.offsetWidth;
  141. elementHeight = this.animationItem.wrapper.offsetHeight;
  142. } else {
  143. elementWidth = this.canvasContext.canvas.width;
  144. elementHeight = this.canvasContext.canvas.height;
  145. }
  146. this.canvasContext.canvas.width = elementWidth * this.renderConfig.dpr;
  147. this.canvasContext.canvas.height = elementHeight * this.renderConfig.dpr;
  148. }
  149. var elementRel;
  150. var animationRel;
  151. if (this.renderConfig.preserveAspectRatio.indexOf('meet') !== -1 || this.renderConfig.preserveAspectRatio.indexOf('slice') !== -1) {
  152. var par = this.renderConfig.preserveAspectRatio.split(' ');
  153. var fillType = par[1] || 'meet';
  154. var pos = par[0] || 'xMidYMid';
  155. var xPos = pos.substr(0, 4);
  156. var yPos = pos.substr(4);
  157. elementRel = elementWidth / elementHeight;
  158. animationRel = this.transformCanvas.w / this.transformCanvas.h;
  159. if ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice')) {
  160. this.transformCanvas.sx = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr);
  161. this.transformCanvas.sy = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr);
  162. } else {
  163. this.transformCanvas.sx = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr);
  164. this.transformCanvas.sy = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr);
  165. }
  166. if (xPos === 'xMid' && ((animationRel < elementRel && fillType === 'meet') || (animationRel > elementRel && fillType === 'slice'))) {
  167. this.transformCanvas.tx = ((elementWidth - this.transformCanvas.w * (elementHeight / this.transformCanvas.h)) / 2) * this.renderConfig.dpr;
  168. } else if (xPos === 'xMax' && ((animationRel < elementRel && fillType === 'meet') || (animationRel > elementRel && fillType === 'slice'))) {
  169. this.transformCanvas.tx = (elementWidth - this.transformCanvas.w * (elementHeight / this.transformCanvas.h)) * this.renderConfig.dpr;
  170. } else {
  171. this.transformCanvas.tx = 0;
  172. }
  173. if (yPos === 'YMid' && ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice'))) {
  174. this.transformCanvas.ty = ((elementHeight - this.transformCanvas.h * (elementWidth / this.transformCanvas.w)) / 2) * this.renderConfig.dpr;
  175. } else if (yPos === 'YMax' && ((animationRel > elementRel && fillType === 'meet') || (animationRel < elementRel && fillType === 'slice'))) {
  176. this.transformCanvas.ty = ((elementHeight - this.transformCanvas.h * (elementWidth / this.transformCanvas.w))) * this.renderConfig.dpr;
  177. } else {
  178. this.transformCanvas.ty = 0;
  179. }
  180. } else if (this.renderConfig.preserveAspectRatio === 'none') {
  181. this.transformCanvas.sx = elementWidth / (this.transformCanvas.w / this.renderConfig.dpr);
  182. this.transformCanvas.sy = elementHeight / (this.transformCanvas.h / this.renderConfig.dpr);
  183. this.transformCanvas.tx = 0;
  184. this.transformCanvas.ty = 0;
  185. } else {
  186. this.transformCanvas.sx = this.renderConfig.dpr;
  187. this.transformCanvas.sy = this.renderConfig.dpr;
  188. this.transformCanvas.tx = 0;
  189. this.transformCanvas.ty = 0;
  190. }
  191. this.transformCanvas.props = [this.transformCanvas.sx, 0, 0, 0, 0, this.transformCanvas.sy, 0, 0, 0, 0, 1, 0, this.transformCanvas.tx, this.transformCanvas.ty, 0, 1];
  192. /* var i, len = this.elements.length;
  193. for(i=0;i<len;i+=1){
  194. if(this.elements[i] && this.elements[i].data.ty === 0){
  195. this.elements[i].resize(this.globalData.transformCanvas);
  196. }
  197. } */
  198. this.ctxTransform(this.transformCanvas.props);
  199. this.canvasContext.beginPath();
  200. this.canvasContext.rect(0, 0, this.transformCanvas.w, this.transformCanvas.h);
  201. this.canvasContext.closePath();
  202. this.canvasContext.clip();
  203. this.renderFrame(this.renderedFrame, true);
  204. };
  205. CanvasRendererBase.prototype.destroy = function () {
  206. if (this.renderConfig.clearCanvas && this.animationItem.wrapper) {
  207. this.animationItem.wrapper.innerText = '';
  208. }
  209. var i;
  210. var len = this.layers ? this.layers.length : 0;
  211. for (i = len - 1; i >= 0; i -= 1) {
  212. if (this.elements[i] && this.elements[i].destroy) {
  213. this.elements[i].destroy();
  214. }
  215. }
  216. this.elements.length = 0;
  217. this.globalData.canvasContext = null;
  218. this.animationItem.container = null;
  219. this.destroyed = true;
  220. };
  221. CanvasRendererBase.prototype.renderFrame = function (num, forceRender) {
  222. if ((this.renderedFrame === num && this.renderConfig.clearCanvas === true && !forceRender) || this.destroyed || num === -1) {
  223. return;
  224. }
  225. this.renderedFrame = num;
  226. this.globalData.frameNum = num - this.animationItem._isFirstFrame;
  227. this.globalData.frameId += 1;
  228. this.globalData._mdf = !this.renderConfig.clearCanvas || forceRender;
  229. this.globalData.projectInterface.currentFrame = num;
  230. // console.log('--------');
  231. // console.log('NEW: ',num);
  232. var i;
  233. var len = this.layers.length;
  234. if (!this.completeLayers) {
  235. this.checkLayers(num);
  236. }
  237. for (i = len - 1; i >= 0; i -= 1) {
  238. if (this.completeLayers || this.elements[i]) {
  239. this.elements[i].prepareFrame(num - this.layers[i].st);
  240. }
  241. }
  242. if (this.globalData._mdf) {
  243. if (this.renderConfig.clearCanvas === true) {
  244. this.canvasContext.clearRect(0, 0, this.transformCanvas.w, this.transformCanvas.h);
  245. } else {
  246. this.save();
  247. }
  248. for (i = len - 1; i >= 0; i -= 1) {
  249. if (this.completeLayers || this.elements[i]) {
  250. this.elements[i].renderFrame();
  251. }
  252. }
  253. if (this.renderConfig.clearCanvas !== true) {
  254. this.restore();
  255. }
  256. }
  257. };
  258. CanvasRendererBase.prototype.buildItem = function (pos) {
  259. var elements = this.elements;
  260. if (elements[pos] || this.layers[pos].ty === 99) {
  261. return;
  262. }
  263. var element = this.createItem(this.layers[pos], this, this.globalData);
  264. elements[pos] = element;
  265. element.initExpressions();
  266. /* if(this.layers[pos].ty === 0){
  267. element.resize(this.globalData.transformCanvas);
  268. } */
  269. };
  270. CanvasRendererBase.prototype.checkPendingElements = function () {
  271. while (this.pendingElements.length) {
  272. var element = this.pendingElements.pop();
  273. element.checkParenting();
  274. }
  275. };
  276. CanvasRendererBase.prototype.hide = function () {
  277. this.animationItem.container.style.display = 'none';
  278. };
  279. CanvasRendererBase.prototype.show = function () {
  280. this.animationItem.container.style.display = 'block';
  281. };
  282. export default CanvasRendererBase;