Source: animate/Animator.js

animate/Animator.js

  1. import AnimatorTimeline from './AnimatorTimeline';
  2. // Static collection of timelines
  3. const timelines = [];
  4. /**
  5. * Play animation via start/stop frame labels
  6. * @class Animator
  7. * @memberof PIXI.animate
  8. */
  9. class Animator {
  10. /**
  11. * The collection of timelines
  12. * @name {Array<PIXI.animate.AnimatorTimeline>} PIXI.animate.Animator#_timelines
  13. * @private
  14. * @static
  15. */
  16. static get _timelines() {
  17. return timelines;
  18. }
  19. /**
  20. * Suffix added to label for a stop.
  21. * @name {String} PIXI.animate.Animator.STOP_LABEL
  22. * @static
  23. * @default "_stop"
  24. */
  25. static get STOP_LABEL() {
  26. return "_stop";
  27. }
  28. /**
  29. * Suffix added to label for a loop.
  30. * @name {String} PIXI.animate.Animator.LOOP_LABEL
  31. * @static
  32. * @default "_loop"
  33. */
  34. static get LOOP_LABEL() {
  35. return "_loop";
  36. }
  37. /**
  38. * Play an animation by frame labels. For instance, play animation sequence from
  39. * "idle" to "idle_stop" or "idle_loop". If no event label is provided, will
  40. * play the entire duration of the MovieClip.
  41. * @method PIXI.animate.Animator#play
  42. * @static
  43. * @param {PIXI.animate.MovieClip} instance Movie clip to play.
  44. * @param {String|Function} [label] The frame label event to call, if no event is provided
  45. * will use the entire length of the MovieClip. Can also be the callback.
  46. * @param {Function} [callback] Optional callback when complete
  47. * @return {PIXI.animate.AnimatorTimeline} Timeline object for stopping or getting progress.
  48. */
  49. static play(instance, label, callback) {
  50. let loop = false;
  51. let start, end;
  52. const labelIsFunction = typeof label === "function";
  53. if (label === undefined || labelIsFunction) {
  54. start = 0;
  55. end = instance.totalFrames - 1;
  56. if (labelIsFunction) {
  57. callback = label;
  58. }
  59. } else {
  60. start = instance.labelsMap[label];
  61. end = instance.labelsMap[label + this.STOP_LABEL];
  62. if (end === undefined) {
  63. end = instance.labelsMap[label + this.LOOP_LABEL];
  64. loop = true;
  65. }
  66. if (start === undefined) {
  67. throw new Error("No start label matching '" + label + "'");
  68. } else if (end === undefined) {
  69. throw new Error("No end label matching '" + label + "'");
  70. }
  71. }
  72. return this.fromTo(
  73. instance,
  74. start,
  75. end,
  76. loop,
  77. callback
  78. );
  79. }
  80. /**
  81. * Play an animation from the current frame to an end frame or label.
  82. * @method PIXI.animate.Animator#to
  83. * @static
  84. * @param {PIXI.animate.MovieClip} instance Movie clip to play.
  85. * @param {String|Number} end The end frame or label.
  86. * @param {Function} [callback] Optional callback when complete
  87. * @return {PIXI.animate.AnimatorTimeline} Timeline object for stopping or getting progress.
  88. */
  89. static to(instance, end, callback) {
  90. return this.fromTo(
  91. instance,
  92. instance.currentFrame,
  93. end,
  94. false,
  95. callback
  96. );
  97. }
  98. /**
  99. * Play a MovieClip from a start to end frame.
  100. * @method PIXI.animate.Animator#fromTo
  101. * @static
  102. * @param {PIXI.animate.MovieClip} instance Movie clip to play.
  103. * @param {Number|String} start The starting frame index or label.
  104. * @param {Number|String} end The ending frame index or label.
  105. * @param {Boolean} [loop=false] If the animation should loop.
  106. * @param {Function} [callback] Optional callback when complete
  107. * @return {PIXI.animate.AnimatorTimeline} Timeline object for stopping or getting progress.
  108. */
  109. static fromTo(instance, start, end, loop, callback) {
  110. if (typeof start === "string") {
  111. const startLabel = start;
  112. start = instance.labelsMap[startLabel];
  113. if (start === undefined) {
  114. throw new Error("No start label matching '" + startLabel + "'");
  115. }
  116. }
  117. if (typeof end === "string") {
  118. const endLabel = end;
  119. end = instance.labelsMap[endLabel];
  120. if (end === undefined) {
  121. throw new Error("No end label matching '" + endLabel + "'");
  122. }
  123. }
  124. if (start < 0) {
  125. throw new Error('Start frame is out of bounds');
  126. }
  127. if (end >= instance.totalFrames) {
  128. throw new Error('End frame is out of bounds');
  129. }
  130. if (start >= end) {
  131. throw new Error('End frame is before start frame');
  132. }
  133. // Stop any animation that's playing
  134. this.stop(instance);
  135. loop = !!loop;
  136. // Add a new timeline
  137. const timeline = AnimatorTimeline.create(
  138. instance,
  139. start,
  140. end,
  141. loop,
  142. callback
  143. );
  144. this._timelines.push(timeline);
  145. // Set the current frame
  146. if (instance.currentFrame !== start) {
  147. instance.gotoAndPlay(start);
  148. } else {
  149. instance.play();
  150. }
  151. return timeline;
  152. }
  153. /**
  154. * Stop the animation by instance.
  155. * @method PIXI.animate.Animator#stop
  156. * @static
  157. * @param {PIXI.animate.MovieClip} instance Movie clip to play.
  158. */
  159. static stop(instance) {
  160. for (let i = 0, len = this._timelines.length; i < len; i++) {
  161. const timeline = this._timelines[i];
  162. if (timeline.instance === instance) {
  163. this._internalStop(timeline);
  164. break;
  165. }
  166. }
  167. }
  168. /**
  169. * Stop all the currently playing animations.
  170. * @method PIXI.animate.Animator#stopAll
  171. * @static
  172. */
  173. static stopAll() {
  174. for (let i = this._timelines.length - 1; i >= 0; i--) {
  175. this._internalStop(this._timelines[i]);
  176. }
  177. }
  178. /**
  179. * Stop the animation
  180. * @method PIXI.animate.Animator#_internalStop
  181. * @private
  182. * @static
  183. * @param {PIXI.animate.AnimatorTimeline} timeline Timeline to stop.
  184. */
  185. static _internalStop(timeline) {
  186. this._timelines.splice(this._timelines.indexOf(timeline), 1);
  187. timeline.instance.stop();
  188. timeline.destroy();
  189. }
  190. }
  191. module.exports = Animator;