Animation.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. var util = require("../core/util");
  2. var _event = require("../core/event");
  3. var Dispatcher = _event.Dispatcher;
  4. var requestAnimationFrame = require("./requestAnimationFrame");
  5. var Animator = require("./Animator");
  6. /**
  7. * Animation main class, dispatch and manage all animation controllers
  8. *
  9. * @module zrender/animation/Animation
  10. * @author pissang(https://github.com/pissang)
  11. */
  12. // TODO Additive animation
  13. // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
  14. // https://developer.apple.com/videos/wwdc2014/#236
  15. /**
  16. * @typedef {Object} IZRenderStage
  17. * @property {Function} update
  18. */
  19. /**
  20. * @alias module:zrender/animation/Animation
  21. * @constructor
  22. * @param {Object} [options]
  23. * @param {Function} [options.onframe]
  24. * @param {IZRenderStage} [options.stage]
  25. * @example
  26. * var animation = new Animation();
  27. * var obj = {
  28. * x: 100,
  29. * y: 100
  30. * };
  31. * animation.animate(node.position)
  32. * .when(1000, {
  33. * x: 500,
  34. * y: 500
  35. * })
  36. * .when(2000, {
  37. * x: 100,
  38. * y: 100
  39. * })
  40. * .start('spline');
  41. */
  42. var Animation = function (options) {
  43. options = options || {};
  44. this.stage = options.stage || {};
  45. this.onframe = options.onframe || function () {}; // 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); // Throw out the events need to be called after
  105. // stage.update, like destroy
  106. if (e) {
  107. deferredEvents.push(e);
  108. deferredClips.push(clip);
  109. }
  110. } // Remove the finished clip
  111. for (var i = 0; i < len;) {
  112. if (clips[i]._needsRemove) {
  113. clips[i] = clips[len - 1];
  114. clips.pop();
  115. len--;
  116. } else {
  117. i++;
  118. }
  119. }
  120. len = deferredEvents.length;
  121. for (var i = 0; i < len; i++) {
  122. deferredClips[i].fire(deferredEvents[i]);
  123. }
  124. this._time = time;
  125. this.onframe(delta); // 'frame' should be triggered before stage, because upper application
  126. // depends on the sequence (e.g., echarts-stream and finish
  127. // event judge)
  128. this.trigger('frame', delta);
  129. if (this.stage.update) {
  130. this.stage.update();
  131. }
  132. },
  133. _startLoop: function () {
  134. var self = this;
  135. this._running = true;
  136. function step() {
  137. if (self._running) {
  138. requestAnimationFrame(step);
  139. !self._paused && self._update();
  140. }
  141. }
  142. requestAnimationFrame(step);
  143. },
  144. /**
  145. * Start animation.
  146. */
  147. start: function () {
  148. this._time = new Date().getTime();
  149. this._pausedTime = 0;
  150. this._startLoop();
  151. },
  152. /**
  153. * Stop animation.
  154. */
  155. stop: function () {
  156. this._running = false;
  157. },
  158. /**
  159. * Pause animation.
  160. */
  161. pause: function () {
  162. if (!this._paused) {
  163. this._pauseStart = new Date().getTime();
  164. this._paused = true;
  165. }
  166. },
  167. /**
  168. * Resume animation.
  169. */
  170. resume: function () {
  171. if (this._paused) {
  172. this._pausedTime += new Date().getTime() - this._pauseStart;
  173. this._paused = false;
  174. }
  175. },
  176. /**
  177. * Clear animation.
  178. */
  179. clear: function () {
  180. this._clips = [];
  181. },
  182. /**
  183. * Whether animation finished.
  184. */
  185. isFinished: function () {
  186. return !this._clips.length;
  187. },
  188. /**
  189. * Creat animator for a target, whose props can be animated.
  190. *
  191. * @param {Object} target
  192. * @param {Object} options
  193. * @param {boolean} [options.loop=false] Whether loop animation.
  194. * @param {Function} [options.getter=null] Get value from target.
  195. * @param {Function} [options.setter=null] Set value to target.
  196. * @return {module:zrender/animation/Animation~Animator}
  197. */
  198. // TODO Gap
  199. animate: function (target, options) {
  200. options = options || {};
  201. var animator = new Animator(target, options.loop, options.getter, options.setter);
  202. this.addAnimator(animator);
  203. return animator;
  204. }
  205. };
  206. util.mixin(Animation, Dispatcher);
  207. var _default = Animation;
  208. module.exports = _default;