prosperon/scripts/tween.js

221 lines
4.9 KiB
JavaScript
Raw Normal View History

2023-12-28 07:57:22 -06:00
/* Take numbers from 0 to 1 and remap them to easing functions */
var Ease = {
2024-09-26 11:36:09 -05:00
linear(t) {
return t;
},
2023-12-28 07:57:22 -06:00
2024-09-26 11:36:09 -05:00
in(t) {
return t * t;
},
2023-12-28 07:57:22 -06:00
out(t) {
2024-09-26 11:36:09 -05:00
var d = 1 - t;
return 1 - d * d;
2023-12-28 07:57:22 -06:00
},
inout(t) {
2024-09-26 11:36:09 -05:00
var d = -2 * t + 2;
2023-12-28 07:57:22 -06:00
return t < 0.5 ? 2 * t * t : 1 - (d * d) / 2;
},
};
function make_easing_fns(num) {
var obj = {};
2024-09-26 11:36:09 -05:00
obj.in = function (t) {
return Math.pow(t, num);
2023-12-28 07:57:22 -06:00
};
2024-09-26 11:36:09 -05:00
obj.out = function (t) {
2023-12-28 07:57:22 -06:00
return 1 - Math.pow(1 - t, num);
};
2024-09-26 11:36:09 -05:00
var mult = Math.pow(2, num - 1);
2023-12-28 07:57:22 -06:00
2024-09-26 11:36:09 -05:00
obj.inout = function (t) {
2023-12-28 07:57:22 -06:00
return t < 0.5 ? mult * Math.pow(t, num) : 1 - Math.pow(-2 * t + 2, num) / 2;
};
return obj;
2024-09-26 11:36:09 -05:00
}
2023-12-28 07:57:22 -06:00
Ease.quad = make_easing_fns(2);
Ease.cubic = make_easing_fns(3);
Ease.quart = make_easing_fns(4);
Ease.quint = make_easing_fns(5);
Ease.expo = {
in(t) {
return t === 0 ? 0 : Math.pow(2, 10 * t - 10);
},
out(t) {
return t === 1 ? 1 : 1 - Math.pow(2, -10 * t);
},
inout(t) {
return t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
2024-09-26 11:36:09 -05:00
},
2023-12-28 07:57:22 -06:00
};
Ease.bounce = {
in(t) {
return 1 - this.out(t - 1);
},
out(t) {
var n1 = 7.5625;
var d1 = 2.75;
2024-09-26 11:36:09 -05:00
if (t < 1 / d1) {
return n1 * t * t;
} else if (t < 2 / d1) {
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else return n1 * (t -= 2.625 / d1) * t + 0.984375;
2023-12-28 07:57:22 -06:00
},
inout(t) {
return t < 0.5 ? (1 - this.out(1 - 2 * t)) / 2 : (1 + this.out(2 * t - 1)) / 2;
2024-09-26 11:36:09 -05:00
},
2023-12-28 07:57:22 -06:00
};
Ease.sine = {
2024-09-26 11:36:09 -05:00
in(t) {
return 1 - Math.cos((t * Math.PI) / 2);
},
2023-12-28 07:57:22 -06:00
2024-09-26 11:36:09 -05:00
out(t) {
return Math.sin((t * Math.PI) / 2);
},
2023-12-28 07:57:22 -06:00
2024-09-26 11:36:09 -05:00
inout(t) {
return -(Math.cos(Math.PI * t) - 1) / 2;
},
2023-12-28 07:57:22 -06:00
};
Ease.elastic = {
in(t) {
2024-09-26 11:36:09 -05:00
return t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * this.c4);
2023-12-28 07:57:22 -06:00
},
out(t) {
2024-09-26 11:36:09 -05:00
return t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * this.c4) + 1;
2023-12-28 07:57:22 -06:00
},
inout(t) {
2024-09-26 11:36:09 -05:00
t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 : (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * this.c5)) / 2 + 1;
2023-12-28 07:57:22 -06:00
},
};
2024-09-26 11:36:09 -05:00
Ease.elastic.c4 = (2 * Math.PI) / 3;
Ease.elastic.c5 = (2 * Math.PI) / 4.5;
2023-12-28 07:57:22 -06:00
2024-09-26 11:36:09 -05:00
var tween = function (from, to, time, fn, endfn) {
2024-04-01 08:13:57 -05:00
var start = profile.secs(profile.now());
2024-09-26 11:36:09 -05:00
var update = function (dt) {
2024-10-02 09:55:32 -05:00
profile.report("tween");
2024-04-01 08:13:57 -05:00
var elapsed = profile.secs(profile.now()) - start;
2024-09-26 11:36:09 -05:00
fn(from.lerp(to, elapsed / time));
2024-04-01 08:13:57 -05:00
if (elapsed >= time) {
2024-07-18 12:39:58 -05:00
fn(to);
if (stop.then) stop.then();
2024-04-01 08:13:57 -05:00
stop();
endfn?.();
2024-04-01 08:13:57 -05:00
}
2024-10-02 09:55:32 -05:00
profile.endreport("tween");
2024-04-01 08:13:57 -05:00
};
var stop = Register.update.register(update);
2024-07-18 12:39:58 -05:00
return stop;
2024-09-26 11:36:09 -05:00
};
2024-04-01 08:13:57 -05:00
2023-12-28 07:57:22 -06:00
var Tween = {
default: {
2024-04-14 14:53:41 -05:00
loop: "hold",
2023-12-28 07:57:22 -06:00
/*
loop types
none: when done, return to first value
hold: hold last value of tween
restart: restart at beginning, looping
yoyo: go up and then back down
circle: go up and back down, looped
*/
2024-09-26 11:36:09 -05:00
time: 1 /* seconds to do */,
2023-12-28 07:57:22 -06:00
ease: Ease.linear,
2024-09-26 11:36:09 -05:00
whole: true /* True if time is for the entire tween, false if each stage */,
cb: function () {},
2023-12-28 07:57:22 -06:00
},
2024-09-26 11:36:09 -05:00
start(obj, target, tvals, options) {
2023-12-28 07:57:22 -06:00
var defn = Object.create(this.default);
Object.assign(defn, options);
2024-09-26 11:36:09 -05:00
if (defn.loop === "circle") tvals.push(tvals[0]);
else if (defn.loop === "yoyo") {
for (var i = tvals.length - 2; i >= 0; i--) tvals.push(tvals[i]);
2023-12-28 07:57:22 -06:00
}
defn.accum = 0;
var slices = tvals.length - 1;
var slicelen = 1 / slices;
2024-09-26 11:36:09 -05:00
defn.fn = function (dt) {
2023-12-28 07:57:22 -06:00
defn.accum += dt;
2024-09-26 11:36:09 -05:00
if (defn.accum >= defn.time && defn.loop === "hold") {
if (typeof target === "string") obj[target] = tvals[tvals.length - 1];
else target(tvals[tvals.length - 1]);
2023-12-28 07:57:22 -06:00
defn.pause();
2024-09-26 11:36:09 -05:00
defn.cb.call(obj);
return;
2023-12-28 07:57:22 -06:00
}
defn.pct = (defn.accum % defn.time) / defn.time;
2024-09-26 11:36:09 -05:00
if (defn.loop === "none" && defn.accum >= defn.time) defn.stop();
2023-12-28 07:57:22 -06:00
var t = defn.whole ? defn.ease(defn.pct) : defn.pct;
var nval = t / slicelen;
var i = Math.trunc(nval);
nval -= i;
2024-09-26 11:36:09 -05:00
if (!defn.whole) nval = defn.ease(nval);
2023-12-28 07:57:22 -06:00
2024-09-26 11:36:09 -05:00
if (typeof target === "string") obj[target] = tvals[i].lerp(tvals[i + 1], nval);
else target(tvals[i].lerp(tvals[i + 1], nval));
2023-12-28 07:57:22 -06:00
};
var playing = false;
2024-09-26 11:36:09 -05:00
defn.play = function () {
2023-12-28 07:57:22 -06:00
if (playing) return;
2024-01-03 14:26:42 -06:00
defn._end = Register.update.register(defn.fn.bind(defn));
2023-12-28 07:57:22 -06:00
playing = true;
};
2024-09-26 11:36:09 -05:00
defn.restart = function () {
2023-12-28 07:57:22 -06:00
defn.accum = 0;
2024-09-26 11:36:09 -05:00
if (typeof target === "string") obj[target] = tvals[0];
else target(tvals[0]);
};
defn.stop = function () {
if (!playing) return;
defn.pause();
defn.restart();
2023-12-28 07:57:22 -06:00
};
2024-09-26 11:36:09 -05:00
defn.pause = function () {
2024-01-03 14:26:42 -06:00
defn._end();
2023-12-28 07:57:22 -06:00
if (!playing) return;
playing = false;
};
return defn;
},
};
Tween.make = Tween.start;
2024-09-26 11:36:09 -05:00
return { Tween, Ease, tween };