@visactor/vrender-animate
Version:
This module provides a graph-based animation system for VRender.
218 lines (214 loc) • 9.86 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: !0
}), exports.Animate = void 0;
const step_1 = require("./step"), vrender_core_1 = require("@visactor/vrender-core"), timeline_1 = require("./timeline");
class Animate {
constructor(id = vrender_core_1.Generator.GenAutoIncrementId(), timeline = timeline_1.defaultTimeline, slience) {
this.id = id, this.status = vrender_core_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) {
return this.target = target, this.target.animates || (this.target.animates = new Map),
this.target.animates.set(this.id, this), this.onRemove((() => {
this.stop(), this.target.animates.delete(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(vrender_core_1.AnimateStepType.to, props, duration, easing);
return step.bind(this.target, this), this.updateStepAfterAppend(step), this;
}
wait(delay) {
const step = new step_1.WaitStep(vrender_core_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 step_1.Step(vrender_core_1.AnimateStepType.from, props, duration, easing);
return this._firstStep ? (this._lastStep.append(step), this._lastStep = step) : (this._firstStep = step,
this._lastStep = step), this.updateDuration(), this;
}
play(customAnimate) {
return customAnimate.bind(this.target, this), this.updateStepAfterAppend(customAnimate),
this;
}
pause() {
this.status === vrender_core_1.AnimateStatus.RUNNING && (this.status = vrender_core_1.AnimateStatus.PAUSED);
}
resume() {
this.status === vrender_core_1.AnimateStatus.PAUSED && (this.status = vrender_core_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.add(key), delete this._startProps[key], delete this._endProps[key];
let step = this._firstStep;
for (;step; ) step.deleteSelfAttr(key), step = step.next;
}
preventAttrs(keys) {
keys.forEach((key => this._preventAttrs.add(key)));
}
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 !== vrender_core_1.AnimateStatus.END && this.onEnd(), this.status = vrender_core_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 = vrender_core_1.AnimateStatus.END, this._onRemove && this._onRemove.forEach((cb => cb())),
this._onStart = [], this._onFrame = [], this._onEnd = [], this._onRemove = [];
}
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 === vrender_core_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) return null === (_a = this._lastStep) || void 0 === _a || _a.onUpdate(!0, 1, {}),
null === (_b = this._lastStep) || void 0 === _b || _b.onEnd(), this.onEnd(), void (this.status = vrender_core_1.AnimateStatus.END);
this.status = vrender_core_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 && this.target.setAttributes(this._startProps);
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;
}
}
exports.Animate = Animate;
//# sourceMappingURL=animate.js.map