Files
pronature-platform/src/lib/MotionEngine.js
T
2026-04-04 17:55:25 +03:00

120 lines
3.7 KiB
JavaScript

class MotionEngine {
constructor() {
const aq = [];
this.animationQueue = aq;
function calcValues(target, values, initial, k = 1, mode = 'offset') {
Object.entries(values).forEach(([key, value]) => {
if (value && typeof value === 'object') {
if (!target[key]) {
target[key] = {};
}
calcValues(target[key], value, initial[key], k, mode);
return;
}
if (mode == 'offset') {
target[key] = (initial[key] || 0) + value * k;
} else if (typeof (value) == 'function') {
let v = value(k, target[key]);
if (target[key] !== v){
target[key] = v;
}
} else {
target[key] = (initial[key] || 0) + (value - (initial[key] || 0)) * k;
}
});
return target;
}
// a = {o-object, a-attributes, t-time, f-finish event, d-delay, m-mode, r-repeat,
// rd-repeat the delay, rf-reset on finish, u-on update, s-scope, p-promise on finish}
this.add = function (a) {
a = Array.isArray(a) ? a : [a];
let r = [];
a.forEach(e => {
if (e.t == 0){
e.t = 1;
this.animate(e, 1)
}else{
aq.push(e);
}
if (e.p && !e.f){
r.push(new Promise( resolve=> e.f = resolve ))
}
});
if (r.length) return Promise.all(r);
};
this.clear = function (object, reset = false) {
for (var i = aq.length - 1; i >= 0; i--) {
if (object && aq[i].o == object || !object && (aq[i].ct == aq[i].t || aq[i].rr)) {
if (reset){
aq[i].ct = 0;
this.animate(aq[i], 0);
}
aq.splice(i, 1);
}
}
};
this.clearAll = function(){
aq.splice(0, aq.length);
return;
}
this.remove = function (a) {
let idx = aq.indexOf(a);
if (idx > -1) {
a.ct = 0;
this.animate(a, 0);
aq.splice(idx, 1);
}
};
this.update = (delta) => {
if (aq.length) {
aq.forEach(e => this.animate(e, delta));
this.clear();
}
};
this.animate = function (e, t) {
if (e.d && (e.dt || 0) < e.d) {
e.dt = (e.dt || 0) + t;
return;
}
if (e.ct === undefined) {
e.ct = 0;
e.iv = calcValues({}, e.a, e.o, 0);
}
e.ct = e.ct + t;
if (e.ct > e.t) {
e.ct = e.t;
e.f?.();
if (e.rf){
e.ct = t = 0;
e.rr = true;
}
}
calcValues(e.o, e.a, e.iv, e.ct / e.t, e.m || 'value');
e.u?.();
if (e.ct == e.t && e.r) {
e.ct = e.m == 'offset' ? undefined : 0;
if (e.rd) {
e.dt = 0;
}
}
};
this.isActive = function (object) {
return aq.find(e => e.o == object);
};
this.isIdle = function (scope) {
if (!scope) return aq.length == 0;
return aq.filter(e => e.s == scope).length == 0
};
}
}
export {MotionEngine}