| /** |
| * 动画主类, 调度和管理所有动画控制器 |
| * |
| * @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 |
| import * as util from '../core/util'; |
| import { Dispatcher } from '../core/event'; |
| import requestAnimationFrame from './requestAnimationFrame'; |
| import Animator from './Animator'; |
| /** |
| * @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, |
| |
| /** |
| * 添加 clip |
| * @param {module:zrender/animation/Clip} clip |
| */ |
| addClip: function (clip) { |
| this._clips.push(clip); |
| }, |
| |
| /** |
| * 添加 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]); |
| } |
| }, |
| |
| /** |
| * 删除动画片段 |
| * @param {module:zrender/animation/Clip} clip |
| */ |
| removeClip: function (clip) { |
| var idx = util.indexOf(this._clips, clip); |
| |
| if (idx >= 0) { |
| this._clips.splice(idx, 1); |
| } |
| }, |
| |
| /** |
| * 删除动画片段 |
| * @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); |
| 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: function () { |
| this._time = new Date().getTime(); |
| this._pausedTime = 0; |
| |
| this._startLoop(); |
| }, |
| |
| /** |
| * 停止运行动画 |
| */ |
| stop: function () { |
| this._running = false; |
| }, |
| |
| /** |
| * Pause |
| */ |
| pause: function () { |
| if (!this._paused) { |
| this._pauseStart = new Date().getTime(); |
| this._paused = true; |
| } |
| }, |
| |
| /** |
| * Resume |
| */ |
| resume: function () { |
| if (this._paused) { |
| this._pausedTime += new Date().getTime() - this._pauseStart; |
| this._paused = false; |
| } |
| }, |
| |
| /** |
| * 清除所有动画片段 |
| */ |
| clear: function () { |
| this._clips = []; |
| }, |
| |
| /** |
| * 对一个目标创建一个animator对象,可以指定目标中的属性使用动画 |
| * @param {Object} target |
| * @param {Object} options |
| * @param {boolean} [options.loop=false] 是否循环播放动画 |
| * @param {Function} [options.getter=null] |
| * 如果指定getter函数,会通过getter函数取属性值 |
| * @param {Function} [options.setter=null] |
| * 如果指定setter函数,会通过setter函数设置属性值 |
| * @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); |
| export default Animation; |