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}