@smoovy/tween
Version:
simple and easy-to-use tween lib
128 lines (127 loc) • 3.8 kB
JavaScript
"use strict";
import { TweenController } from "./controller";
import { getDomProps, mergeDomProps, setDomProps } from "./dom";
function isTargetValid(target) {
return target instanceof HTMLElement || target instanceof SVGElement;
}
function getChanges(from, to) {
const changes = {};
for (const key in from) {
if (Object.prototype.hasOwnProperty.call(from, key) && Object.prototype.hasOwnProperty.call(to, key)) {
const change = to[key] - from[key];
if (change !== 0) {
changes[key] = change;
}
}
}
return changes;
}
const _Tween = class extends TweenController {
constructor(config) {
super(config);
this.config = config;
this.registry = _Tween.registry;
this.originState = {};
this.changedState = {};
this.resultState = {};
this.update();
if (config.reversed) {
this.reverse();
}
if (config.initSeek) {
this.seek(0, true, true);
}
if (config.autoStart !== false) {
this.start();
}
}
get key() {
return this.config.key || this.config.target || this.config.from;
}
updateRegistry() {
const tween = this.registry.get(this.key);
if (this.config.overwrite !== false && tween) {
this.overwrite(this.key);
}
this.registry.set(this.key, this);
}
beforeStop() {
this.registry.delete(this.key);
}
beforeSeek() {
this.updateRegistry();
if (this.config.seekUpdate !== false) {
this.update();
}
}
overwrite(key) {
const tween = this.registry.get(key);
if (tween) {
if (!this._overridden && tween.ticking) {
tween.stop();
}
this.registry.delete(key);
this.callback(this.config.onOverwrite, [tween]);
}
}
update() {
const config = this.config;
const fromState = config.from;
if (config.target && isTargetValid(config.target)) {
this.domTarget = config.target;
} else if (isTargetValid(fromState)) {
this.domTarget = fromState;
}
if (this.domTarget) {
const { values: currentState } = getDomProps(this.domTarget);
const initialState = fromState instanceof HTMLElement ? { ...currentState } : mergeDomProps(currentState, fromState);
const desiredState = mergeDomProps(
currentState,
config.to
);
const changedState = getChanges(initialState, desiredState);
this.originState = initialState;
this.changedState = changedState;
this.resultState = { ...this.originState };
for (const x in this.resultState) {
if (!Object.hasOwnProperty.call(config.to, x)) {
delete this.resultState[x];
}
}
} else {
const initialState = fromState;
const desiredState = config.to;
this.originState = { ...initialState };
this.changedState = getChanges(this.originState, desiredState);
if (config.target && !isTargetValid(config.target)) {
this.resultState = config.target;
} else {
this.resultState = config.mutate !== false ? initialState : { ...this.originState };
}
}
return this;
}
process(eased, linear) {
let changed = false;
for (const prop in this.changedState) {
if (this.changedState[prop] !== void 0) {
const change = this.changedState[prop];
const origin = this.originState[prop];
if (origin !== void 0) {
this.resultState[prop] = origin + change * eased;
changed = true;
}
}
}
if (this.domTarget && changed) {
setDomProps(this.domTarget, this.resultState, this.config.units);
}
this.callback(
this.config.onUpdate,
[this.resultState, { target: this, linear, eased }]
);
return this;
}
};
export let Tween = _Tween;
Tween.registry = /* @__PURE__ */ new WeakMap();