644 lines
14 KiB
JavaScript
644 lines
14 KiB
JavaScript
|
var Clip = require("./Clip");
|
|||
|
|
|||
|
var color = require("../tool/color");
|
|||
|
|
|||
|
var _util = require("../core/util");
|
|||
|
|
|||
|
var isArrayLike = _util.isArrayLike;
|
|||
|
|
|||
|
/**
|
|||
|
* @module echarts/animation/Animator
|
|||
|
*/
|
|||
|
var arraySlice = Array.prototype.slice;
|
|||
|
|
|||
|
function defaultGetter(target, key) {
|
|||
|
return target[key];
|
|||
|
}
|
|||
|
|
|||
|
function defaultSetter(target, key, value) {
|
|||
|
target[key] = value;
|
|||
|
}
|
|||
|
/**
|
|||
|
* @param {number} p0
|
|||
|
* @param {number} p1
|
|||
|
* @param {number} percent
|
|||
|
* @return {number}
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
function interpolateNumber(p0, p1, percent) {
|
|||
|
return (p1 - p0) * percent + p0;
|
|||
|
}
|
|||
|
/**
|
|||
|
* @param {string} p0
|
|||
|
* @param {string} p1
|
|||
|
* @param {number} percent
|
|||
|
* @return {string}
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
function interpolateString(p0, p1, percent) {
|
|||
|
return percent > 0.5 ? p1 : p0;
|
|||
|
}
|
|||
|
/**
|
|||
|
* @param {Array} p0
|
|||
|
* @param {Array} p1
|
|||
|
* @param {number} percent
|
|||
|
* @param {Array} out
|
|||
|
* @param {number} arrDim
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
function interpolateArray(p0, p1, percent, out, arrDim) {
|
|||
|
var len = p0.length;
|
|||
|
|
|||
|
if (arrDim === 1) {
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
out[i] = interpolateNumber(p0[i], p1[i], percent);
|
|||
|
}
|
|||
|
} else {
|
|||
|
var len2 = len && p0[0].length;
|
|||
|
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
for (var j = 0; j < len2; j++) {
|
|||
|
out[i][j] = interpolateNumber(p0[i][j], p1[i][j], percent);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
} // arr0 is source array, arr1 is target array.
|
|||
|
// Do some preprocess to avoid error happened when interpolating from arr0 to arr1
|
|||
|
|
|||
|
|
|||
|
function fillArr(arr0, arr1, arrDim) {
|
|||
|
var arr0Len = arr0.length;
|
|||
|
var arr1Len = arr1.length;
|
|||
|
|
|||
|
if (arr0Len !== arr1Len) {
|
|||
|
// FIXME Not work for TypedArray
|
|||
|
var isPreviousLarger = arr0Len > arr1Len;
|
|||
|
|
|||
|
if (isPreviousLarger) {
|
|||
|
// Cut the previous
|
|||
|
arr0.length = arr1Len;
|
|||
|
} else {
|
|||
|
// Fill the previous
|
|||
|
for (var i = arr0Len; i < arr1Len; i++) {
|
|||
|
arr0.push(arrDim === 1 ? arr1[i] : arraySlice.call(arr1[i]));
|
|||
|
}
|
|||
|
}
|
|||
|
} // Handling NaN value
|
|||
|
|
|||
|
|
|||
|
var len2 = arr0[0] && arr0[0].length;
|
|||
|
|
|||
|
for (var i = 0; i < arr0.length; i++) {
|
|||
|
if (arrDim === 1) {
|
|||
|
if (isNaN(arr0[i])) {
|
|||
|
arr0[i] = arr1[i];
|
|||
|
}
|
|||
|
} else {
|
|||
|
for (var j = 0; j < len2; j++) {
|
|||
|
if (isNaN(arr0[i][j])) {
|
|||
|
arr0[i][j] = arr1[i][j];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/**
|
|||
|
* @param {Array} arr0
|
|||
|
* @param {Array} arr1
|
|||
|
* @param {number} arrDim
|
|||
|
* @return {boolean}
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
function isArraySame(arr0, arr1, arrDim) {
|
|||
|
if (arr0 === arr1) {
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
var len = arr0.length;
|
|||
|
|
|||
|
if (len !== arr1.length) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
if (arrDim === 1) {
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
if (arr0[i] !== arr1[i]) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
} else {
|
|||
|
var len2 = arr0[0].length;
|
|||
|
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
for (var j = 0; j < len2; j++) {
|
|||
|
if (arr0[i][j] !== arr1[i][j]) {
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return true;
|
|||
|
}
|
|||
|
/**
|
|||
|
* Catmull Rom interpolate array
|
|||
|
* @param {Array} p0
|
|||
|
* @param {Array} p1
|
|||
|
* @param {Array} p2
|
|||
|
* @param {Array} p3
|
|||
|
* @param {number} t
|
|||
|
* @param {number} t2
|
|||
|
* @param {number} t3
|
|||
|
* @param {Array} out
|
|||
|
* @param {number} arrDim
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
function catmullRomInterpolateArray(p0, p1, p2, p3, t, t2, t3, out, arrDim) {
|
|||
|
var len = p0.length;
|
|||
|
|
|||
|
if (arrDim === 1) {
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
out[i] = catmullRomInterpolate(p0[i], p1[i], p2[i], p3[i], t, t2, t3);
|
|||
|
}
|
|||
|
} else {
|
|||
|
var len2 = p0[0].length;
|
|||
|
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
for (var j = 0; j < len2; j++) {
|
|||
|
out[i][j] = catmullRomInterpolate(p0[i][j], p1[i][j], p2[i][j], p3[i][j], t, t2, t3);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
/**
|
|||
|
* Catmull Rom interpolate number
|
|||
|
* @param {number} p0
|
|||
|
* @param {number} p1
|
|||
|
* @param {number} p2
|
|||
|
* @param {number} p3
|
|||
|
* @param {number} t
|
|||
|
* @param {number} t2
|
|||
|
* @param {number} t3
|
|||
|
* @return {number}
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
function catmullRomInterpolate(p0, p1, p2, p3, t, t2, t3) {
|
|||
|
var v0 = (p2 - p0) * 0.5;
|
|||
|
var v1 = (p3 - p1) * 0.5;
|
|||
|
return (2 * (p1 - p2) + v0 + v1) * t3 + (-3 * (p1 - p2) - 2 * v0 - v1) * t2 + v0 * t + p1;
|
|||
|
}
|
|||
|
|
|||
|
function cloneValue(value) {
|
|||
|
if (isArrayLike(value)) {
|
|||
|
var len = value.length;
|
|||
|
|
|||
|
if (isArrayLike(value[0])) {
|
|||
|
var ret = [];
|
|||
|
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
ret.push(arraySlice.call(value[i]));
|
|||
|
}
|
|||
|
|
|||
|
return ret;
|
|||
|
}
|
|||
|
|
|||
|
return arraySlice.call(value);
|
|||
|
}
|
|||
|
|
|||
|
return value;
|
|||
|
}
|
|||
|
|
|||
|
function rgba2String(rgba) {
|
|||
|
rgba[0] = Math.floor(rgba[0]);
|
|||
|
rgba[1] = Math.floor(rgba[1]);
|
|||
|
rgba[2] = Math.floor(rgba[2]);
|
|||
|
return 'rgba(' + rgba.join(',') + ')';
|
|||
|
}
|
|||
|
|
|||
|
function getArrayDim(keyframes) {
|
|||
|
var lastValue = keyframes[keyframes.length - 1].value;
|
|||
|
return isArrayLike(lastValue && lastValue[0]) ? 2 : 1;
|
|||
|
}
|
|||
|
|
|||
|
function createTrackClip(animator, easing, oneTrackDone, keyframes, propName, forceAnimate) {
|
|||
|
var getter = animator._getter;
|
|||
|
var setter = animator._setter;
|
|||
|
var useSpline = easing === 'spline';
|
|||
|
var trackLen = keyframes.length;
|
|||
|
|
|||
|
if (!trackLen) {
|
|||
|
return;
|
|||
|
} // Guess data type
|
|||
|
|
|||
|
|
|||
|
var firstVal = keyframes[0].value;
|
|||
|
var isValueArray = isArrayLike(firstVal);
|
|||
|
var isValueColor = false;
|
|||
|
var isValueString = false; // For vertices morphing
|
|||
|
|
|||
|
var arrDim = isValueArray ? getArrayDim(keyframes) : 0;
|
|||
|
var trackMaxTime; // Sort keyframe as ascending
|
|||
|
|
|||
|
keyframes.sort(function (a, b) {
|
|||
|
return a.time - b.time;
|
|||
|
});
|
|||
|
trackMaxTime = keyframes[trackLen - 1].time; // Percents of each keyframe
|
|||
|
|
|||
|
var kfPercents = []; // Value of each keyframe
|
|||
|
|
|||
|
var kfValues = [];
|
|||
|
var prevValue = keyframes[0].value;
|
|||
|
var isAllValueEqual = true;
|
|||
|
|
|||
|
for (var i = 0; i < trackLen; i++) {
|
|||
|
kfPercents.push(keyframes[i].time / trackMaxTime); // Assume value is a color when it is a string
|
|||
|
|
|||
|
var value = keyframes[i].value; // Check if value is equal, deep check if value is array
|
|||
|
|
|||
|
if (!(isValueArray && isArraySame(value, prevValue, arrDim) || !isValueArray && value === prevValue)) {
|
|||
|
isAllValueEqual = false;
|
|||
|
}
|
|||
|
|
|||
|
prevValue = value; // Try converting a string to a color array
|
|||
|
|
|||
|
if (typeof value === 'string') {
|
|||
|
var colorArray = color.parse(value);
|
|||
|
|
|||
|
if (colorArray) {
|
|||
|
value = colorArray;
|
|||
|
isValueColor = true;
|
|||
|
} else {
|
|||
|
isValueString = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
kfValues.push(value);
|
|||
|
}
|
|||
|
|
|||
|
if (!forceAnimate && isAllValueEqual) {
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
var lastValue = kfValues[trackLen - 1]; // Polyfill array and NaN value
|
|||
|
|
|||
|
for (var i = 0; i < trackLen - 1; i++) {
|
|||
|
if (isValueArray) {
|
|||
|
fillArr(kfValues[i], lastValue, arrDim);
|
|||
|
} else {
|
|||
|
if (isNaN(kfValues[i]) && !isNaN(lastValue) && !isValueString && !isValueColor) {
|
|||
|
kfValues[i] = lastValue;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
isValueArray && fillArr(getter(animator._target, propName), lastValue, arrDim); // Cache the key of last frame to speed up when
|
|||
|
// animation playback is sequency
|
|||
|
|
|||
|
var lastFrame = 0;
|
|||
|
var lastFramePercent = 0;
|
|||
|
var start;
|
|||
|
var w;
|
|||
|
var p0;
|
|||
|
var p1;
|
|||
|
var p2;
|
|||
|
var p3;
|
|||
|
|
|||
|
if (isValueColor) {
|
|||
|
var rgba = [0, 0, 0, 0];
|
|||
|
}
|
|||
|
|
|||
|
var onframe = function (target, percent) {
|
|||
|
// Find the range keyframes
|
|||
|
// kf1-----kf2---------current--------kf3
|
|||
|
// find kf2 and kf3 and do interpolation
|
|||
|
var frame; // In the easing function like elasticOut, percent may less than 0
|
|||
|
|
|||
|
if (percent < 0) {
|
|||
|
frame = 0;
|
|||
|
} else if (percent < lastFramePercent) {
|
|||
|
// Start from next key
|
|||
|
// PENDING start from lastFrame ?
|
|||
|
start = Math.min(lastFrame + 1, trackLen - 1);
|
|||
|
|
|||
|
for (frame = start; frame >= 0; frame--) {
|
|||
|
if (kfPercents[frame] <= percent) {
|
|||
|
break;
|
|||
|
}
|
|||
|
} // PENDING really need to do this ?
|
|||
|
|
|||
|
|
|||
|
frame = Math.min(frame, trackLen - 2);
|
|||
|
} else {
|
|||
|
for (frame = lastFrame; frame < trackLen; frame++) {
|
|||
|
if (kfPercents[frame] > percent) {
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
frame = Math.min(frame - 1, trackLen - 2);
|
|||
|
}
|
|||
|
|
|||
|
lastFrame = frame;
|
|||
|
lastFramePercent = percent;
|
|||
|
var range = kfPercents[frame + 1] - kfPercents[frame];
|
|||
|
|
|||
|
if (range === 0) {
|
|||
|
return;
|
|||
|
} else {
|
|||
|
w = (percent - kfPercents[frame]) / range;
|
|||
|
}
|
|||
|
|
|||
|
if (useSpline) {
|
|||
|
p1 = kfValues[frame];
|
|||
|
p0 = kfValues[frame === 0 ? frame : frame - 1];
|
|||
|
p2 = kfValues[frame > trackLen - 2 ? trackLen - 1 : frame + 1];
|
|||
|
p3 = kfValues[frame > trackLen - 3 ? trackLen - 1 : frame + 2];
|
|||
|
|
|||
|
if (isValueArray) {
|
|||
|
catmullRomInterpolateArray(p0, p1, p2, p3, w, w * w, w * w * w, getter(target, propName), arrDim);
|
|||
|
} else {
|
|||
|
var value;
|
|||
|
|
|||
|
if (isValueColor) {
|
|||
|
value = catmullRomInterpolateArray(p0, p1, p2, p3, w, w * w, w * w * w, rgba, 1);
|
|||
|
value = rgba2String(rgba);
|
|||
|
} else if (isValueString) {
|
|||
|
// String is step(0.5)
|
|||
|
return interpolateString(p1, p2, w);
|
|||
|
} else {
|
|||
|
value = catmullRomInterpolate(p0, p1, p2, p3, w, w * w, w * w * w);
|
|||
|
}
|
|||
|
|
|||
|
setter(target, propName, value);
|
|||
|
}
|
|||
|
} else {
|
|||
|
if (isValueArray) {
|
|||
|
interpolateArray(kfValues[frame], kfValues[frame + 1], w, getter(target, propName), arrDim);
|
|||
|
} else {
|
|||
|
var value;
|
|||
|
|
|||
|
if (isValueColor) {
|
|||
|
interpolateArray(kfValues[frame], kfValues[frame + 1], w, rgba, 1);
|
|||
|
value = rgba2String(rgba);
|
|||
|
} else if (isValueString) {
|
|||
|
// String is step(0.5)
|
|||
|
return interpolateString(kfValues[frame], kfValues[frame + 1], w);
|
|||
|
} else {
|
|||
|
value = interpolateNumber(kfValues[frame], kfValues[frame + 1], w);
|
|||
|
}
|
|||
|
|
|||
|
setter(target, propName, value);
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var clip = new Clip({
|
|||
|
target: animator._target,
|
|||
|
life: trackMaxTime,
|
|||
|
loop: animator._loop,
|
|||
|
delay: animator._delay,
|
|||
|
onframe: onframe,
|
|||
|
ondestroy: oneTrackDone
|
|||
|
});
|
|||
|
|
|||
|
if (easing && easing !== 'spline') {
|
|||
|
clip.easing = easing;
|
|||
|
}
|
|||
|
|
|||
|
return clip;
|
|||
|
}
|
|||
|
/**
|
|||
|
* @alias module:zrender/animation/Animator
|
|||
|
* @constructor
|
|||
|
* @param {Object} target
|
|||
|
* @param {boolean} loop
|
|||
|
* @param {Function} getter
|
|||
|
* @param {Function} setter
|
|||
|
*/
|
|||
|
|
|||
|
|
|||
|
var Animator = function (target, loop, getter, setter) {
|
|||
|
this._tracks = {};
|
|||
|
this._target = target;
|
|||
|
this._loop = loop || false;
|
|||
|
this._getter = getter || defaultGetter;
|
|||
|
this._setter = setter || defaultSetter;
|
|||
|
this._clipCount = 0;
|
|||
|
this._delay = 0;
|
|||
|
this._doneList = [];
|
|||
|
this._onframeList = [];
|
|||
|
this._clipList = [];
|
|||
|
};
|
|||
|
|
|||
|
Animator.prototype = {
|
|||
|
/**
|
|||
|
* 设置动画关键帧
|
|||
|
* @param {number} time 关键帧时间,单位是ms
|
|||
|
* @param {Object} props 关键帧的属性值,key-value表示
|
|||
|
* @return {module:zrender/animation/Animator}
|
|||
|
*/
|
|||
|
when: function (time
|
|||
|
/* ms */
|
|||
|
, props) {
|
|||
|
var tracks = this._tracks;
|
|||
|
|
|||
|
for (var propName in props) {
|
|||
|
if (!props.hasOwnProperty(propName)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
if (!tracks[propName]) {
|
|||
|
tracks[propName] = []; // Invalid value
|
|||
|
|
|||
|
var value = this._getter(this._target, propName);
|
|||
|
|
|||
|
if (value == null) {
|
|||
|
// zrLog('Invalid property ' + propName);
|
|||
|
continue;
|
|||
|
} // If time is 0
|
|||
|
// Then props is given initialize value
|
|||
|
// Else
|
|||
|
// Initialize value from current prop value
|
|||
|
|
|||
|
|
|||
|
if (time !== 0) {
|
|||
|
tracks[propName].push({
|
|||
|
time: 0,
|
|||
|
value: cloneValue(value)
|
|||
|
});
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
tracks[propName].push({
|
|||
|
time: time,
|
|||
|
value: props[propName]
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 添加动画每一帧的回调函数
|
|||
|
* @param {Function} callback
|
|||
|
* @return {module:zrender/animation/Animator}
|
|||
|
*/
|
|||
|
during: function (callback) {
|
|||
|
this._onframeList.push(callback);
|
|||
|
|
|||
|
return this;
|
|||
|
},
|
|||
|
pause: function () {
|
|||
|
for (var i = 0; i < this._clipList.length; i++) {
|
|||
|
this._clipList[i].pause();
|
|||
|
}
|
|||
|
|
|||
|
this._paused = true;
|
|||
|
},
|
|||
|
resume: function () {
|
|||
|
for (var i = 0; i < this._clipList.length; i++) {
|
|||
|
this._clipList[i].resume();
|
|||
|
}
|
|||
|
|
|||
|
this._paused = false;
|
|||
|
},
|
|||
|
isPaused: function () {
|
|||
|
return !!this._paused;
|
|||
|
},
|
|||
|
_doneCallback: function () {
|
|||
|
// Clear all tracks
|
|||
|
this._tracks = {}; // Clear all clips
|
|||
|
|
|||
|
this._clipList.length = 0;
|
|||
|
var doneList = this._doneList;
|
|||
|
var len = doneList.length;
|
|||
|
|
|||
|
for (var i = 0; i < len; i++) {
|
|||
|
doneList[i].call(this);
|
|||
|
}
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 开始执行动画
|
|||
|
* @param {string|Function} [easing]
|
|||
|
* 动画缓动函数,详见{@link module:zrender/animation/easing}
|
|||
|
* @param {boolean} forceAnimate
|
|||
|
* @return {module:zrender/animation/Animator}
|
|||
|
*/
|
|||
|
start: function (easing, forceAnimate) {
|
|||
|
var self = this;
|
|||
|
var clipCount = 0;
|
|||
|
|
|||
|
var oneTrackDone = function () {
|
|||
|
clipCount--;
|
|||
|
|
|||
|
if (!clipCount) {
|
|||
|
self._doneCallback();
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
var lastClip;
|
|||
|
|
|||
|
for (var propName in this._tracks) {
|
|||
|
if (!this._tracks.hasOwnProperty(propName)) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
var clip = createTrackClip(this, easing, oneTrackDone, this._tracks[propName], propName, forceAnimate);
|
|||
|
|
|||
|
if (clip) {
|
|||
|
this._clipList.push(clip);
|
|||
|
|
|||
|
clipCount++; // If start after added to animation
|
|||
|
|
|||
|
if (this.animation) {
|
|||
|
this.animation.addClip(clip);
|
|||
|
}
|
|||
|
|
|||
|
lastClip = clip;
|
|||
|
}
|
|||
|
} // Add during callback on the last clip
|
|||
|
|
|||
|
|
|||
|
if (lastClip) {
|
|||
|
var oldOnFrame = lastClip.onframe;
|
|||
|
|
|||
|
lastClip.onframe = function (target, percent) {
|
|||
|
oldOnFrame(target, percent);
|
|||
|
|
|||
|
for (var i = 0; i < self._onframeList.length; i++) {
|
|||
|
self._onframeList[i](target, percent);
|
|||
|
}
|
|||
|
};
|
|||
|
} // This optimization will help the case that in the upper application
|
|||
|
// the view may be refreshed frequently, where animation will be
|
|||
|
// called repeatly but nothing changed.
|
|||
|
|
|||
|
|
|||
|
if (!clipCount) {
|
|||
|
this._doneCallback();
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 停止动画
|
|||
|
* @param {boolean} forwardToLast If move to last frame before stop
|
|||
|
*/
|
|||
|
stop: function (forwardToLast) {
|
|||
|
var clipList = this._clipList;
|
|||
|
var animation = this.animation;
|
|||
|
|
|||
|
for (var i = 0; i < clipList.length; i++) {
|
|||
|
var clip = clipList[i];
|
|||
|
|
|||
|
if (forwardToLast) {
|
|||
|
// Move to last frame before stop
|
|||
|
clip.onframe(this._target, 1);
|
|||
|
}
|
|||
|
|
|||
|
animation && animation.removeClip(clip);
|
|||
|
}
|
|||
|
|
|||
|
clipList.length = 0;
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 设置动画延迟开始的时间
|
|||
|
* @param {number} time 单位ms
|
|||
|
* @return {module:zrender/animation/Animator}
|
|||
|
*/
|
|||
|
delay: function (time) {
|
|||
|
this._delay = time;
|
|||
|
return this;
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* 添加动画结束的回调
|
|||
|
* @param {Function} cb
|
|||
|
* @return {module:zrender/animation/Animator}
|
|||
|
*/
|
|||
|
done: function (cb) {
|
|||
|
if (cb) {
|
|||
|
this._doneList.push(cb);
|
|||
|
}
|
|||
|
|
|||
|
return this;
|
|||
|
},
|
|||
|
|
|||
|
/**
|
|||
|
* @return {Array.<module:zrender/animation/Clip>}
|
|||
|
*/
|
|||
|
getClips: function () {
|
|||
|
return this._clipList;
|
|||
|
}
|
|||
|
};
|
|||
|
var _default = Animator;
|
|||
|
module.exports = _default;
|