123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- var util = require("../core/util");
- var _event = require("../core/event");
- var Dispatcher = _event.Dispatcher;
- var requestAnimationFrame = require("./requestAnimationFrame");
- var Animator = require("./Animator");
- /**
- * Animation main class, dispatch and manage all animation controllers
- *
- * @module zrender/animation/Animation
- * @author pissang(https://github.com/pissang)
- */
- // TODO Additive animation
- // http://iosoteric.com/additive-animations-animatewithduration-in-ios-8/
- // https://developer.apple.com/videos/wwdc2014/#236
- /**
- * @typedef {Object} IZRenderStage
- * @property {Function} update
- */
- /**
- * @alias module:zrender/animation/Animation
- * @constructor
- * @param {Object} [options]
- * @param {Function} [options.onframe]
- * @param {IZRenderStage} [options.stage]
- * @example
- * var animation = new Animation();
- * var obj = {
- * x: 100,
- * y: 100
- * };
- * animation.animate(node.position)
- * .when(1000, {
- * x: 500,
- * y: 500
- * })
- * .when(2000, {
- * x: 100,
- * y: 100
- * })
- * .start('spline');
- */
- var Animation = function (options) {
- options = options || {};
- this.stage = options.stage || {};
- this.onframe = options.onframe || function () {}; // private properties
- this._clips = [];
- this._running = false;
- this._time;
- this._pausedTime;
- this._pauseStart;
- this._paused = false;
- Dispatcher.call(this);
- };
- Animation.prototype = {
- constructor: Animation,
- /**
- * Add clip
- * @param {module:zrender/animation/Clip} clip
- */
- addClip: function (clip) {
- this._clips.push(clip);
- },
- /**
- * Add animator
- * @param {module:zrender/animation/Animator} animator
- */
- addAnimator: function (animator) {
- animator.animation = this;
- var clips = animator.getClips();
- for (var i = 0; i < clips.length; i++) {
- this.addClip(clips[i]);
- }
- },
- /**
- * Delete animation clip
- * @param {module:zrender/animation/Clip} clip
- */
- removeClip: function (clip) {
- var idx = util.indexOf(this._clips, clip);
- if (idx >= 0) {
- this._clips.splice(idx, 1);
- }
- },
- /**
- * Delete animation clip
- * @param {module:zrender/animation/Animator} animator
- */
- removeAnimator: function (animator) {
- var clips = animator.getClips();
- for (var i = 0; i < clips.length; i++) {
- this.removeClip(clips[i]);
- }
- animator.animation = null;
- },
- _update: function () {
- var time = new Date().getTime() - this._pausedTime;
- var delta = time - this._time;
- var clips = this._clips;
- var len = clips.length;
- var deferredEvents = [];
- var deferredClips = [];
- for (var i = 0; i < len; i++) {
- var clip = clips[i];
- var e = clip.step(time, delta); // Throw out the events need to be called after
- // stage.update, like destroy
- if (e) {
- deferredEvents.push(e);
- deferredClips.push(clip);
- }
- } // Remove the finished clip
- for (var i = 0; i < len;) {
- if (clips[i]._needsRemove) {
- clips[i] = clips[len - 1];
- clips.pop();
- len--;
- } else {
- i++;
- }
- }
- len = deferredEvents.length;
- for (var i = 0; i < len; i++) {
- deferredClips[i].fire(deferredEvents[i]);
- }
- this._time = time;
- this.onframe(delta); // '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);
- if (this.stage.update) {
- this.stage.update();
- }
- },
- _startLoop: function () {
- var self = this;
- this._running = true;
- function step() {
- if (self._running) {
- requestAnimationFrame(step);
- !self._paused && self._update();
- }
- }
- requestAnimationFrame(step);
- },
- /**
- * Start animation.
- */
- start: function () {
- this._time = new Date().getTime();
- this._pausedTime = 0;
- this._startLoop();
- },
- /**
- * Stop animation.
- */
- stop: function () {
- this._running = false;
- },
- /**
- * Pause animation.
- */
- pause: function () {
- if (!this._paused) {
- this._pauseStart = new Date().getTime();
- this._paused = true;
- }
- },
- /**
- * Resume animation.
- */
- resume: function () {
- if (this._paused) {
- this._pausedTime += new Date().getTime() - this._pauseStart;
- this._paused = false;
- }
- },
- /**
- * Clear animation.
- */
- clear: function () {
- this._clips = [];
- },
- /**
- * Whether animation finished.
- */
- isFinished: function () {
- return !this._clips.length;
- },
- /**
- * Creat animator for a target, whose props can be animated.
- *
- * @param {Object} target
- * @param {Object} options
- * @param {boolean} [options.loop=false] Whether loop animation.
- * @param {Function} [options.getter=null] Get value from target.
- * @param {Function} [options.setter=null] Set value to target.
- * @return {module:zrender/animation/Animation~Animator}
- */
- // TODO Gap
- animate: function (target, options) {
- options = options || {};
- var animator = new Animator(target, options.loop, options.getter, options.setter);
- this.addAnimator(animator);
- return animator;
- }
- };
- util.mixin(Animation, Dispatcher);
- var _default = Animation;
- module.exports = _default;
|