Source: animate/utils.js

animate/utils.js

  1. import { MovieClip } from './MovieClip';
  2. // If the movieclip plugin is installed
  3. let _prepare = null;
  4. /**
  5. * @namespace PIXI.animate.utils
  6. * @description For keyframe conversions
  7. */
  8. export default class AnimateUtils {
  9. /**
  10. * Convert the Hexidecimal string (e.g., "#fff") to uint
  11. * @static
  12. * @method PIXI.animate.utils.hexToUint
  13. */
  14. static hexToUint(hex) {
  15. // Remove the hash
  16. hex = hex.substr(1);
  17. // Convert shortcolors fc9 to ffcc99
  18. if (hex.length === 3) {
  19. hex = hex.replace(/([a-f0-9])/g, '$1$1');
  20. }
  21. return parseInt(hex, 16);
  22. }
  23. /**
  24. * Fill frames with booleans of true (showing) and false (hidden).
  25. * @static
  26. * @method PIXI.animate.utils.fillFrames
  27. * @param {Array<Boolean>} timeline
  28. * @param {int} startFrame The start frame when the timeline shows up
  29. * @param {int} duration The length of showing
  30. */
  31. static fillFrames(timeline, startFrame, duration) {
  32. //ensure that the timeline is long enough
  33. const oldLength = timeline.length;
  34. if (oldLength < startFrame + duration) {
  35. timeline.length = startFrame + duration;
  36. //fill any gaps with false to denote that the child should be removed for a bit
  37. if (oldLength < startFrame) {
  38. //if the browser has implemented the ES6 fill() function, use that
  39. if (timeline.fill) {
  40. timeline.fill(false, oldLength, startFrame);
  41. } else {
  42. //if we can't use fill, then do a for loop to fill it
  43. for (let i = oldLength; i < startFrame; ++i) {
  44. timeline[i] = false;
  45. }
  46. }
  47. }
  48. }
  49. //if the browser has implemented the ES6 fill() function, use that
  50. if (timeline.fill) {
  51. timeline.fill(true, startFrame, startFrame + duration);
  52. } else {
  53. const length = timeline.length;
  54. //if we can't use fill, then do a for loop to fill it
  55. for (let i = startFrame; i < length; ++i) {
  56. timeline[i] = true;
  57. }
  58. }
  59. }
  60. /**
  61. * Convert serialized array into keyframes
  62. * `"0x100y100 1x150"` to: `{ "0": {"x":100, "y": 100}, "1": {"x": 150} }`
  63. * @static
  64. * @method PIXI.animate.utils.deserializeKeyframes
  65. * @param {String} keyframes
  66. * @param {Object} Resulting keyframes
  67. */
  68. static deserializeKeyframes(keyframes) {
  69. let result = {};
  70. let i = 0;
  71. let keysMap = {
  72. X: 'x', // x position
  73. Y: 'y', // y position
  74. A: 'sx', // scale x
  75. B: 'sy', // scale y
  76. C: 'kx', // skew x
  77. D: 'ky', // skew y
  78. R: 'r', // rotation
  79. L: 'a', // alpha
  80. T: 't', // tint
  81. F: 'c', // colorTransform
  82. V: 'v' // visibility
  83. };
  84. let c,
  85. buffer = '',
  86. isFrameStarted = false,
  87. prop,
  88. frame = {};
  89. while (i <= keyframes.length) {
  90. c = keyframes[i];
  91. if (keysMap[c]) {
  92. if (!isFrameStarted) {
  93. isFrameStarted = true;
  94. result[buffer] = frame;
  95. }
  96. if (prop) {
  97. frame[prop] = this.parseValue(prop, buffer);
  98. }
  99. prop = keysMap[c];
  100. buffer = '';
  101. i++;
  102. }
  103. // Start a new prop
  104. else if (!c || c === ' ') {
  105. i++;
  106. frame[prop] = this.parseValue(prop, buffer);
  107. buffer = '';
  108. prop = null;
  109. frame = {};
  110. isFrameStarted = false;
  111. } else {
  112. buffer += c;
  113. i++;
  114. }
  115. }
  116. return result;
  117. }
  118. /**
  119. * Convert serialized shapes into draw commands for PIXI.Graphics.
  120. * @static
  121. * @method PIXI.animate.utils.deserializeShapes
  122. * @param {String} str
  123. * @param {Array} Resulting shapes map
  124. */
  125. static deserializeShapes(str) {
  126. const result = [];
  127. // each shape is a new line
  128. let shapes = str.split("\n");
  129. let isCommand = /^[a-z]{1,2}$/;
  130. for (let i = 0; i < shapes.length; i++) {
  131. let shape = shapes[i].split(' '); // arguments are space separated
  132. for (let j = 0; j < shape.length; j++) {
  133. // Convert all numbers to floats, ignore colors
  134. let arg = shape[j];
  135. if (arg[0] !== '#' && !isCommand.test(arg)) {
  136. shape[j] = parseFloat(arg);
  137. }
  138. }
  139. result.push(shape);
  140. }
  141. return result;
  142. }
  143. /**
  144. * Parse the value of the compressed keyframe.
  145. * @method PIXI.animate.utils.parseValue
  146. * @static
  147. * @private
  148. * @param {String} prop The property key
  149. * @param {String} buffer The contents
  150. * @return {*} The parsed value
  151. */
  152. static parseValue(prop, buffer) {
  153. switch (prop) {
  154. // Color transforms are parsed as an array
  155. case 'c':
  156. {
  157. buffer = buffer.split(',');
  158. buffer.forEach(function(val, i, buffer) {
  159. buffer[i] = parseFloat(val);
  160. });
  161. return buffer;
  162. }
  163. // Tint value should not be converted
  164. // can be color uint or string
  165. case 't':
  166. {
  167. return buffer;
  168. }
  169. // The visiblity parse as boolean
  170. case 'v':
  171. {
  172. return !!parseInt(buffer);
  173. }
  174. // Everything else parse a floats
  175. default:
  176. {
  177. return parseFloat(buffer);
  178. }
  179. }
  180. }
  181. /**
  182. * Upload all the textures and graphics to the GPU.
  183. * @method PIXI.animate.utils.upload
  184. * @static
  185. * @param {PIXI.WebGLRenderer} renderer Render to upload to
  186. * @param {PIXI.DisplayObject} clip MovieClip to upload
  187. * @param {function} done When complete
  188. */
  189. static upload(renderer, displayObject, done) {
  190. if (!_prepare) {
  191. _prepare = renderer.plugins.prepare;
  192. _prepare.register(this.addMovieClips);
  193. }
  194. _prepare.upload(displayObject, done);
  195. }
  196. /**
  197. * Add movie clips to the upload prepare.
  198. * @method PIXI.animate.utils.addMovieClips
  199. * @static
  200. * @private
  201. * @param {*} item To add to the queue
  202. */
  203. static addMovieClips(item) {
  204. if (item instanceof MovieClip) {
  205. item._timedChildTimelines.forEach((timeline) => {
  206. const index = item.children.indexOf(timeline.target);
  207. if (index === -1) {
  208. _prepare.add(timeline.target);
  209. }
  210. });
  211. return true;
  212. }
  213. return false;
  214. }
  215. }