247 lines
5.3 KiB
JavaScript
247 lines
5.3 KiB
JavaScript
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; |