@visactor/vrender-animate
Version:
This module provides a graph-based animation system for VRender.
270 lines (263 loc) • 12.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.Animate = void 0;
const step_1 = require("./step"), generator_1 = require("@visactor/vrender-core/common/generator"), constant_1 = require("@visactor/vrender-core/event/constant"), timeline_1 = require("./timeline"), fromTo_1 = require("./custom/fromTo"), transient_1 = require("./custom/transient");
function includesKey(keys, key) {
for (let i = 0; i < keys.length; i++) if (keys[i] === key) return !0;
return !1;
}
function 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;
}
function collectActiveSiblingAttrKeys(target, currentAnimate) {
var _a;
const getTrackedAnimates = null == target ? void 0 : target.getTrackedAnimates;
if ("function" == typeof getTrackedAnimates) {
const trackedAnimates = getTrackedAnimates.call(target);
if (trackedAnimates && trackedAnimates.size <= 1) return;
}
const forEachTrackedAnimate = null == target ? void 0 : target.forEachTrackedAnimate;
if ("function" != typeof forEachTrackedAnimate) return;
let keys;
const currentEndProps = null === (_a = currentAnimate.getEndProps) || void 0 === _a ? void 0 : _a.call(currentAnimate);
return forEachTrackedAnimate.call(target, (animate => {
var _a;
if (animate === currentAnimate || animate.status === constant_1.AnimateStatus.END) return;
const endProps = null === (_a = animate.getEndProps) || void 0 === _a ? void 0 : _a.call(animate);
if (endProps) for (const key in endProps) !Object.prototype.hasOwnProperty.call(endProps, key) || currentEndProps && Object.prototype.hasOwnProperty.call(currentEndProps, key) || ((null != keys ? keys : keys = Object.create(null))[key] = !0);
})), keys;
}
class Animate {
constructor(id = generator_1.Generator.GenAutoIncrementId(), timeline = timeline_1.defaultTimeline, slience) {
this.id = id, this.status = constant_1.AnimateStatus.INITIAL, this._timeline = timeline,
timeline.addAnimate(this), this.slience = slience, this._startTime = 0, this._duration = 0,
this._totalDuration = 0, this._loopCount = 0, this._currentLoop = 0, this._bounce = !1,
this._firstStep = null, this._lastStep = null, this._startProps = {}, this._endProps = {},
this._preventAttrs = new Set, this.currentTime = 0, this.interpolateUpdateFunction = null,
this.priority = 0;
}
getStartProps() {
return this._startProps;
}
getEndProps() {
return this._endProps;
}
setTimeline(timeline) {
this._timeline = timeline;
}
getTimeline() {
return this._timeline;
}
get timeline() {
return this._timeline;
}
bind(target) {
this.target = target;
const trackerTarget = this.target;
return trackerTarget.detachAttributeFromBaseAttributes(), trackerTarget.trackAnimate(this),
this.onRemove((() => {
this.stop(), this.__skipRestoreStaticAttributeOnRemove || trackerTarget.restoreStaticAttribute(collectActiveSiblingAttrKeys(trackerTarget, this)),
trackerTarget.untrackAnimate(this.id);
})), this.target.onAnimateBind && !this.slience && this.target.onAnimateBind(this),
this.target.animationAttribute || (this.target.animationAttribute = {}), this;
}
to(props, duration = 300, easing = "linear") {
const step = new step_1.Step(constant_1.AnimateStepType.to, props, duration, easing);
return step.bind(this.target, this), this.updateStepAfterAppend(step), this;
}
wait(delay) {
const step = new step_1.WaitStep(constant_1.AnimateStepType.wait, {}, delay, "linear");
return step.bind(this.target, this), this.updateStepAfterAppend(step), this;
}
updateStepAfterAppend(step) {
this._firstStep ? (this._lastStep.append(step), this._lastStep = step) : (this._firstStep = step,
this._lastStep = step), this.parseStepProps(step), this.updateDuration();
}
parseStepProps(step) {
this._lastStep && (step.propKeys = step.propKeys || Object.keys(step.props), Object.keys(this._endProps).forEach((key => {
var _a;
step.props[key] = null !== (_a = step.props[key]) && void 0 !== _a ? _a : this._endProps[key];
})), step.propKeys.forEach((key => {
this._endProps[key] = step.props[key];
})));
}
reSyncProps() {
if (!this._lastStep) return;
this._endProps = {};
let currentStep = this._firstStep;
for (;currentStep; ) Object.keys(this._endProps).forEach((key => {
var _a;
currentStep.props[key] = null !== (_a = currentStep.props[key]) && void 0 !== _a ? _a : this._endProps[key];
})), currentStep.propKeys.forEach((key => {
this._endProps[key] = currentStep.props[key];
})), currentStep = currentStep.next;
}
from(props, duration = 300, easing = "linear") {
const step = new fromTo_1.FromTo(props, {}, duration, easing);
return step.bind(this.target, this), this.updateStepAfterAppend(step), this;
}
play(customAnimate) {
return customAnimate.bind(this.target, this), this.updateStepAfterAppend(customAnimate),
this;
}
pause() {
this.status === constant_1.AnimateStatus.RUNNING && (this.status = constant_1.AnimateStatus.PAUSED);
}
resume() {
this.status === constant_1.AnimateStatus.PAUSED && (this.status = constant_1.AnimateStatus.RUNNING);
}
onStart(cb) {
var _a;
cb ? (this._onStart || (this._onStart = []), this._onStart.push(cb)) : (null === (_a = this._onStart) || void 0 === _a || _a.forEach((cb => cb())),
Object.keys(this._endProps).forEach((key => {
this._startProps[key] = this.target.getComputedAttribute(key);
})));
}
onEnd(cb) {
var _a;
cb ? (this._onEnd || (this._onEnd = []), this._onEnd.push(cb)) : null === (_a = this._onEnd) || void 0 === _a || _a.forEach((cb => cb()));
}
onFrame(cb) {
cb && (this._onFrame || (this._onFrame = []), this._onFrame.push(cb));
}
onRemove(cb) {
var _a;
cb ? (this._onRemove || (this._onRemove = []), this._onRemove.push(cb)) : null === (_a = this._onRemove) || void 0 === _a || _a.forEach((cb => cb()));
}
preventAttr(key) {
this.preventAttrs([ key ]);
}
preventAttrs(keys) {
if (!(null == keys ? void 0 : keys.length)) return;
for (let i = 0; i < keys.length; i++) this._preventAttrs.add(keys[i]);
this._startProps = removeKeysFromRecord(this._startProps, keys), this._endProps = removeKeysFromRecord(this._endProps, keys);
let step = this._firstStep;
for (;step; ) step.deleteSelfAttrs(keys), step = step.next;
}
validAttr(key) {
return !this._preventAttrs.has(key);
}
runCb(cb) {
var _a;
return null === (_a = this._lastStep) || void 0 === _a || _a.onEnd(cb), this;
}
startAt(t) {
return this._startTime = t, this;
}
customInterpolate(key, ratio, from, to, target, ret) {
return !1;
}
getFromValue() {
return this._startProps;
}
getToValue() {
return this._endProps;
}
stop(type) {
let step = this._firstStep;
for (;step; ) step.stop(), step = step.next;
this.status !== constant_1.AnimateStatus.END && this.onEnd(), this.status = constant_1.AnimateStatus.END,
this.target && ("start" === type ? this.target.setAttributes(this._startProps) : "end" === type ? this.target.setAttributes(this._endProps) : type && this.target.setAttributes(type));
}
release() {
this.status = constant_1.AnimateStatus.END, this._onRemove && this._onRemove.forEach((cb => cb())),
this._onStart = [], this._onFrame = [], this._onEnd = [], this._onRemove = [], this.forEachStep((step => {
step.release();
}));
}
getDuration() {
return this._duration;
}
getStartTime() {
return this._startTime;
}
afterAll(list) {
if (!list || 0 === list.length) return this;
let maxEndTime = 0;
return list.forEach((animate => {
const endTime = animate.getStartTime() + animate.getTotalDuration();
maxEndTime = Math.max(maxEndTime, endTime);
})), this.startAt(maxEndTime);
}
after(animate) {
if (!animate) return this;
const endTime = animate.getStartTime() + animate.getTotalDuration();
return this.startAt(endTime);
}
parallel(animate) {
return animate ? (this.startAt(animate.getStartTime()), this) : this;
}
loop(n) {
return !0 === n ? n = 1 / 0 : !1 === n && (n = 0), this._loopCount = n, this.updateDuration(),
this;
}
bounce(b) {
return this._bounce = b, this;
}
advance(delta) {
var _a, _b, _c;
if (this.status === constant_1.AnimateStatus.END) return void console.warn("aaa 动画已经结束,不能推进");
const nextTime = this.currentTime + delta;
if (nextTime < this._startTime) return void (this.currentTime = nextTime);
if (nextTime >= this._startTime + this._totalDuration) {
null === (_a = this._lastStep) || void 0 === _a || _a.onUpdate(!0, 1, {}), null === (_b = this._lastStep) || void 0 === _b || _b.onEnd(),
this.onEnd(), this.status = constant_1.AnimateStatus.END;
const trackerTarget = this.target;
return trackerTarget.restoreStaticAttribute(collectActiveSiblingAttrKeys(trackerTarget, this)),
void (this.__skipRestoreStaticAttributeOnRemove = !0);
}
this.status = constant_1.AnimateStatus.RUNNING, this.currentTime <= this._startTime && this.onStart(),
this.currentTime = nextTime;
let cycleTime = nextTime - this._startTime, newLoop = !1, bounceTime = !1;
if (this._loopCount > 0) {
cycleTime = (nextTime - this._startTime) % this._duration;
const currentLoop = Math.floor((nextTime - this._startTime) / this._duration);
newLoop = currentLoop > this._currentLoop, this._currentLoop = currentLoop, bounceTime = this._bounce && currentLoop % 2 == 1,
bounceTime && (cycleTime = this._duration - cycleTime);
}
newLoop && !bounceTime && (0, transient_1.applyAnimationTransientAttributes)(this.target, this._startProps, constant_1.AttributeUpdateType.ANIMATE_START);
let targetStep = null;
if (this._lastStep === this._firstStep) targetStep = this._firstStep; else {
let currentStep = this._firstStep;
for (;currentStep; ) {
const stepStartTime = currentStep.getStartTime(), stepDuration = currentStep.getDuration();
if (cycleTime >= stepStartTime && cycleTime <= stepStartTime + stepDuration) {
targetStep = currentStep;
break;
}
currentStep = currentStep.next;
}
}
if (!targetStep) return;
targetStep !== this.lastRunStep && (null === (_c = this.lastRunStep) || void 0 === _c || _c.onEnd()),
this.lastRunStep = targetStep;
const ratio = (cycleTime - targetStep.getStartTime()) / targetStep.getDuration(), isEnd = ratio >= 1;
targetStep.update(isEnd, ratio, {}), isEnd && (targetStep.onEnd(), this.lastRunStep = null);
}
updateDuration() {
this._lastStep ? (this._duration = this._lastStep.getStartTime() + this._lastStep.getDuration(),
this._totalDuration = this._duration * (this._loopCount + 1)) : this._duration = 0;
}
getTotalDuration() {
return this._totalDuration;
}
getLoop() {
return this._loopCount;
}
forEachStep(cb) {
let step = this._firstStep;
for (;step; ) cb(step), step = step.next;
}
}
exports.Animate = Animate;
//# sourceMappingURL=animate.js.map