Animation.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /**
  2. * Animation main class, dispatch and manage all animation controllers
  3. *
  4. * @module zrender/animation/Animation
  5. * @author pissang(https://github.com/pissang)
  6. */
  7. // TODO Additive animation
  8. // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
  9. // https://developer.apple.com/videos/wwdc2014/#236
  10. import * as util from '../core/util';
  11. import {Dispatcher} from '../core/event';
  12. import requestAnimationFrame from './requestAnimationFrame';
  13. import Animator from './Animator';
  14. /**
  15. * @typedef {Object} IZRenderStage
  16. * @property {Function} update
  17. */
  18. /**
  19. * @alias module:zrender/animation/Animation
  20. * @constructor
  21. * @param {Object} [options]
  22. * @param {Function} [options.onframe]
  23. * @param {IZRenderStage} [options.stage]
  24. * @example
  25. * var animation = new Animation();
  26. * var obj = {
  27. * x: 100,
  28. * y: 100
  29. * };
  30. * animation.animate(node.position)
  31. * .when(1000, {
  32. * x: 500,
  33. * y: 500
  34. * })
  35. * .when(2000, {
  36. * x: 100,
  37. * y: 100
  38. * })
  39. * .start('spline');
  40. */
  41. var Animation = function (options) {
  42. options = options || {};
  43. this.stage = options.stage || {};
  44. this.onframe = options.onframe || function () {};
  45. // private properties
  46. this._clips = [];
  47. this._running = false;
  48. this._time;
  49. this._pausedTime;
  50. this._pauseStart;
  51. this._paused = false;
  52. Dispatcher.call(this);
  53. };
  54. Animation.prototype = {
  55. constructor: Animation,
  56. /**
  57. * Add clip
  58. * @param {module:zrender/animation/Clip} clip
  59. */
  60. addClip: function (clip) {
  61. this._clips.push(clip);
  62. },
  63. /**
  64. * Add animator
  65. * @param {module:zrender/animation/Animator} animator
  66. */
  67. addAnimator: function (animator) {
  68. animator.animation = this;
  69. var clips = animator.getClips();
  70. for (var i = 0; i < clips.length; i++) {
  71. this.addClip(clips[i]);
  72. }
  73. },
  74. /**
  75. * Delete animation clip
  76. * @param {module:zrender/animation/Clip} clip
  77. */
  78. removeClip: function (clip) {
  79. var idx = util.indexOf(this._clips, clip);
  80. if (idx >= 0) {
  81. this._clips.splice(idx, 1);
  82. }
  83. },
  84. /**
  85. * Delete animation clip
  86. * @param {module:zrender/animation/Animator} animator
  87. */
  88. removeAnimator: function (animator) {
  89. var clips = animator.getClips();
  90. for (var i = 0; i < clips.length; i++) {
  91. this.removeClip(clips[i]);
  92. }
  93. animator.animation = null;
  94. },
  95. _update: function () {
  96. var time = new Date().getTime() - this._pausedTime;
  97. var delta = time - this._time;
  98. var clips = this._clips;
  99. var len = clips.length;
  100. var deferredEvents = [];
  101. var deferredClips = [];
  102. for (var i = 0; i < len; i++) {
  103. var clip = clips[i];
  104. var e = clip.step(time, delta);
  105. // Throw out the events need to be called after
  106. // stage.update, like destroy
  107. if (e) {
  108. deferredEvents.push(e);
  109. deferredClips.push(clip);
  110. }
  111. }
  112. // Remove the finished clip
  113. for (var i = 0; i < len;) {
  114. if (clips[i]._needsRemove) {
  115. clips[i] = clips[len - 1];
  116. clips.pop();
  117. len--;
  118. }
  119. else {
  120. i++;
  121. }
  122. }
  123. len = deferredEvents.length;
  124. for (var i = 0; i < len; i++) {
  125. deferredClips[i].fire(deferredEvents[i]);
  126. }
  127. this._time = time;
  128. this.onframe(delta);
  129. // 'frame' should be triggered before stage, because upper application
  130. // depends on the sequence (e.g., echarts-stream and finish
  131. // event judge)
  132. this.trigger('frame', delta);
  133. if (this.stage.update) {
  134. this.stage.update();
  135. }
  136. },
  137. _startLoop: function () {
  138. var self = this;
  139. this._running = true;
  140. function step() {
  141. if (self._running) {
  142. requestAnimationFrame(step);
  143. !self._paused && self._update();
  144. }
  145. }
  146. requestAnimationFrame(step);
  147. },
  148. /**
  149. * Start animation.
  150. */
  151. start: function () {
  152. this._time = new Date().getTime();
  153. this._pausedTime = 0;
  154. this._startLoop();
  155. },
  156. /**
  157. * Stop animation.
  158. */
  159. stop: function () {
  160. this._running = false;
  161. },
  162. /**
  163. * Pause animation.
  164. */
  165. pause: function () {
  166. if (!this._paused) {
  167. this._pauseStart = new Date().getTime();
  168. this._paused = true;
  169. }
  170. },
  171. /**
  172. * Resume animation.
  173. */
  174. resume: function () {
  175. if (this._paused) {
  176. this._pausedTime += (new Date().getTime()) - this._pauseStart;
  177. this._paused = false;
  178. }
  179. },
  180. /**
  181. * Clear animation.
  182. */
  183. clear: function () {
  184. this._clips = [];
  185. },
  186. /**
  187. * Whether animation finished.
  188. */
  189. isFinished: function () {
  190. return !this._clips.length;
  191. },
  192. /**
  193. * Creat animator for a target, whose props can be animated.
  194. *
  195. * @param {Object} target
  196. * @param {Object} options
  197. * @param {boolean} [options.loop=false] Whether loop animation.
  198. * @param {Function} [options.getter=null] Get value from target.
  199. * @param {Function} [options.setter=null] Set value to target.
  200. * @return {module:zrender/animation/Animation~Animator}
  201. */
  202. // TODO Gap
  203. animate: function (target, options) {
  204. options = options || {};
  205. var animator = new Animator(
  206. target,
  207. options.loop,
  208. options.getter,
  209. options.setter
  210. );
  211. this.addAnimator(animator);
  212. return animator;
  213. }
  214. };
  215. util.mixin(Animation, Dispatcher);
  216. export default Animation;