@visactor/vrender-animate
Version:
This module provides a graph-based animation system for VRender.
182 lines (172 loc) • 8.3 kB
JavaScript
import { ColorStore, ColorType } from "@visactor/vrender-core/color-string";
import { Generator } from "@visactor/vrender-core/common/generator";
import { AttributeUpdateType } from "@visactor/vrender-core/event/constant";
import { Easing } from "./utils/easing";
import { commonInterpolateUpdate, interpolateUpdateStore } from "./interpolate/store";
import { isString } from "@visactor/vutils";
import { applyAnimationTransientAttributes } from "./custom/transient";
function noop() {}
function includesKey(keys, key) {
for (let i = 0; i < keys.length; i++) if (keys[i] === key) return !0;
return !1;
}
export class Step {
constructor(type, props, duration, easing) {
var _a;
this._startTime = 0, this._hasFirstRun = !1, this._syncAttributeUpdate = () => {
this.target.addUpdateShapeAndBoundsTag(), this.target.addUpdatePositionTag(), this.target.onAttributeUpdate({
type: AttributeUpdateType.ANIMATE_UPDATE
});
}, this.type = type, this.props = props, this.duration = duration, this.easing = easing ? "function" == typeof easing ? easing : null !== (_a = Easing[easing]) && void 0 !== _a ? _a : Easing.linear : Easing.linear,
"wait" === type && (this.onUpdate = noop), this.id = Generator.GenAutoIncrementId(),
this.syncAttributeUpdate = noop;
}
bind(target, animate) {
this.target = target, this.animate = animate, this.onBind(), this.syncAttributeUpdate();
}
append(step) {
this.next = step, step.prev = this, step.setStartTime(this.getStartTime() + this.duration, !1);
}
updateDownstreamStartTimes() {
let currentStep = this.next, currentStartTime = this._startTime + this.duration;
for (;currentStep; ) currentStep.setStartTime(currentStartTime, !1), currentStartTime += currentStep.duration,
currentStep = currentStep.next;
this.animate.updateDuration();
}
getLastProps() {
return this.prev ? this.prev.props || {} : this.animate.getStartProps();
}
setDuration(duration, updateDownstream = !0) {
this.duration = duration, updateDownstream && this.updateDownstreamStartTimes();
}
getDuration() {
return this.duration;
}
determineInterpolateUpdateFunction() {
if (!this.props) return;
const funcs = [];
this.propKeys.forEach((key => {
if ("fill" === key || "stroke" === key) {
const from = this.fromProps[key], to = this.props[key];
if (isString(from) && isString(to)) {
const fromArray = ColorStore.Get(from, ColorType.Color255), toArray = ColorStore.Get(to, ColorType.Color255);
this.fromParsedProps || (this.fromParsedProps = {}), this.toParsedProps || (this.toParsedProps = {}),
this.fromParsedProps[key] = fromArray, this.toParsedProps[key] = toArray, funcs.push(interpolateUpdateStore["fill" === key ? "fillPure" : "strokePure"]);
} else interpolateUpdateStore[key] ? funcs.push(interpolateUpdateStore[key]) : funcs.push(commonInterpolateUpdate);
} else interpolateUpdateStore[key] ? funcs.push(interpolateUpdateStore[key]) : funcs.push(commonInterpolateUpdate);
})), this.interpolateUpdateFunctions = funcs;
}
setStartTime(time, updateDownstream = !0) {
this._startTime = time, updateDownstream && this.updateDownstreamStartTimes();
}
getStartTime() {
return this._startTime;
}
onBind() {
"glyph" === this.target.type && (this.syncAttributeUpdate = this._syncAttributeUpdate);
}
runInterpolateUpdate(fromProps, toProps, ratio) {
if (this.animate.interpolateUpdateFunction) return void this.animate.interpolateUpdateFunction(fromProps, toProps, ratio, this, this.target);
const funcs = this.interpolateUpdateFunctions, propKeys = this.propKeys;
if (funcs && propKeys) for (let index = 0; index < funcs.length; index++) {
const key = propKeys[index], fromValue = fromProps[key], toValue = toProps[key];
funcs[index](key, fromValue, toValue, ratio, this, this.target);
}
}
onFirstRun() {}
onStart() {
if (!this._hasFirstRun) {
this._hasFirstRun = !0, this.fromProps = this.getLastProps();
const startProps = this.animate.getStartProps();
this.propKeys && this.propKeys.forEach((key => {
var _a;
this.fromProps[key] = null !== (_a = this.fromProps[key]) && void 0 !== _a ? _a : startProps[key];
})), this.determineInterpolateUpdateFunction(), this.tryPreventConflict(), this.trySyncStartProps(),
this.onFirstRun();
}
}
tryPreventConflict() {
const animate = this.animate, target = this.target, propKeys = this.propKeys;
target.forEachTrackedAnimate((a => {
if (a === animate || a.priority > animate.priority || a.priority === 1 / 0) return;
const fromProps = a.getStartProps();
let conflictKeys = null;
for (let i = 0; i < propKeys.length; i++) {
const key = propKeys[i];
null != fromProps[key] && (null != conflictKeys ? conflictKeys : conflictKeys = []).push(key);
}
conflictKeys && a.preventAttrs(conflictKeys);
}));
}
removeKeysFromRecord(record, keys) {
if (!record) return record;
let hasBlockedKey = !1;
for (const key in record) if (Object.prototype.hasOwnProperty.call(record, key) && includesKey(keys, key)) {
hasBlockedKey = !0;
break;
}
if (!hasBlockedKey) return record;
const nextRecord = {};
for (const key in record) Object.prototype.hasOwnProperty.call(record, key) && !includesKey(keys, key) && (nextRecord[key] = record[key]);
return nextRecord;
}
deleteSelfAttr(key) {
this.deleteSelfAttrs([ key ]);
}
deleteSelfAttrs(keys) {
var _a;
if ((null == keys ? void 0 : keys.length) && (this.props = this.removeKeysFromRecord(this.props, keys),
this.fromProps = this.removeKeysFromRecord(this.fromProps, keys), this.fromParsedProps = this.removeKeysFromRecord(this.fromParsedProps, keys),
this.toParsedProps = this.removeKeysFromRecord(this.toParsedProps, keys), null === (_a = this.propKeys) || void 0 === _a ? void 0 : _a.length)) {
const funcs = this.interpolateUpdateFunctions;
let writeIndex = 0;
for (let readIndex = 0; readIndex < this.propKeys.length; readIndex++) {
const propKey = this.propKeys[readIndex];
includesKey(keys, propKey) || (writeIndex !== readIndex && (this.propKeys[writeIndex] = propKey,
funcs && (funcs[writeIndex] = funcs[readIndex])), writeIndex++);
}
this.propKeys.length = writeIndex, funcs && (funcs.length = writeIndex);
}
}
trySyncStartProps() {
this.propKeys.forEach((key => {
this.fromProps[key] = this.animate.target.getComputedAttribute(key);
}));
}
update(end, ratio, out) {
if (this.onStart(), !this.props || !this.propKeys) return;
const easedRatio = this.easing(ratio);
this.runInterpolateUpdate(this.fromProps, this.props, easedRatio), this.onUpdate(end, easedRatio, out),
this.syncAttributeUpdate();
}
onUpdate(end, ratio, out) {}
onEnd(cb) {
cb ? this._endCb = cb : this._endCb && this._endCb(this.animate, this);
}
getEndProps() {
return this.props;
}
getFromProps() {
return this.fromProps;
}
getMergedEndProps() {
return this.getEndProps();
}
stop() {}
release() {}
}
export class WaitStep extends Step {
constructor(type, props, duration, easing) {
super(type, props, duration, easing);
}
onStart() {
super.onStart();
const fromProps = this.getFromProps();
applyAnimationTransientAttributes(this.target, fromProps, AttributeUpdateType.ANIMATE_START);
}
update(end, ratio, out) {
this.onStart();
}
determineInterpolateUpdateFunction() {}
}
//# sourceMappingURL=step.js.map