HybridRendererBase.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. import {
  2. extendPrototype,
  3. } from '../utils/functionExtensions';
  4. import createNS from '../utils/helpers/svg_elements';
  5. import createTag from '../utils/helpers/html_elements';
  6. import SVGRenderer from './SVGRenderer';
  7. import HSolidElement from '../elements/htmlElements/HSolidElement';
  8. import {
  9. styleDiv,
  10. } from '../utils/common';
  11. import BaseRenderer from './BaseRenderer';
  12. import IImageElement from '../elements/ImageElement';
  13. import SVGShapeElement from '../elements/svgElements/SVGShapeElement';
  14. import HShapeElement from '../elements/htmlElements/HShapeElement';
  15. import HTextElement from '../elements/htmlElements/HTextElement';
  16. import HCameraElement from '../elements/htmlElements/HCameraElement';
  17. import HImageElement from '../elements/htmlElements/HImageElement';
  18. import ISolidElement from '../elements/SolidElement';
  19. import SVGTextLottieElement from '../elements/svgElements/SVGTextElement';
  20. function HybridRendererBase(animationItem, config) {
  21. this.animationItem = animationItem;
  22. this.layers = null;
  23. this.renderedFrame = -1;
  24. this.renderConfig = {
  25. className: (config && config.className) || '',
  26. imagePreserveAspectRatio: (config && config.imagePreserveAspectRatio) || 'xMidYMid slice',
  27. hideOnTransparent: !(config && config.hideOnTransparent === false),
  28. filterSize: {
  29. width: (config && config.filterSize && config.filterSize.width) || '400%',
  30. height: (config && config.filterSize && config.filterSize.height) || '400%',
  31. x: (config && config.filterSize && config.filterSize.x) || '-100%',
  32. y: (config && config.filterSize && config.filterSize.y) || '-100%',
  33. },
  34. };
  35. this.globalData = {
  36. _mdf: false,
  37. frameNum: -1,
  38. renderConfig: this.renderConfig,
  39. };
  40. this.pendingElements = [];
  41. this.elements = [];
  42. this.threeDElements = [];
  43. this.destroyed = false;
  44. this.camera = null;
  45. this.supports3d = true;
  46. this.rendererType = 'html';
  47. }
  48. extendPrototype([BaseRenderer], HybridRendererBase);
  49. HybridRendererBase.prototype.buildItem = SVGRenderer.prototype.buildItem;
  50. HybridRendererBase.prototype.checkPendingElements = function () {
  51. while (this.pendingElements.length) {
  52. var element = this.pendingElements.pop();
  53. element.checkParenting();
  54. }
  55. };
  56. HybridRendererBase.prototype.appendElementInPos = function (element, pos) {
  57. var newDOMElement = element.getBaseElement();
  58. if (!newDOMElement) {
  59. return;
  60. }
  61. var layer = this.layers[pos];
  62. if (!layer.ddd || !this.supports3d) {
  63. if (this.threeDElements) {
  64. this.addTo3dContainer(newDOMElement, pos);
  65. } else {
  66. var i = 0;
  67. var nextDOMElement;
  68. var nextLayer;
  69. var tmpDOMElement;
  70. while (i < pos) {
  71. if (this.elements[i] && this.elements[i] !== true && this.elements[i].getBaseElement) {
  72. nextLayer = this.elements[i];
  73. tmpDOMElement = this.layers[i].ddd ? this.getThreeDContainerByPos(i) : nextLayer.getBaseElement();
  74. nextDOMElement = tmpDOMElement || nextDOMElement;
  75. }
  76. i += 1;
  77. }
  78. if (nextDOMElement) {
  79. if (!layer.ddd || !this.supports3d) {
  80. this.layerElement.insertBefore(newDOMElement, nextDOMElement);
  81. }
  82. } else if (!layer.ddd || !this.supports3d) {
  83. this.layerElement.appendChild(newDOMElement);
  84. }
  85. }
  86. } else {
  87. this.addTo3dContainer(newDOMElement, pos);
  88. }
  89. };
  90. HybridRendererBase.prototype.createShape = function (data) {
  91. if (!this.supports3d) {
  92. return new SVGShapeElement(data, this.globalData, this);
  93. }
  94. return new HShapeElement(data, this.globalData, this);
  95. };
  96. HybridRendererBase.prototype.createText = function (data) {
  97. if (!this.supports3d) {
  98. return new SVGTextLottieElement(data, this.globalData, this);
  99. }
  100. return new HTextElement(data, this.globalData, this);
  101. };
  102. HybridRendererBase.prototype.createCamera = function (data) {
  103. this.camera = new HCameraElement(data, this.globalData, this);
  104. return this.camera;
  105. };
  106. HybridRendererBase.prototype.createImage = function (data) {
  107. if (!this.supports3d) {
  108. return new IImageElement(data, this.globalData, this);
  109. }
  110. return new HImageElement(data, this.globalData, this);
  111. };
  112. HybridRendererBase.prototype.createSolid = function (data) {
  113. if (!this.supports3d) {
  114. return new ISolidElement(data, this.globalData, this);
  115. }
  116. return new HSolidElement(data, this.globalData, this);
  117. };
  118. HybridRendererBase.prototype.createNull = SVGRenderer.prototype.createNull;
  119. HybridRendererBase.prototype.getThreeDContainerByPos = function (pos) {
  120. var i = 0;
  121. var len = this.threeDElements.length;
  122. while (i < len) {
  123. if (this.threeDElements[i].startPos <= pos && this.threeDElements[i].endPos >= pos) {
  124. return this.threeDElements[i].perspectiveElem;
  125. }
  126. i += 1;
  127. }
  128. return null;
  129. };
  130. HybridRendererBase.prototype.createThreeDContainer = function (pos, type) {
  131. var perspectiveElem = createTag('div');
  132. var style;
  133. var containerStyle;
  134. styleDiv(perspectiveElem);
  135. var container = createTag('div');
  136. styleDiv(container);
  137. if (type === '3d') {
  138. style = perspectiveElem.style;
  139. style.width = this.globalData.compSize.w + 'px';
  140. style.height = this.globalData.compSize.h + 'px';
  141. var center = '50% 50%';
  142. style.webkitTransformOrigin = center;
  143. style.mozTransformOrigin = center;
  144. style.transformOrigin = center;
  145. containerStyle = container.style;
  146. var matrix = 'matrix3d(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)';
  147. containerStyle.transform = matrix;
  148. containerStyle.webkitTransform = matrix;
  149. }
  150. perspectiveElem.appendChild(container);
  151. // this.resizerElem.appendChild(perspectiveElem);
  152. var threeDContainerData = {
  153. container: container,
  154. perspectiveElem: perspectiveElem,
  155. startPos: pos,
  156. endPos: pos,
  157. type: type,
  158. };
  159. this.threeDElements.push(threeDContainerData);
  160. return threeDContainerData;
  161. };
  162. HybridRendererBase.prototype.build3dContainers = function () {
  163. var i;
  164. var len = this.layers.length;
  165. var lastThreeDContainerData;
  166. var currentContainer = '';
  167. for (i = 0; i < len; i += 1) {
  168. if (this.layers[i].ddd && this.layers[i].ty !== 3) {
  169. if (currentContainer !== '3d') {
  170. currentContainer = '3d';
  171. lastThreeDContainerData = this.createThreeDContainer(i, '3d');
  172. }
  173. lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos, i);
  174. } else {
  175. if (currentContainer !== '2d') {
  176. currentContainer = '2d';
  177. lastThreeDContainerData = this.createThreeDContainer(i, '2d');
  178. }
  179. lastThreeDContainerData.endPos = Math.max(lastThreeDContainerData.endPos, i);
  180. }
  181. }
  182. len = this.threeDElements.length;
  183. for (i = len - 1; i >= 0; i -= 1) {
  184. this.resizerElem.appendChild(this.threeDElements[i].perspectiveElem);
  185. }
  186. };
  187. HybridRendererBase.prototype.addTo3dContainer = function (elem, pos) {
  188. var i = 0;
  189. var len = this.threeDElements.length;
  190. while (i < len) {
  191. if (pos <= this.threeDElements[i].endPos) {
  192. var j = this.threeDElements[i].startPos;
  193. var nextElement;
  194. while (j < pos) {
  195. if (this.elements[j] && this.elements[j].getBaseElement) {
  196. nextElement = this.elements[j].getBaseElement();
  197. }
  198. j += 1;
  199. }
  200. if (nextElement) {
  201. this.threeDElements[i].container.insertBefore(elem, nextElement);
  202. } else {
  203. this.threeDElements[i].container.appendChild(elem);
  204. }
  205. break;
  206. }
  207. i += 1;
  208. }
  209. };
  210. HybridRendererBase.prototype.configAnimation = function (animData) {
  211. var resizerElem = createTag('div');
  212. var wrapper = this.animationItem.wrapper;
  213. var style = resizerElem.style;
  214. style.width = animData.w + 'px';
  215. style.height = animData.h + 'px';
  216. this.resizerElem = resizerElem;
  217. styleDiv(resizerElem);
  218. style.transformStyle = 'flat';
  219. style.mozTransformStyle = 'flat';
  220. style.webkitTransformStyle = 'flat';
  221. if (this.renderConfig.className) {
  222. resizerElem.setAttribute('class', this.renderConfig.className);
  223. }
  224. wrapper.appendChild(resizerElem);
  225. style.overflow = 'hidden';
  226. var svg = createNS('svg');
  227. svg.setAttribute('width', '1');
  228. svg.setAttribute('height', '1');
  229. styleDiv(svg);
  230. this.resizerElem.appendChild(svg);
  231. var defs = createNS('defs');
  232. svg.appendChild(defs);
  233. this.data = animData;
  234. // Mask animation
  235. this.setupGlobalData(animData, svg);
  236. this.globalData.defs = defs;
  237. this.layers = animData.layers;
  238. this.layerElement = this.resizerElem;
  239. this.build3dContainers();
  240. this.updateContainerSize();
  241. };
  242. HybridRendererBase.prototype.destroy = function () {
  243. if (this.animationItem.wrapper) {
  244. this.animationItem.wrapper.innerText = '';
  245. }
  246. this.animationItem.container = null;
  247. this.globalData.defs = null;
  248. var i;
  249. var len = this.layers ? this.layers.length : 0;
  250. for (i = 0; i < len; i += 1) {
  251. if (this.elements[i] && this.elements[i].destroy) {
  252. this.elements[i].destroy();
  253. }
  254. }
  255. this.elements.length = 0;
  256. this.destroyed = true;
  257. this.animationItem = null;
  258. };
  259. HybridRendererBase.prototype.updateContainerSize = function () {
  260. var elementWidth = this.animationItem.wrapper.offsetWidth;
  261. var elementHeight = this.animationItem.wrapper.offsetHeight;
  262. var elementRel = elementWidth / elementHeight;
  263. var animationRel = this.globalData.compSize.w / this.globalData.compSize.h;
  264. var sx;
  265. var sy;
  266. var tx;
  267. var ty;
  268. if (animationRel > elementRel) {
  269. sx = elementWidth / (this.globalData.compSize.w);
  270. sy = elementWidth / (this.globalData.compSize.w);
  271. tx = 0;
  272. ty = ((elementHeight - this.globalData.compSize.h * (elementWidth / this.globalData.compSize.w)) / 2);
  273. } else {
  274. sx = elementHeight / (this.globalData.compSize.h);
  275. sy = elementHeight / (this.globalData.compSize.h);
  276. tx = (elementWidth - this.globalData.compSize.w * (elementHeight / this.globalData.compSize.h)) / 2;
  277. ty = 0;
  278. }
  279. var style = this.resizerElem.style;
  280. style.webkitTransform = 'matrix3d(' + sx + ',0,0,0,0,' + sy + ',0,0,0,0,1,0,' + tx + ',' + ty + ',0,1)';
  281. style.transform = style.webkitTransform;
  282. };
  283. HybridRendererBase.prototype.renderFrame = SVGRenderer.prototype.renderFrame;
  284. HybridRendererBase.prototype.hide = function () {
  285. this.resizerElem.style.display = 'none';
  286. };
  287. HybridRendererBase.prototype.show = function () {
  288. this.resizerElem.style.display = 'block';
  289. };
  290. HybridRendererBase.prototype.initItems = function () {
  291. this.buildAllItems();
  292. if (this.camera) {
  293. this.camera.setup();
  294. } else {
  295. var cWidth = this.globalData.compSize.w;
  296. var cHeight = this.globalData.compSize.h;
  297. var i;
  298. var len = this.threeDElements.length;
  299. for (i = 0; i < len; i += 1) {
  300. var style = this.threeDElements[i].perspectiveElem.style;
  301. style.webkitPerspective = Math.sqrt(Math.pow(cWidth, 2) + Math.pow(cHeight, 2)) + 'px';
  302. style.perspective = style.webkitPerspective;
  303. }
  304. }
  305. };
  306. HybridRendererBase.prototype.searchExtraCompositions = function (assets) {
  307. var i;
  308. var len = assets.length;
  309. var floatingContainer = createTag('div');
  310. for (i = 0; i < len; i += 1) {
  311. if (assets[i].xt) {
  312. var comp = this.createComp(assets[i], floatingContainer, this.globalData.comp, null);
  313. comp.initExpressions();
  314. this.globalData.projectInterface.registerComposition(comp);
  315. }
  316. }
  317. };
  318. export default HybridRendererBase;