@visactor/vrender-animate
Version:
This module provides a graph-based animation system for VRender.
390 lines (386 loc) • 25.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.AnimateExecutor = void 0;
const constant_1 = require("@visactor/vrender-core/event/constant"), vutils_1 = require("@visactor/vutils"), utils_1 = require("./utils"), static_truth_1 = require("../custom/static-truth");
class AnimateExecutor {
static registerBuiltInAnimate(name, animate) {
AnimateExecutor.builtInAnimateMap[name] = animate;
}
constructor(target) {
this._animates = [], this._startCallbacks = [], this._endCallbacks = [], this._started = !1,
this._activeCount = 0, this._activeConfigList = null, this._target = target;
}
get started() {
return this._started;
}
onStart(cb) {
cb ? (this._startCallbacks.push(cb), this._started && this._activeCount > 0 && cb()) : this._startCallbacks.forEach((cb => {
cb();
}));
}
onEnd(cb) {
cb ? this._endCallbacks.push(cb) : this._endCallbacks.forEach((cb => {
cb();
}));
}
getActiveAttrKeys() {
const keys = [];
for (let i = 0; i < this._animates.length; i++) {
const animate = this._animates[i];
if (animate.status === constant_1.AnimateStatus.END) continue;
const endProps = animate.getEndProps();
if (endProps) for (const key in endProps) Object.prototype.hasOwnProperty.call(endProps, key) && keys.indexOf(key) < 0 && keys.push(key);
}
return keys;
}
hasActiveAttrs() {
for (let i = 0; i < this._animates.length; i++) {
const animate = this._animates[i];
if (animate.status === constant_1.AnimateStatus.END) continue;
const endProps = animate.getEndProps();
if (endProps) for (const key in endProps) if (Object.prototype.hasOwnProperty.call(endProps, key)) return !0;
}
return !1;
}
preventAttrs(keys) {
if (!(null == keys ? void 0 : keys.length)) return this.hasActiveAttrs();
for (let i = 0; i < this._animates.length; i++) {
const animate = this._animates[i];
animate.status !== constant_1.AnimateStatus.END && animate.preventAttrs(keys);
}
return this.hasActiveAttrs();
}
_trackAnimation(animate) {
this._animates.push(animate), this._activeCount++, 1 !== this._activeCount || this._started || (this._started = !0,
this.onStart()), animate.onEnd((() => {
this._activeCount--;
const index = this._animates.indexOf(animate);
index >= 0 && this._animates.splice(index, 1), 0 === this._activeCount && this._started && (this._started = !1,
this.onEnd());
}));
}
parseParams(params, isTimeline, child) {
var _a, _b;
const totalTime = this.resolveValue(params.totalTime, child, void 0), startTime = this.resolveValue(params.startTime, child, 0), parsedParams = Object.assign({}, params);
parsedParams.oneByOneDelay = 0, parsedParams.startTime = startTime, parsedParams.totalTime = totalTime;
const oneByOne = this.resolveValue(params.oneByOne, child, !1);
if (isTimeline) {
const timeSlices = parsedParams.timeSlices;
(0, vutils_1.isArray)(timeSlices) || (parsedParams.timeSlices = [ timeSlices ]);
let sliceTime = 0;
parsedParams.timeSlices = parsedParams.timeSlices.map((slice => {
const delay = this.resolveValue(slice.delay, child, 0), delayAfter = this.resolveValue(slice.delayAfter, child, 0), duration = this.resolveValue(slice.duration, child, 300);
return sliceTime += delay + duration + delayAfter, Object.assign(Object.assign({}, slice), {
delay: delay,
delayAfter: delayAfter,
duration: duration
});
}));
let oneByOneDelay = 0;
oneByOne && (oneByOneDelay = "number" == typeof oneByOne ? oneByOne : oneByOne ? sliceTime : 0),
parsedParams.oneByOneDelay = oneByOneDelay;
let scale = 1;
if (totalTime) {
const _totalTime = sliceTime + oneByOneDelay * (this._target.count - 2);
scale = totalTime ? totalTime / _totalTime : 1;
}
parsedParams.timeSlices = parsedParams.timeSlices.map((slice => {
let effects = slice.effects;
return Array.isArray(effects) || (effects = [ effects ]), Object.assign(Object.assign({}, slice), {
delay: slice.delay * scale,
delayAfter: slice.delayAfter * scale,
duration: slice.duration * scale,
effects: effects.map((effect => {
var _a, _b;
const custom = null !== (_a = effect.custom) && void 0 !== _a ? _a : AnimateExecutor.builtInAnimateMap[null !== (_b = effect.type) && void 0 !== _b ? _b : "fromTo"], customType = (0,
utils_1.getCustomType)(custom);
return Object.assign(Object.assign({}, effect), {
custom: custom,
customType: customType
});
}))
});
})), parsedParams.oneByOneDelay = oneByOneDelay * scale, parsedParams.startTime = startTime * scale;
} else {
const delay = this.resolveValue(params.delay, child, 0), delayAfter = this.resolveValue(params.delayAfter, child, 0), duration = this.resolveValue(params.duration, child, 300);
let oneByOneDelay = 0;
oneByOne && (oneByOneDelay = "number" == typeof oneByOne ? oneByOne : oneByOne ? delay + delayAfter + duration : 0),
parsedParams.oneByOneDelay = oneByOneDelay, parsedParams.custom = null !== (_a = params.custom) && void 0 !== _a ? _a : AnimateExecutor.builtInAnimateMap[null !== (_b = params.type) && void 0 !== _b ? _b : "fromTo"];
const customType = (0, utils_1.getCustomType)(parsedParams.custom);
parsedParams.customType = customType;
const _totalTime = delay + delayAfter + duration + oneByOneDelay * (this._target.count - 2), scale = (0,
vutils_1.isValidNumber)(totalTime) ? totalTime / _totalTime : 1;
parsedParams.delay = delay * scale, parsedParams.delayAfter = delayAfter * scale,
parsedParams.duration = duration * scale, parsedParams.oneByOneDelay = oneByOneDelay * scale,
parsedParams.startTime = startTime;
}
return parsedParams;
}
execute(params) {
if (Array.isArray(params)) {
const prevConfigList = this._activeConfigList;
this._activeConfigList = params;
try {
params.forEach((param => this._execute(param)));
} finally {
this._activeConfigList = prevConfigList;
}
} else this._execute(params);
}
_execute(params) {
if (params.selfOnly) return this._executeItem(params, this._target, 0, 1);
const isTimeline = "timeSlices" in params;
let filteredChildren;
isTimeline && params.partitioner && (filteredChildren = (null != filteredChildren ? filteredChildren : this._target.getChildren()).filter((child => {
var _a, _b;
return params.partitioner(null === (_b = null === (_a = child.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], child, {});
}))), isTimeline && params.sort && (filteredChildren = null != filteredChildren ? filteredChildren : this._target.getChildren(),
filteredChildren.sort(((a, b) => {
var _a, _b, _c, _d;
return params.sort(null === (_b = null === (_a = a.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], null === (_d = null === (_c = b.context) || void 0 === _c ? void 0 : _c.data) || void 0 === _d ? void 0 : _d[0], a, b, {});
})));
const cb = isTimeline ? (child, index, count) => {
const parsedParams = this.parseParams(params, isTimeline, child), animate = this.executeTimelineItem(parsedParams, child, index, count);
animate && this._trackAnimation(animate);
} : (child, index, count) => {
const parsedParams = this.parseParams(params, isTimeline, child), animate = this.executeTypeConfigItem(parsedParams, child, index, count);
animate && this._trackAnimation(animate);
};
filteredChildren ? filteredChildren.forEach(((child, index) => cb(child, index, filteredChildren.length))) : this._target.count <= 1 ? cb(this._target, 0, 1) : this._target.forEachChildren(((child, index) => cb(child, index, this._target.count - 1)));
}
executeTypeConfigItem(params, graphic, index, count) {
var _a, _b, _c, _d, _e, _f, _g, _h;
this.syncFinalAttrsFromContext(graphic);
const {type: type = "fromTo", channel: channel, customParameters: customParameters, easing: easing = "linear", delay: delay = 0, delayAfter: delayAfter = 0, duration: duration = 300, startTime: startTime = 0, oneByOneDelay: oneByOneDelay = 0, loop: loop, bounce: bounce, priority: priority = 0, options: options, custom: custom, customType: customType, controlOptions: controlOptions} = params, animate = graphic.animate();
animate.priority = priority;
const delayValue = (0, vutils_1.isFunction)(delay) ? delay(null === (_b = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], graphic, {}) : delay, datum = null === (_d = null === (_c = graphic.context) || void 0 === _c ? void 0 : _c.data) || void 0 === _d ? void 0 : _d[0], indexKey = null === (_e = graphic.context) || void 0 === _e ? void 0 : _e.indexKey;
datum && indexKey && (index = null !== (_f = datum[indexKey]) && void 0 !== _f ? _f : index),
animate.startAt(startTime);
const wait = index * oneByOneDelay + delayValue;
wait > 0 && animate.wait(wait);
let parsedFromProps = null, props = params.to, from = params.from;
const commitAttrOutChannel = this.shouldCommitAttrOutChannel(type);
props || (parsedFromProps || (parsedFromProps = this.createPropsFromChannel(channel, graphic, commitAttrOutChannel, this.getAttrOutChannelExcludedKeys(graphic))),
props = parsedFromProps.props), from || (parsedFromProps || (parsedFromProps = this.createPropsFromChannel(channel, graphic, commitAttrOutChannel, this.getAttrOutChannelExcludedKeys(graphic))),
from = parsedFromProps.from), parsedFromProps.attrOutChannel && graphic.setAttributes(parsedFromProps.attrOutChannel),
this._handleRunAnimate(animate, custom, customType, from, props, duration, easing, customParameters, controlOptions, options, type, graphic),
this.commitAnimatedUpdateDiffAttrsOnEnd(animate, graphic, type, props);
let totalDelay = 0;
oneByOneDelay && (totalDelay = oneByOneDelay * (count - index - 1));
const delayAfterValue = (0, vutils_1.isFunction)(delayAfter) ? delayAfter(null === (_h = null === (_g = graphic.context) || void 0 === _g ? void 0 : _g.data) || void 0 === _h ? void 0 : _h[0], graphic, {}) : delayAfter;
return delayAfterValue > 0 && (totalDelay += delayAfterValue), totalDelay > 0 && animate.wait(totalDelay),
loop && loop > 0 && animate.loop(loop), bounce && animate.bounce(!0), animate;
}
_handleRunAnimate(animate, custom, customType, from, props, duration, easing, customParameters, controlOptions, options, type, graphic) {
var _a, _b, _c, _d, _e, _f, _g, _h;
if (custom && customType) {
customType = (0, utils_1.getCustomType)(custom);
let customParams = this.resolveValue(customParameters, graphic);
"function" == typeof customParams && (customParams = customParams(null === (_b = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], graphic, {})),
customParams = Object.assign({
width: (null === (_c = graphic.stage) || void 0 === _c ? void 0 : _c.width) || 0,
height: (null === (_d = graphic.stage) || void 0 === _d ? void 0 : _d.height) || 0,
group: this._target.parent
}, customParams);
const objOptions = (0, vutils_1.isFunction)(options) ? options.call(null, null !== (_f = customParams && (null === (_e = customParams.data) || void 0 === _e ? void 0 : _e[0])) && void 0 !== _f ? _f : null === (_h = null === (_g = graphic.context) || void 0 === _g ? void 0 : _g.data) || void 0 === _h ? void 0 : _h[0], graphic, customParams) : options;
customParams.options = objOptions, customParams.controlOptions = controlOptions,
1 === customType ? this.createCustomAnimation(animate, custom, from, props, duration, easing, customParams) : 2 === customType && this.createCustomInterpolatorAnimation(animate, custom, props, duration, easing, customParams);
} else "to" === type ? animate.to(props, duration, easing) : "from" === type && animate.from(props, duration, easing);
}
executeTimelineItem(params, graphic, index, count) {
var _a, _b, _c, _d;
this.syncFinalAttrsFromContext(graphic);
const {timeSlices: timeSlices, startTime: startTime = 0, loop: loop, bounce: bounce, oneByOneDelay: oneByOneDelay, priority: priority, controlOptions: controlOptions} = params, datum = null === (_b = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], indexKey = null === (_c = graphic.context) || void 0 === _c ? void 0 : _c.indexKey;
datum && indexKey && (index = null !== (_d = datum[indexKey]) && void 0 !== _d ? _d : index);
const animate = graphic.animate();
animate.priority = priority, animate.startAt(startTime), animate.wait(index * oneByOneDelay),
loop && loop > 0 && animate.loop(loop), bounce && animate.bounce(!0);
return (Array.isArray(timeSlices) ? timeSlices : [ timeSlices ]).forEach((slice => {
this.applyTimeSliceToAnimate(slice, animate, graphic, controlOptions);
})), oneByOneDelay && animate.wait(oneByOneDelay * (count - index - 1)), animate;
}
applyTimeSliceToAnimate(slice, animate, graphic, controlOptions) {
var _a, _b, _c, _d;
const {effects: effects, duration: duration = 300, delay: delay = 0, delayAfter: delayAfter = 0} = slice, delayValue = (0,
vutils_1.isFunction)(delay) ? delay(null === (_b = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], graphic, {}) : delay, delayAfterValue = (0,
vutils_1.isFunction)(delayAfter) ? delayAfter(null === (_d = null === (_c = graphic.context) || void 0 === _c ? void 0 : _c.data) || void 0 === _d ? void 0 : _d[0], graphic, {}) : delayAfter;
delayValue > 0 && animate.wait(delayValue);
(Array.isArray(effects) ? effects : [ effects ]).forEach((effect => {
var _a;
const {type: type = "fromTo", channel: channel, customParameters: customParameters, easing: easing = "linear", options: options} = effect;
let parsedFromProps = null, props = effect.to, from = effect.from;
const commitAttrOutChannel = this.shouldCommitAttrOutChannel(type);
props || (parsedFromProps || (parsedFromProps = this.createPropsFromChannel(channel, graphic, commitAttrOutChannel, this.getAttrOutChannelExcludedKeys(graphic))),
props = parsedFromProps.props), from || (parsedFromProps || (parsedFromProps = this.createPropsFromChannel(channel, graphic, commitAttrOutChannel, this.getAttrOutChannelExcludedKeys(graphic))),
from = parsedFromProps.from), parsedFromProps.attrOutChannel && graphic.setAttributes(parsedFromProps.attrOutChannel);
const custom = null !== (_a = effect.custom) && void 0 !== _a ? _a : AnimateExecutor.builtInAnimateMap[type], customType = effect.custom ? effect.customType : (0,
utils_1.getCustomType)(custom);
this._handleRunAnimate(animate, custom, customType, from, props, duration, easing, customParameters, controlOptions, options, type, graphic);
})), delayAfterValue > 0 && animate.wait(delayAfterValue);
}
createCustomInterpolatorAnimation(animate, interpolator, props, duration, easing, customParams) {
const from = {}, to = props;
Object.keys(to).forEach((key => {
from[key] = animate.target.getComputedAttribute(key);
})), animate.interpolateUpdateFunction = (from, to, ratio, step, target) => {
interpolator(ratio, from, to, step, target, animate.target, customParams);
}, animate.to(props, duration, easing);
}
shouldCommitAttrOutChannel(type) {
return "update" !== type;
}
commitAnimatedUpdateDiffAttrsOnEnd(animate, graphic, type, props) {
if ("update" === type || !props || !this.isUpdateDiffContext(graphic)) return;
const keys = this.collectAnimatedUpdateDiffAttrKeys(graphic, props);
(null == keys ? void 0 : keys.length) && animate.onEnd((() => {
(0, static_truth_1.commitAnimationStaticAttrs)(graphic, keys, animate, props);
}));
}
isUpdateDiffContext(graphic) {
const context = graphic.context;
return "update" === (null == context ? void 0 : context.diffState) || "update" === (null == context ? void 0 : context.animationState);
}
collectAnimatedUpdateDiffAttrKeys(graphic, props) {
var _a;
const diffAttrs = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.diffAttrs;
if (!diffAttrs) return null;
let keys = null;
for (const key in props) Object.prototype.hasOwnProperty.call(props, key) && Object.prototype.hasOwnProperty.call(diffAttrs, key) && void 0 !== diffAttrs[key] && (null != keys || (keys = []),
keys.push(key));
return keys;
}
createCustomAnimation(animate, CustomAnimateConstructor, from, props, duration, easing, customParams) {
const customAnimate = new CustomAnimateConstructor(from, props, duration, easing, customParams);
animate.play(customAnimate);
}
createPropsFromChannel(channel, graphic, includeAttrOutChannel = !0, excludedAttrOutKeys) {
var _a;
const props = {};
let from = null;
if (!channel) return {
from: from,
props: props,
attrOutChannel: null
};
const attrOutChannel = includeAttrOutChannel ? {} : null;
let hasAttrs = !1;
const diffAttrs = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.diffAttrs;
if (Array.isArray(channel) && (channel = channel.reduce(((res, key) => (void 0 === diffAttrs[key] || (res[key] = {
to: diffAttrs[key]
}), res)), {})), Object.keys(channel).forEach((key => {
var _a, _b, _c, _d;
const config = channel[key];
void 0 !== config.to && ("function" == typeof config.to ? props[key] = config.to(null === (_b = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], graphic, {}) : props[key] = config.to),
void 0 !== config.from && (from || (from = {}), "function" == typeof config.from ? from[key] = config.from(null === (_d = null === (_c = graphic.context) || void 0 === _c ? void 0 : _c.data) || void 0 === _d ? void 0 : _d[0], graphic, {}) : from[key] = config.from);
})), diffAttrs && attrOutChannel) for (const key in diffAttrs) {
const value = diffAttrs[key];
if (void 0 === value) continue;
props.hasOwnProperty(key) || !!(null == from ? void 0 : from.hasOwnProperty(key)) || (null == excludedAttrOutKeys ? void 0 : excludedAttrOutKeys[key]) || (attrOutChannel[key] = value,
hasAttrs = !0);
}
return {
from: from,
props: props,
attrOutChannel: hasAttrs ? attrOutChannel : null
};
}
resolveValue(value, graphic, defaultValue) {
var _a, _b;
return void 0 === value ? defaultValue : "function" == typeof value && graphic ? value(null === (_b = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.data) || void 0 === _b ? void 0 : _b[0], graphic, {}) : value;
}
getAttrOutChannelExcludedKeys(graphic) {
var _a;
const configList = this._activeConfigList, diffAttrs = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.diffAttrs;
if (!configList || configList.length <= 1 || !diffAttrs) return null;
let excludedKeys = null;
for (let i = 0; i < configList.length; i++) excludedKeys = this.collectAnimatedDiffKeys(configList[i], graphic, diffAttrs, excludedKeys);
return excludedKeys;
}
collectAnimatedDiffKeys(config, graphic, diffAttrs, keys) {
if ("timeSlices" in config) {
const slices = Array.isArray(config.timeSlices) ? config.timeSlices : [ config.timeSlices ];
for (let i = 0; i < slices.length; i++) {
const effects = Array.isArray(slices[i].effects) ? slices[i].effects : [ slices[i].effects ];
for (let j = 0; j < effects.length; j++) keys = this.collectAnimatedDiffKeysFromEffect(effects[j], graphic, diffAttrs, keys);
}
return keys;
}
return this.collectAnimatedDiffKeysFromEffect(config, graphic, diffAttrs, keys);
}
collectAnimatedDiffKeysFromEffect(effect, graphic, diffAttrs, keys) {
var _a;
if ("update" === (null !== (_a = effect.type) && void 0 !== _a ? _a : "fromTo")) {
const options = this.resolveValue(effect.options, graphic, void 0), excludeChannels = null == options ? void 0 : options.excludeChannels;
for (const key in diffAttrs) Object.prototype.hasOwnProperty.call(diffAttrs, key) && void 0 !== diffAttrs[key] && !this.includesChannel(excludeChannels, key) && (null != keys || (keys = {}),
keys[key] = !0);
return keys;
}
return keys = this.collectExplicitAnimatedKeys(effect.to, diffAttrs, keys), keys = this.collectExplicitAnimatedKeys(effect.from, diffAttrs, keys),
this.collectChannelAnimatedKeys(effect.channel, diffAttrs, keys);
}
collectExplicitAnimatedKeys(attrs, diffAttrs, keys) {
if (!attrs) return keys;
for (const key in attrs) Object.prototype.hasOwnProperty.call(attrs, key) && Object.prototype.hasOwnProperty.call(diffAttrs, key) && void 0 !== diffAttrs[key] && (null != keys || (keys = {}),
keys[key] = !0);
return keys;
}
collectChannelAnimatedKeys(channel, diffAttrs, keys) {
if (!channel) return keys;
if (Array.isArray(channel)) {
for (let i = 0; i < channel.length; i++) {
const key = channel[i];
Object.prototype.hasOwnProperty.call(diffAttrs, key) && void 0 !== diffAttrs[key] && (null != keys || (keys = {}),
keys[key] = !0);
}
return keys;
}
for (const key in channel) if (Object.prototype.hasOwnProperty.call(channel, key) && Object.prototype.hasOwnProperty.call(diffAttrs, key) && void 0 !== diffAttrs[key]) {
const config = channel[key];
void 0 === config.to && void 0 === config.from || (null != keys || (keys = {}),
keys[key] = !0);
}
return keys;
}
includesChannel(channels, key) {
if (!(null == channels ? void 0 : channels.length)) return !1;
for (let i = 0; i < channels.length; i++) if (channels[i] === key) return !0;
return !1;
}
syncFinalAttrsFromContext(graphic) {
var _a;
const finalAttrs = null === (_a = graphic.context) || void 0 === _a ? void 0 : _a.finalAttrs;
finalAttrs && graphic.setFinalAttributes(finalAttrs);
}
executeItem(params, graphic, index = 0, count = 1) {
if (Array.isArray(params)) {
const prevConfigList = this._activeConfigList;
this._activeConfigList = params;
try {
return params.map((param => this._executeItem(param, graphic, index, count))).filter(Boolean);
} finally {
this._activeConfigList = prevConfigList;
}
}
return [ this._executeItem(params, graphic, index, count) ].filter(Boolean);
}
_executeItem(params, graphic, index = 0, count = 1) {
if (!graphic) return null;
const isTimeline = "timeSlices" in params;
let animate = null;
const parsedParams = this.parseParams(params, isTimeline);
return animate = isTimeline ? this.executeTimelineItem(parsedParams, graphic, index, count) : this.executeTypeConfigItem(parsedParams, graphic, index, count),
animate && this._trackAnimation(animate), animate;
}
stop(type, callEnd = !0) {
for (;this._animates.length > 0; ) {
const animate = this._animates.pop();
!1 === callEnd && (animate.status = constant_1.AnimateStatus.END, animate.__skipRestoreStaticAttributeOnRemove = !0),
null == animate || animate.stop(type);
}
this._animates = [], this._activeCount = 0, this._started && (this._started = !1,
callEnd && this.onEnd());
}
}
exports.AnimateExecutor = AnimateExecutor, AnimateExecutor.builtInAnimateMap = {};
//# sourceMappingURL=animate-executor.js.map