TransformProperty.js 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. import {
  2. degToRads,
  3. } from './common';
  4. import {
  5. extendPrototype,
  6. } from './functionExtensions';
  7. import DynamicPropertyContainer from './helpers/dynamicProperties';
  8. import Matrix from '../3rd_party/transformation-matrix';
  9. import PropertyFactory from './PropertyFactory';
  10. const TransformPropertyFactory = (function () {
  11. var defaultVector = [0, 0];
  12. function applyToMatrix(mat) {
  13. var _mdf = this._mdf;
  14. this.iterateDynamicProperties();
  15. this._mdf = this._mdf || _mdf;
  16. if (this.a) {
  17. mat.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
  18. }
  19. if (this.s) {
  20. mat.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
  21. }
  22. if (this.sk) {
  23. mat.skewFromAxis(-this.sk.v, this.sa.v);
  24. }
  25. if (this.r) {
  26. mat.rotate(-this.r.v);
  27. } else {
  28. mat.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2])
  29. .rotateY(this.or.v[1])
  30. .rotateX(this.or.v[0]);
  31. }
  32. if (this.data.p.s) {
  33. if (this.data.p.z) {
  34. mat.translate(this.px.v, this.py.v, -this.pz.v);
  35. } else {
  36. mat.translate(this.px.v, this.py.v, 0);
  37. }
  38. } else {
  39. mat.translate(this.p.v[0], this.p.v[1], -this.p.v[2]);
  40. }
  41. }
  42. function processKeys(forceRender) {
  43. if (this.elem.globalData.frameId === this.frameId) {
  44. return;
  45. }
  46. if (this._isDirty) {
  47. this.precalculateMatrix();
  48. this._isDirty = false;
  49. }
  50. this.iterateDynamicProperties();
  51. if (this._mdf || forceRender) {
  52. var frameRate;
  53. this.v.cloneFromProps(this.pre.props);
  54. if (this.appliedTransformations < 1) {
  55. this.v.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
  56. }
  57. if (this.appliedTransformations < 2) {
  58. this.v.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
  59. }
  60. if (this.sk && this.appliedTransformations < 3) {
  61. this.v.skewFromAxis(-this.sk.v, this.sa.v);
  62. }
  63. if (this.r && this.appliedTransformations < 4) {
  64. this.v.rotate(-this.r.v);
  65. } else if (!this.r && this.appliedTransformations < 4) {
  66. this.v.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2])
  67. .rotateY(this.or.v[1])
  68. .rotateX(this.or.v[0]);
  69. }
  70. if (this.autoOriented) {
  71. var v1;
  72. var v2;
  73. frameRate = this.elem.globalData.frameRate;
  74. if (this.p && this.p.keyframes && this.p.getValueAtTime) {
  75. if (this.p._caching.lastFrame + this.p.offsetTime <= this.p.keyframes[0].t) {
  76. v1 = this.p.getValueAtTime((this.p.keyframes[0].t + 0.01) / frameRate, 0);
  77. v2 = this.p.getValueAtTime(this.p.keyframes[0].t / frameRate, 0);
  78. } else if (this.p._caching.lastFrame + this.p.offsetTime >= this.p.keyframes[this.p.keyframes.length - 1].t) {
  79. v1 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t / frameRate), 0);
  80. v2 = this.p.getValueAtTime((this.p.keyframes[this.p.keyframes.length - 1].t - 0.05) / frameRate, 0);
  81. } else {
  82. v1 = this.p.pv;
  83. v2 = this.p.getValueAtTime((this.p._caching.lastFrame + this.p.offsetTime - 0.01) / frameRate, this.p.offsetTime);
  84. }
  85. } else if (this.px && this.px.keyframes && this.py.keyframes && this.px.getValueAtTime && this.py.getValueAtTime) {
  86. v1 = [];
  87. v2 = [];
  88. var px = this.px;
  89. var py = this.py;
  90. if (px._caching.lastFrame + px.offsetTime <= px.keyframes[0].t) {
  91. v1[0] = px.getValueAtTime((px.keyframes[0].t + 0.01) / frameRate, 0);
  92. v1[1] = py.getValueAtTime((py.keyframes[0].t + 0.01) / frameRate, 0);
  93. v2[0] = px.getValueAtTime((px.keyframes[0].t) / frameRate, 0);
  94. v2[1] = py.getValueAtTime((py.keyframes[0].t) / frameRate, 0);
  95. } else if (px._caching.lastFrame + px.offsetTime >= px.keyframes[px.keyframes.length - 1].t) {
  96. v1[0] = px.getValueAtTime((px.keyframes[px.keyframes.length - 1].t / frameRate), 0);
  97. v1[1] = py.getValueAtTime((py.keyframes[py.keyframes.length - 1].t / frameRate), 0);
  98. v2[0] = px.getValueAtTime((px.keyframes[px.keyframes.length - 1].t - 0.01) / frameRate, 0);
  99. v2[1] = py.getValueAtTime((py.keyframes[py.keyframes.length - 1].t - 0.01) / frameRate, 0);
  100. } else {
  101. v1 = [px.pv, py.pv];
  102. v2[0] = px.getValueAtTime((px._caching.lastFrame + px.offsetTime - 0.01) / frameRate, px.offsetTime);
  103. v2[1] = py.getValueAtTime((py._caching.lastFrame + py.offsetTime - 0.01) / frameRate, py.offsetTime);
  104. }
  105. } else {
  106. v2 = defaultVector;
  107. v1 = v2;
  108. }
  109. this.v.rotate(-Math.atan2(v1[1] - v2[1], v1[0] - v2[0]));
  110. }
  111. if (this.data.p && this.data.p.s) {
  112. if (this.data.p.z) {
  113. this.v.translate(this.px.v, this.py.v, -this.pz.v);
  114. } else {
  115. this.v.translate(this.px.v, this.py.v, 0);
  116. }
  117. } else {
  118. this.v.translate(this.p.v[0], this.p.v[1], -this.p.v[2]);
  119. }
  120. }
  121. this.frameId = this.elem.globalData.frameId;
  122. }
  123. function precalculateMatrix() {
  124. this.appliedTransformations = 0;
  125. this.pre.reset();
  126. if (!this.a.effectsSequence.length) {
  127. this.pre.translate(-this.a.v[0], -this.a.v[1], this.a.v[2]);
  128. this.appliedTransformations = 1;
  129. } else {
  130. return;
  131. }
  132. if (!this.s.effectsSequence.length) {
  133. this.pre.scale(this.s.v[0], this.s.v[1], this.s.v[2]);
  134. this.appliedTransformations = 2;
  135. } else {
  136. return;
  137. }
  138. if (this.sk) {
  139. if (!this.sk.effectsSequence.length && !this.sa.effectsSequence.length) {
  140. this.pre.skewFromAxis(-this.sk.v, this.sa.v);
  141. this.appliedTransformations = 3;
  142. } else {
  143. return;
  144. }
  145. }
  146. if (this.r) {
  147. if (!this.r.effectsSequence.length) {
  148. this.pre.rotate(-this.r.v);
  149. this.appliedTransformations = 4;
  150. }
  151. } else if (!this.rz.effectsSequence.length && !this.ry.effectsSequence.length && !this.rx.effectsSequence.length && !this.or.effectsSequence.length) {
  152. this.pre.rotateZ(-this.rz.v).rotateY(this.ry.v).rotateX(this.rx.v).rotateZ(-this.or.v[2])
  153. .rotateY(this.or.v[1])
  154. .rotateX(this.or.v[0]);
  155. this.appliedTransformations = 4;
  156. }
  157. }
  158. function autoOrient() {
  159. //
  160. // var prevP = this.getValueAtTime();
  161. }
  162. function addDynamicProperty(prop) {
  163. this._addDynamicProperty(prop);
  164. this.elem.addDynamicProperty(prop);
  165. this._isDirty = true;
  166. }
  167. function TransformProperty(elem, data, container) {
  168. this.elem = elem;
  169. this.frameId = -1;
  170. this.propType = 'transform';
  171. this.data = data;
  172. this.v = new Matrix();
  173. // Precalculated matrix with non animated properties
  174. this.pre = new Matrix();
  175. this.appliedTransformations = 0;
  176. this.initDynamicPropertyContainer(container || elem);
  177. if (data.p && data.p.s) {
  178. this.px = PropertyFactory.getProp(elem, data.p.x, 0, 0, this);
  179. this.py = PropertyFactory.getProp(elem, data.p.y, 0, 0, this);
  180. if (data.p.z) {
  181. this.pz = PropertyFactory.getProp(elem, data.p.z, 0, 0, this);
  182. }
  183. } else {
  184. this.p = PropertyFactory.getProp(elem, data.p || { k: [0, 0, 0] }, 1, 0, this);
  185. }
  186. if (data.rx) {
  187. this.rx = PropertyFactory.getProp(elem, data.rx, 0, degToRads, this);
  188. this.ry = PropertyFactory.getProp(elem, data.ry, 0, degToRads, this);
  189. this.rz = PropertyFactory.getProp(elem, data.rz, 0, degToRads, this);
  190. if (data.or.k[0].ti) {
  191. var i;
  192. var len = data.or.k.length;
  193. for (i = 0; i < len; i += 1) {
  194. data.or.k[i].to = null;
  195. data.or.k[i].ti = null;
  196. }
  197. }
  198. this.or = PropertyFactory.getProp(elem, data.or, 1, degToRads, this);
  199. // sh Indicates it needs to be capped between -180 and 180
  200. this.or.sh = true;
  201. } else {
  202. this.r = PropertyFactory.getProp(elem, data.r || { k: 0 }, 0, degToRads, this);
  203. }
  204. if (data.sk) {
  205. this.sk = PropertyFactory.getProp(elem, data.sk, 0, degToRads, this);
  206. this.sa = PropertyFactory.getProp(elem, data.sa, 0, degToRads, this);
  207. }
  208. this.a = PropertyFactory.getProp(elem, data.a || { k: [0, 0, 0] }, 1, 0, this);
  209. this.s = PropertyFactory.getProp(elem, data.s || { k: [100, 100, 100] }, 1, 0.01, this);
  210. // Opacity is not part of the transform properties, that's why it won't use this.dynamicProperties. That way transforms won't get updated if opacity changes.
  211. if (data.o) {
  212. this.o = PropertyFactory.getProp(elem, data.o, 0, 0.01, elem);
  213. } else {
  214. this.o = { _mdf: false, v: 1 };
  215. }
  216. this._isDirty = true;
  217. if (!this.dynamicProperties.length) {
  218. this.getValue(true);
  219. }
  220. }
  221. TransformProperty.prototype = {
  222. applyToMatrix: applyToMatrix,
  223. getValue: processKeys,
  224. precalculateMatrix: precalculateMatrix,
  225. autoOrient: autoOrient,
  226. };
  227. extendPrototype([DynamicPropertyContainer], TransformProperty);
  228. TransformProperty.prototype.addDynamicProperty = addDynamicProperty;
  229. TransformProperty.prototype._addDynamicProperty = DynamicPropertyContainer.prototype.addDynamicProperty;
  230. function getTransformProperty(elem, data, container) {
  231. return new TransformProperty(elem, data, container);
  232. }
  233. return {
  234. getTransformProperty: getTransformProperty,
  235. };
  236. }());
  237. export default TransformPropertyFactory;