| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 | 
							- /**
 
-  * Animation main class, dispatch and manage all animation controllers
 
-  *
 
-  */
 
- // TODO Additive animation
 
- // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
 
- // https://developer.apple.com/videos/wwdc2014/#236
 
- import Eventful from '../core/Eventful';
 
- import requestAnimationFrame from './requestAnimationFrame';
 
- import Animator from './Animator';
 
- import Clip from './Clip';
 
- export function getTime() {
 
-     return new Date().getTime();
 
- }
 
- interface Stage {
 
-     update?: () => void
 
- }
 
- interface AnimationOption {
 
-     stage?: Stage
 
- }
 
- /**
 
-  * @example
 
-  *     const animation = new Animation();
 
-  *     const obj = {
 
-  *         x: 100,
 
-  *         y: 100
 
-  *     };
 
-  *     animation.animate(node.position)
 
-  *         .when(1000, {
 
-  *             x: 500,
 
-  *             y: 500
 
-  *         })
 
-  *         .when(2000, {
 
-  *             x: 100,
 
-  *             y: 100
 
-  *         })
 
-  *         .start();
 
-  */
 
- export default class Animation extends Eventful {
 
-     stage: Stage
 
-     // Use linked list to store clip
 
-     private _head: Clip
 
-     private _tail: Clip
 
-     private _running = false
 
-     private _time = 0
 
-     private _pausedTime = 0
 
-     private _pauseStart = 0
 
-     private _paused = false;
 
-     constructor(opts?: AnimationOption) {
 
-         super();
 
-         opts = opts || {};
 
-         this.stage = opts.stage || {};
 
-     }
 
-     /**
 
-      * Add clip
 
-      */
 
-     addClip(clip: Clip) {
 
-         if (clip.animation) {
 
-             // Clip has been added
 
-             this.removeClip(clip);
 
-         }
 
-         if (!this._head) {
 
-             this._head = this._tail = clip;
 
-         }
 
-         else {
 
-             this._tail.next = clip;
 
-             clip.prev = this._tail;
 
-             clip.next = null;
 
-             this._tail = clip;
 
-         }
 
-         clip.animation = this;
 
-     }
 
-     /**
 
-      * Add animator
 
-      */
 
-     addAnimator(animator: Animator<any>) {
 
-         animator.animation = this;
 
-         const clip = animator.getClip();
 
-         if (clip) {
 
-             this.addClip(clip);
 
-         }
 
-     }
 
-     /**
 
-      * Delete animation clip
 
-      */
 
-     removeClip(clip: Clip) {
 
-         if (!clip.animation) {
 
-             return;
 
-         }
 
-         const prev = clip.prev;
 
-         const next = clip.next;
 
-         if (prev) {
 
-             prev.next = next;
 
-         }
 
-         else {
 
-             // Is head
 
-             this._head = next;
 
-         }
 
-         if (next) {
 
-             next.prev = prev;
 
-         }
 
-         else {
 
-             // Is tail
 
-             this._tail = prev;
 
-         }
 
-         clip.next = clip.prev = clip.animation = null;
 
-     }
 
-     /**
 
-      * Delete animation clip
 
-      */
 
-     removeAnimator(animator: Animator<any>) {
 
-         const clip = animator.getClip();
 
-         if (clip) {
 
-             this.removeClip(clip);
 
-         }
 
-         animator.animation = null;
 
-     }
 
-     update(notTriggerFrameAndStageUpdate?: boolean) {
 
-         const time = getTime() - this._pausedTime;
 
-         const delta = time - this._time;
 
-         let clip = this._head;
 
-         while (clip) {
 
-             // Save the nextClip before step.
 
-             // So the loop will not been affected if the clip is removed in the callback
 
-             const nextClip = clip.next;
 
-             let finished = clip.step(time, delta);
 
-             if (finished) {
 
-                 clip.ondestroy();
 
-                 this.removeClip(clip);
 
-                 clip = nextClip;
 
-             }
 
-             else {
 
-                 clip = nextClip;
 
-             }
 
-         }
 
-         this._time = time;
 
-         if (!notTriggerFrameAndStageUpdate) {
 
-             // 'frame' should be triggered before stage, because upper application
 
-             // depends on the sequence (e.g., echarts-stream and finish
 
-             // event judge)
 
-             this.trigger('frame', delta);
 
-             this.stage.update && this.stage.update();
 
-         }
 
-     }
 
-     _startLoop() {
 
-         const self = this;
 
-         this._running = true;
 
-         function step() {
 
-             if (self._running) {
 
-                 requestAnimationFrame(step);
 
-                 !self._paused && self.update();
 
-             }
 
-         }
 
-         requestAnimationFrame(step);
 
-     }
 
-     /**
 
-      * Start animation.
 
-      */
 
-     start() {
 
-         if (this._running) {
 
-             return;
 
-         }
 
-         this._time = getTime();
 
-         this._pausedTime = 0;
 
-         this._startLoop();
 
-     }
 
-     /**
 
-      * Stop animation.
 
-      */
 
-     stop() {
 
-         this._running = false;
 
-     }
 
-     /**
 
-      * Pause animation.
 
-      */
 
-     pause() {
 
-         if (!this._paused) {
 
-             this._pauseStart = getTime();
 
-             this._paused = true;
 
-         }
 
-     }
 
-     /**
 
-      * Resume animation.
 
-      */
 
-     resume() {
 
-         if (this._paused) {
 
-             this._pausedTime += getTime() - this._pauseStart;
 
-             this._paused = false;
 
-         }
 
-     }
 
-     /**
 
-      * Clear animation.
 
-      */
 
-     clear() {
 
-         let clip = this._head;
 
-         while (clip) {
 
-             let nextClip = clip.next;
 
-             clip.prev = clip.next = clip.animation = null;
 
-             clip = nextClip;
 
-         }
 
-         this._head = this._tail = null;
 
-     }
 
-     /**
 
-      * Whether animation finished.
 
-      */
 
-     isFinished() {
 
-         return this._head == null;
 
-     }
 
-     /**
 
-      * Creat animator for a target, whose props can be animated.
 
-      */
 
-     // TODO Gap
 
-     animate<T>(target: T, options: {
 
-         loop?: boolean  // Whether loop animation
 
-     }) {
 
-         options = options || {};
 
-         // Start animation loop
 
-         this.start();
 
-         const animator = new Animator(
 
-             target,
 
-             options.loop
 
-         );
 
-         this.addAnimator(animator);
 
-         return animator;
 
-     }
 
- }
 
 
  |