tinyjs-plugin-easy-animation
Version:
a easy way to use tiny tween animation
518 lines (500 loc) • 18.6 kB
JavaScript
/*!
* Name: tinyjs-plugin-easy-animation
* Description: a easy way to use tiny tween animation
* Author: zhaizheng.zz
* Version: v0.1.3
*/
// AppX: adapter for the alibaba mini program
if (typeof $global !== 'undefined') {
window = $global.window
navigator = window.navigator
Tiny = $global.Tiny
}
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
};
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var defineProperty = function (obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
};
var _extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
var slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
var xEval = function xEval(localValue, operation) {
var FN = Function;
if (typeof localValue === 'number') {
return new FN('return ' + localValue + operation)();
}
return {
x: new FN('return ' + localValue.x + operation)(),
y: new FN('return ' + localValue.y + operation)()
};
};
var parsePercent = function parsePercent(percentValue) {
return percentValue.slice(0, -1) / 100;
};
var isUndefined = function isUndefined(value) {
return value === void 0;
};
var isObject = function isObject(target) {
return Object.prototype.toString.call(target) === '[object Object]';
};
var deepCloneConfig = function deepCloneConfig(config) {
var configClone = {};
for (var key in config) {
if (config.hasOwnProperty(key)) {
if (config[key] && _typeof(config[key]) === 'object') {
if (Array.isArray(config[key])) {
configClone[key] = config[key].map(function (item) {
if ((typeof item === 'undefined' ? 'undefined' : _typeof(item)) === 'object') {
return deepCloneConfig(item);
}
return item;
});
} else {
configClone[key] = deepCloneConfig(config[key]);
}
} else {
configClone[key] = config[key];
}
}
}
return configClone;
};
var xRequestAnimationFrame = function xRequestAnimationFrame(callback) {
if (navigator.canUseBinding) {
return setTimeout(function () {
callback && callback();
}, 0);
} else {
return window.requestAnimationFrame(function () {
callback && callback();
});
}
};
var xCancelAnimationFrame = function xCancelAnimationFrame(handler) {
if (navigator.canUseBinding) {
clearTimeout(handler);
} else {
window.cancelAnimationFrame(handler);
}
};
var getParentRelativePosValue = function getParentRelativePosValue(displayObject, property, targetValue, toValue, clipIndex) {
displayObject.displayObjectUpdateTransform();
var operator = toValue < targetValue ? '-' : '+';
var localValue = void 0;
var deltaValue = toValue - targetValue;
if (property === 'position.x') {
localValue = displayObject.localTransform.tx;
} else if (property === 'position.y') {
localValue = displayObject.localTransform.ty;
} else {
localValue = { x: displayObject.localTransform.tx, y: displayObject.localTransform.ty };
}
toValue = '' + operator + Math.abs(deltaValue);
if (clipIndex === 0) {
displayObject.__easyAnimationOperation = toValue;
return {
targetValue: localValue,
toValue: (typeof localValue === 'undefined' ? 'undefined' : _typeof(localValue)) === 'object' ? { x: toValue, y: toValue } : toValue
};
} else {
var _targetValue = xEval(localValue, displayObject.__easyAnimationOperation);
displayObject.__easyAnimationOperation += toValue;
return {
targetValue: _targetValue,
toValue: (typeof localValue === 'undefined' ? 'undefined' : _typeof(localValue)) === 'object' ? { x: toValue, y: toValue } : toValue
};
}
};
/**
* @name tinyjs-plugin-easy-animation
* @overview a easy way to use tiny tween animation
* @author zhaizheng.zz
* @license MIT
*/
var ANIMATION_FILL_MODE = {
'FORWARDS': 'forwards',
'BACKWARDS': 'backwards'
};
var EasyAnimation = function () {
function EasyAnimation(displayObject) {
classCallCheck(this, EasyAnimation);
this.pluginName = 'easyAnimation';
this.displayObject = displayObject;
this.tweenGroup = new Tiny.TWEEN.Group();
this.tweenAnimationCache = {};
this.playingAimationCompleteTimes = {};
this.playingAnimation = '';
this.playTimes = 1;
this.chainAnimationCompleteTimes = 0;
this.playing = false;
this.useRelativePositionValue = false;
this.animationFillMode = 'forwards';
}
createClass(EasyAnimation, [{
key: 'setAnimationConfig',
value: function setAnimationConfig(config, useRelativePositionValue) {
var _this = this;
this.displayObject.updateTransform = function () {
_this.tweenGroup.update();
_this.displayObject.containerUpdateTransform.call(_this.displayObject);
};
this.useRelativePositionValue = useRelativePositionValue;
var tweenConfigs = this.__parseAnimationConfig(deepCloneConfig(config));
this.__createTween(tweenConfigs);
}
}, {
key: 'play',
value: function play(animationName, playTimes, animationFillMode) {
var animations = this.tweenAnimationCache[animationName];
if (!animations) {
throw new Error('can not find animationName {' + animationName + '} in your configs.');
}
if (this.playing) {
return;
}
if (typeof playTimes === 'number') {
this.playTimes = playTimes || 1;
}
if (typeof playTimes === 'string') {
this.animationFillMode = playTimes;
}
if (animationFillMode) {
this.animationFillMode = animationFillMode;
}
this.playingAnimation = animationName;
this.playing = true;
this.__playAnimation(animationName);
}
}, {
key: 'stop',
value: function stop() {
var animations = this.tweenGroup.getAll();
animations.forEach(function (animation) {
animation.stop();
});
this.playing = false;
this.__setAnimationClipCompleteTimes(this.playingAnimation, 0);
this.playingAnimation = '';
this.playTimes = 1;
}
}, {
key: 'clear',
value: function clear() {
this.tweenAnimationCache = {};
this.tweenGroup.removeAll();
this.playingAnimation = '';
this.playingAimationCompleteTimes = {};
this.playTimes = 1;
this.playing = false;
}
}, {
key: '__playAnimation',
value: function __playAnimation(animationName) {
var animations = this.tweenAnimationCache[animationName];
if (!animations) return;
animations.forEach(function (animation) {
animation.start();
});
}
}, {
key: '__createTween',
value: function __createTween(tweenConfigs) {
var _this2 = this;
var animationNames = Object.keys(tweenConfigs);
animationNames.forEach(function (animationName) {
var tweenConfig = tweenConfigs[animationName];
var propertyKeys = Object.keys(tweenConfig);
var displayObjectInitProperty = {};
_this2.tweenAnimationCache[animationName] = propertyKeys.map(function (property) {
var configs = tweenConfig[property];
var tweenCount = 0;
var headTween = void 0;
configs.reduce(function (prevItem, curItem) {
var property = curItem.property,
target = curItem.target,
to = curItem.to,
easeFunction = curItem.easeFunction,
duration = curItem.duration,
delay = curItem.delay;
var _updateProperty = property.split('.');
var _easeFunction = typeof easeFunction === 'function' ? easeFunction : easeFunction.split('.').reduce(function (prev, cur) {
return prev[cur];
}, Tiny.TWEEN.Easing);
var tween = new Tiny.TWEEN.Tween(target, _this2.tweenGroup);
var initValue = target[property] || _extends({}, target);
_this2.__cacheDisplayObjectInitPropertyValue(_updateProperty, property, displayObjectInitProperty);
tween.animationName = animationName;
tween.to(to, duration);
tween.easing(_easeFunction);
tween.delay(delay);
tween.onUpdate(function () {
_this2.__updateDisplayObjectProperty(_updateProperty, isUndefined(target[property]) ? target : target[property]);
});
tween.onComplete(function (data) {
var playingAnimations = _this2.tweenAnimationCache[_this2.playingAnimation];
if (!playingAnimations) {
return;
}
var animationTotalCount = playingAnimations.reduce(function (prev, cur) {
return prev + cur.tweenCount;
}, 0);
var animationPlayCount = animationTotalCount * _this2.playTimes;
_this2.__setAnimationClipCompleteTimes(_this2.playingAnimation);
_this2.displayObject.emit('onAnimationClipEnd', data);
if (_this2.useRelativePositionValue && property === 'position') {
target.x = initValue.x;
target.y = initValue.y;
} else {
target[property] = initValue;
}
var clipCompleteTimes = _this2.__getAnimationClipCompleteTimes(_this2.playingAnimation);
if (_this2.playTimes === Infinity) {
if (animationTotalCount === clipCompleteTimes) {
_this2.__setAnimationClipCompleteTimes(_this2.playingAnimation, 0);
var rafId = xRequestAnimationFrame(function () {
_this2.__playAnimation(_this2.playingAnimation);
xCancelAnimationFrame(rafId);
});
}
} else {
if (clipCompleteTimes % animationTotalCount === 0 && _this2.playTimes > _this2.chainAnimationCompleteTimes + 1) {
_this2.chainAnimationCompleteTimes++;
var _rafId = xRequestAnimationFrame(function () {
_this2.__playAnimation(_this2.playingAnimation);
xCancelAnimationFrame(_rafId);
});
}
if (clipCompleteTimes === animationPlayCount) {
_this2.playing = false;
_this2.__setAnimationClipCompleteTimes(_this2.playingAnimation, 0);
_this2.playTimes = 1;
_this2.chainAnimationCompleteTimes = 0;
if (_this2.animationFillMode === ANIMATION_FILL_MODE.BACKWARDS) {
Object.keys(displayObjectInitProperty).forEach(function (key) {
var _updateProperty = key.split('.');
_this2.__updateDisplayObjectProperty(_updateProperty, displayObjectInitProperty[key]);
});
}
_this2.displayObject.emit('onAnimationEnd', _this2.playingAnimation);
}
}
});
tweenCount++;
if (!prevItem) {
headTween = tween;
return headTween;
}
prevItem.chain(tween);
return tween;
}, null);
headTween.tweenCount = tweenCount;
return headTween;
});
});
}
}, {
key: '__getAnimationClipCompleteTimes',
value: function __getAnimationClipCompleteTimes(animationName) {
return this.playingAimationCompleteTimes[animationName];
}
}, {
key: '__setAnimationClipCompleteTimes',
value: function __setAnimationClipCompleteTimes(animationName, times) {
if (!isUndefined(times)) {
this.playingAimationCompleteTimes[animationName] = times;
return;
}
if (this.playingAimationCompleteTimes[animationName]) {
this.playingAimationCompleteTimes[animationName]++;
} else {
this.playingAimationCompleteTimes[animationName] = 1;
}
}
}, {
key: '__updateDisplayObjectProperty',
value: function __updateDisplayObjectProperty(updatePropertyList, value) {
var _updatePropertyList = slicedToArray(updatePropertyList, 2),
property0 = _updatePropertyList[0],
property1 = _updatePropertyList[1];
if (isUndefined(this.displayObject[property0])) {
console.warn('DisplayObject no ' + property0);
return;
}
if (property1) {
this.displayObject[property0][property1] = value;
return;
}
if (isObject(this.displayObject[property0]) && !isUndefined(this.displayObject[property0]['x']) && !isUndefined(this.displayObject[property0]['y'])) {
this.displayObject[property0]['x'] = isObject(value) ? value.x : value;
this.displayObject[property0]['y'] = isObject(value) ? value.y : value;
} else {
this.displayObject[property0] = value;
}
}
}, {
key: '__cacheDisplayObjectInitPropertyValue',
value: function __cacheDisplayObjectInitPropertyValue(_updateProperty, property, map) {
if (!isUndefined(map[property])) {
return;
}
if (_updateProperty.length > 1) {
map[property] = this.displayObject[_updateProperty[0]][_updateProperty[1]];
} else {
var value = this.displayObject[_updateProperty[0]];
map[property] = isObject(value) ? { x: value.x, y: value.y } : value;
}
return map;
}
}, {
key: '__parseAnimationConfig',
value: function __parseAnimationConfig(config) {
var _this3 = this;
var animationNames = Object.keys(config);
var tweenParams = {};
var tweenConfigs = {};
animationNames.forEach(function (animationName) {
var curAnimationConfig = config[animationName];
curAnimationConfig.forEach(function (animation) {
var property = animation.property,
_animation$easeFuncti = animation.easeFunction,
easeFunction = _animation$easeFuncti === undefined ? 'Linear.None' : _animation$easeFuncti,
duration = animation.duration,
clips = animation.clips;
clips.map(function (item) {
var percent = item.percent;
if (percent) {
item.percent = parsePercent(percent);
}
if (property === 'rotation') {
item.value = Tiny.deg2radian(item.value);
}
return item;
}).sort(function (a, b) {
if (!isUndefined(a.startTime) && !isUndefined(b.startTime)) {
return a.startTime - b.startTime;
}
return a.percent - b.percent;
}).forEach(function (clip, index) {
if (!clips[index + 1]) {
return;
}
var _duration = clips[index + 1].startTime - clip.startTime;
var targetValue = clip.value;
var toValue = clips[index + 1].value;
if (!isUndefined(clip.percent) && !isUndefined(clips[index + 1].percent)) {
_duration = clips[index + 1].percent * duration - clip.percent * duration;
}
if (!_duration) {
throw new Error('animation clips property startTime or percent is required!');
}
if (_this3.useRelativePositionValue && /position/.test(property)) {
var values = getParentRelativePosValue(_this3.displayObject, property, targetValue, toValue, index);
targetValue = values.targetValue;
toValue = values.toValue;
}
var target = defineProperty({}, property, targetValue);
var to = defineProperty({}, property, toValue);
if (property === 'position' && _this3.useRelativePositionValue) {
target = _extends({}, targetValue);
to = _extends({}, toValue);
}
var param = {
property: property,
target: target,
to: to,
duration: _duration,
easeFunction: clip.easeFunction || easeFunction,
delay: clip.delay || 0
};
if (tweenParams[property]) {
tweenParams[property].push(param);
} else {
tweenParams[property] = [param];
}
});
});
tweenConfigs[animationName] = tweenParams;
tweenParams = {};
});
return tweenConfigs;
}
}]);
return EasyAnimation;
}();
Tiny.DisplayObject.registerPlugin('easyAnimation', EasyAnimation);