rc-tween-one
Version:
tween-one anim component for react
430 lines (399 loc) • 15.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _styleUtils = require('style-utils');
var _easing = require('./easing');
var _easing2 = _interopRequireDefault(_easing);
var _plugins = require('./plugins');
var _plugins2 = _interopRequireDefault(_plugins);
var _StylePlugin = require('./plugin/StylePlugin');
var _StylePlugin2 = _interopRequireDefault(_StylePlugin);
var _util = require('./util.js');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
var DEFAULT_EASING = 'easeInOutQuad'; /* eslint-disable func-names */
/**
* Created by jljsj on 16/1/27.
*/
var DEFAULT_DURATION = 450;
var DEFAULT_DELAY = 0;
function noop() {}
_plugins2['default'].push(_StylePlugin2['default']);
// 设置默认数据
function defaultData(vars, now) {
var duration = vars.duration || vars.duration === 0 ? vars.duration : DEFAULT_DURATION;
return {
duration: vars.type === 'set' ? 0 : duration,
delay: vars.delay || DEFAULT_DELAY,
ease: typeof vars.ease === 'function' ? vars.ease : _easing2['default'][vars.ease || DEFAULT_EASING],
onUpdate: vars.onUpdate || noop,
onComplete: vars.onComplete || noop,
onStart: vars.onStart || noop,
onRepeat: vars.onRepeat || noop,
repeat: vars.repeat || 0,
repeatDelay: vars.repeatDelay || 0,
yoyo: vars.yoyo || false,
type: vars.type === 'from' ? 'from' : 'to',
initTime: now,
appearTo: typeof vars.appearTo === 'number' ? vars.appearTo : null,
perTime: 0,
currentRepeat: 0
};
}
var Tween = function Tween(target, toData, props) {
this.target = target;
this.attr = props.attr || 'style';
// 时间精度补齐;
this.accuracy = 0.00001;
// 记录总时间;
this.totalTime = 0;
// 记录当前时间;
this.progressTime = 0;
// 记录时间轴数据;
this.defaultData = [];
// 每个的开始数据;
this.start = {};
// 开始默认的数据;
this.startDefaultData = {};
// 动画过程
this.tween = {};
// toData;
this.data = toData;
// 每帧的时间;
this.perFrame = Math.round(1000 / 60);
// 注册,第一次进入执行注册
this.register = false;
// svg元素
this.isSvg = this.target.ownerSVGElement;
// 设置 style
var data = this.setAttrIsStyle();
// 设置默认动画数据;
this.setDefaultData(data);
};
var p = Tween.prototype;
p.setAttrIsStyle = function () {
var _this = this;
var data = [];
this.data.forEach(function (d, i) {
var _d = (0, _extends3['default'])({}, d);
if (_this.attr === 'style') {
data[i] = {};
Object.keys(_d).forEach(function (key) {
if (key in defaultData({}, 0)) {
data[i][key] = _d[key];
delete _d[key];
}
});
data[i].style = _d;
_this.startDefaultData.style = _this.target.getAttribute('style');
} else if (_this.attr === 'attr') {
Object.keys(_d).forEach(function (key) {
if (key === 'style' && Array.isArray(d[key])) {
throw new Error('Style should be the object.');
}
if (key === 'bezier') {
_d.style = (0, _extends3['default'])({}, _d.style, { bezier: _d[key] });
delete _d[key];
_this.startDefaultData.style = _this.target.getAttribute('style');
} else {
_this.startDefaultData[key] = _this.target.getAttribute(key);
}
});
data[i] = _d;
}
});
return data;
};
p.setDefaultData = function (_vars) {
var _this2 = this;
var now = 0;
var repeatMax = false;
var data = _vars.map(function (item) {
var appearToBool = typeof item.appearTo === 'number';
// 加上延时,在没有播放过时;
if (!appearToBool) {
now += item.delay || 0;
}
var appearToTime = (item.appearTo || 0) + (item.delay || 0);
// 获取默认数据
var tweenData = defaultData(item, appearToBool ? appearToTime : now);
tweenData.vars = {};
Object.keys(item).forEach(function (_key) {
if (!(_key in tweenData)) {
var _data = item[_key];
if (_key in _plugins2['default']) {
tweenData.vars[_key] = new _plugins2['default'][_key](_this2.target, _data, tweenData.type);
} else if (_key.match(/color/i) || _key === 'stroke' || _key === 'fill') {
tweenData.vars[_key] = { type: 'color', vars: (0, _styleUtils.parseColor)(_data) };
} else if (typeof _data === 'number' || _data.split(/[,|\s]/g).length <= 1) {
var vars = parseFloat(_data);
var unit = _data.toString().replace(/[^a-z|%]/g, '');
var count = _data.toString().replace(/[^+|=|-]/g, '');
tweenData.vars[_key] = { unit: unit, vars: vars, count: count };
} else if ((_key === 'd' || _key === 'points') && 'SVGMorph' in _plugins2['default']) {
tweenData.vars[_key] = new _plugins2['default'].SVGMorph(_this2.target, _data, _key);
}
}
});
if (tweenData.yoyo && !tweenData.repeat) {
console.warn('Warning: yoyo must be used together with repeat;'); // eslint-disable-line
}
if (tweenData.repeat === -1) {
repeatMax = true;
}
var repeat = tweenData.repeat === -1 ? 0 : tweenData.repeat;
if (appearToBool) {
// 如果有 appearTo 且这条时间比 now 大时,,总时间用这条;
var appearNow = item.appearTo + (item.delay || 0) + tweenData.duration * (repeat + 1) + tweenData.repeatDelay * repeat;
now = appearNow >= now ? appearNow : now;
} else if (tweenData.delay < -tweenData.duration) {
// 如果延时小于 负时间时,,不加,再减回延时;
now -= tweenData.delay;
} else {
// repeat 为 -1 只记录一次。不能跟 reverse 同时使用;
now += tweenData.duration * (repeat + 1) + tweenData.repeatDelay * repeat;
}
tweenData.mode = '';
return tweenData;
});
this.totalTime = repeatMax ? Number.MAX_VALUE : now;
this.defaultData = data;
};
p.getComputedStyle = function () {
var style = typeof window !== 'undefined' && document.defaultView ? document.defaultView.getComputedStyle(this.target) : {};
// 如果是 SVG, 样式全部提出为 transformSVG, 兼容 safari 不能获取 transform;
if (this.isSvg) {
var transform = style[(0, _styleUtils.checkStyleName)('transform')] || 'none';
if (transform === 'none') {
var attrStyle = this.target.getAttribute('style');
if (attrStyle && attrStyle.indexOf('transform:') >= 0) {
transform = attrStyle.split(';').filter(function (k) {
return k.indexOf('transform:') >= 0;
}).map(function (item) {
return (0, _styleUtils.createMatrix)(item.split(':')[1].trim()).toString();
})[0];
} else if (this.target.getAttribute('transform')) {
// 暂时不支持标签上的 transform,后期增加;
console.warn('Do not add transform on the label, otherwise it will be invalid.'); // eslint-disable-line no-console
}
}
style.transformSVG = transform;
}
return style;
};
p.getAnimStartData = function (item) {
var _this3 = this;
var start = {};
Object.keys(item).forEach(function (_key) {
if (_key in _plugins2['default'] || _this3.attr === 'attr' && (_key === 'd' || _key === 'points')) {
_this3.computedStyle = _this3.computedStyle || _this3.getComputedStyle();
start[_key] = item[_key].getAnimStart(_this3.computedStyle, _this3.tween, _this3.isSvg);
return;
}
if (_this3.attr === 'attr') {
// 除了d和这points外的标签动画;
var attribute = _this3.target.getAttribute(_key);
var data = attribute === 'null' || !attribute ? 0 : attribute;
if (_key.match(/color/i) || _key === 'stroke' || _key === 'fill') {
data = !data && _key === 'stroke' ? 'rgba(255, 255, 255, 0)' : data;
data = (0, _styleUtils.parseColor)(data);
start[_key] = data;
} else if (parseFloat(data) || parseFloat(data) === 0 || data === 0) {
var unit = data.toString().replace(/[^a-z|%]/g, '');
start[_key] = unit !== item[_key].unit ? (0, _util.startConvertToEndUnit)(_this3.target, _key, parseFloat(data), unit, item[_key].unit) : parseFloat(data);
}
return;
}
start[_key] = _this3.target[_key] || 0;
});
return start;
};
p.setAnimData = function (data) {
var _this4 = this;
Object.keys(data).forEach(function (key) {
if (key in _plugins2['default'] || _this4.attr === 'attr' && (key === 'd' || key === 'points')) {
return;
}
_this4.target[key] = data[key];
});
};
p.setRatio = function (ratio, endData, i) {
var _this5 = this;
Object.keys(endData.vars).forEach(function (_key) {
if (_key in _plugins2['default'] || _this5.attr === 'attr' && (_key === 'd' || _key === 'points')) {
endData.vars[_key].setRatio(ratio, _this5.tween, _this5.isSvg && _this5.computedStyle);
return;
}
var endVars = endData.vars[_key];
var startVars = _this5.start[i][_key];
var data = void 0;
if (_this5.attr === 'attr') {
// 除了d和这points外的标签动画;
if (!endVars.type) {
data = endVars.unit.charAt(1) === '=' ? startVars + endVars.vars * ratio + endVars.unit : (endVars.vars - startVars) * ratio + startVars + endVars.unit;
_this5.target.setAttribute(_key, data);
} else if (endVars.type === 'color') {
if (endVars.vars.length === 3 && startVars.length === 4) {
endVars.vars[3] = 1;
}
data = endVars.vars.map(function (_endData, _i) {
var startData = startVars[_i] || 0;
return (_endData - startData) * ratio + startData;
});
_this5.target.setAttribute(_key, (0, _styleUtils.getColor)(data));
}
}
});
this.setAnimData(this.tween);
};
p.render = function () {
var _this6 = this;
var reverse = this.reverse;
this.defaultData.forEach(function (item, i) {
var initTime = item.initTime;
var duration = (0, _styleUtils.toFixed)(item.duration);
// 处理 yoyo 和 repeat; yoyo 是在时间轴上的, 并不是倒放
var repeatNum = Math.ceil((_this6.progressTime - initTime) / (duration + item.repeatDelay)) - 1 || 0;
repeatNum = repeatNum < 0 ? 0 : repeatNum;
if (item.repeat) {
if (item.repeat < repeatNum && item.repeat !== -1) {
return;
}
if (item.repeat || item.repeat <= repeatNum) {
initTime += repeatNum * (duration + item.repeatDelay);
}
}
var startData = item.yoyo && repeatNum % 2 ? 1 : 0;
var endData = item.yoyo && repeatNum % 2 ? 0 : 1;
startData = item.type === 'from' ? 1 - startData : startData;
endData = item.type === 'from' ? 1 - endData : endData;
// 精度损失,只取小数点后10位。
var progressTime = (0, _styleUtils.toFixed)(_this6.progressTime - initTime);
var ratio = void 0;
// 开始注册;
// from 时需先执行参数位置;
var fromDelay = item.type === 'from' ? item.delay : 0;
if (progressTime + fromDelay >= 0) {
if (!_this6.start[i]) {
// 设置 start
_this6.start[i] = _this6.getAnimStartData(item.vars);
if (progressTime < _this6.perFrame) {
ratio = !item.duration && !item.delay ? item.ease(1, startData, endData, 1) : item.ease(0, startData, endData, 1);
_this6.setRatio(ratio, item, i);
} else if (progressTime > duration) {
ratio = item.ease(1, startData, endData, 1);
_this6.setRatio(ratio, item, i);
}
if (!_this6.register || i && !initTime) {
_this6.register = true;
if (progressTime === 0 && item.duration) {
return;
}
}
}
}
var e = {
index: i,
target: _this6.target
};
var cb = (0, _extends3['default'])({
moment: _this6.progressTime
}, e);
if (progressTime >= (item.delay && reverse ? -_this6.perFrame + _this6.accuracy : 0) && !(progressTime > duration && item.mode === 'onComplete') && _this6.start[i]) {
var updateAnim = _this6.updateAnim === 'update';
progressTime = progressTime < _this6.perFrame - _this6.accuracy && !reverse ? 0 : progressTime;
if ((progressTime >= duration - _this6.accuracy && !reverse || reverse && progressTime <= 0) && repeatNum >= item.repeat) {
// onReveresComplete 和 onComplete 统一用 onComplete;
ratio = item.ease(reverse ? 0 : 1, startData, endData, 1);
_this6.setRatio(ratio, item, i, item.currentRepeat !== repeatNum);
if (!item.reset && !updateAnim) {
// duration 为 0 时的一个回调;
if (!duration) {
item.onStart(e);
cb.mode = 'onStart';
_this6.onChange(cb);
item.onUpdate((0, _extends3['default'])({ ratio: ratio }, e));
cb.mode = 'onUpdate';
_this6.onChange(cb);
}
item.onComplete(e);
} else if (progressTime >= duration + _this6.perFrame - _this6.accuracy) {
return;
}
item.mode = 'onComplete';
} else if (duration) {
var currentProgress = progressTime < 0 ? 0 : progressTime;
currentProgress = currentProgress > duration ? duration : currentProgress;
ratio = item.ease(currentProgress, startData, endData, duration);
_this6.setRatio(ratio, item, i);
if (!updateAnim) {
if (item.repeat && repeatNum > 0 && item.currentRepeat !== repeatNum) {
item.mode = 'onRepeat';
item.currentRepeat = repeatNum;
item.onRepeat((0, _extends3['default'])({}, e, { repeatNum: repeatNum }));
} else if ((typeof item.perTime !== 'number' || progressTime === 0 || reverse && item.perTime >= _this6.reverseStartTime - initTime) && item.mode !== 'onStart') {
// onReveresStart 和 onStart 统一用 onStart;
item.mode = 'onStart';
item.onStart(e);
} else {
item.mode = 'onUpdate';
item.onUpdate((0, _extends3['default'])({ ratio: ratio }, e));
}
}
}
if (!updateAnim) {
cb.mode = item.mode;
_this6.onChange(cb);
}
item.perTime = progressTime;
if (item.reset) {
delete item.reset;
}
}
});
};
// 播放帧
p.frame = function (moment) {
var _this7 = this;
this.progressTime = moment;
this.defaultData.forEach(function (item) {
var t = _this7.progressTime - item.duration - item.initTime;
if (t < _this7.perFrame && t > 0) {
_this7.progressTime = item.duration + item.initTime;
}
});
this.render();
};
p.resetAnimData = function () {
this.tween = {};
this.start = {};
};
p.resetDefaultStyle = function () {
var _this8 = this;
this.tween = {};
this.defaultData = this.defaultData.map(function (item) {
item.reset = true;
delete item.mode;
return item;
});
Object.keys(this.startDefaultData).forEach(function (key) {
if (!(key in defaultData({}, 0))) {
_this8.target.setAttribute(key, _this8.startDefaultData[key]);
}
});
};
p.reStart = function (style) {
var _this9 = this;
this.start = {};
this.target.style.cssText = '';
Object.keys(style || {}).forEach(function (key) {
_this9.target.style[key] = (0, _styleUtils.stylesToCss)(key, style[key]);
});
this.setAttrIsStyle();
this.resetDefaultStyle();
};
p.onChange = noop;
exports['default'] = Tween;
module.exports = exports['default'];