Skip to content

Instantly share code, notes, and snippets.

@Sheepolution
Created May 20, 2022 22:01
Show Gist options
  • Save Sheepolution/6b44e0522c10a0c8344d93a7c2e9976e to your computer and use it in GitHub Desktop.
Save Sheepolution/6b44e0522c10a0c8344d93a7c2e9976e to your computer and use it in GitHub Desktop.
rxi's flux in JavaScript
const getFlux = function () {
var flux = { _version: '0.1.5' };
var tween = getTween();
flux.list = [];
flux.objects = [];
flux.tweens = {};
flux.easing = { linear: function (p) { return p; } };
var easing = {
quad: 'p * p',
cubic: 'p * p * p',
quart: 'p * p * p * p',
quint: 'p * p * p * p * p',
expo: '2 ^ (10 * (p - 1))',
sine: '-Math.cos(p * (Math.pi * .5)) + 1',
circ: '-(Math.sqrt(1 - (p * p)) - 1)',
back: 'p * p * (2.7 * p - 1.7)',
elastic: '-(2^(10 * (p - 1)) * Math.sin((p - 1.075) * (Math.PI * 2) / .3))'
};
var makefunc = function (str, expr) {
return new Function('p', str.split('$e').join(expr));
};
for (var k in easing) {
var v = easing[k];
flux.easing[k + 'in'] = makefunc('return $e', v);
flux.easing[k + 'out'] = makefunc(`
p = 1 - p;
return 1 - ($e);
`, v);
flux.easing[k + 'inout'] = makefunc(`
p = p * 2
if (p < 1) {
return .5 * ($e);
}
else {
p = 2 - p;
return .5 * (1 - ($e)) + .5;
}
`, v);
}
flux.group = function () {
return getFlux();
};
flux.to = function (obj, time, vars) {
return flux.add(tween.new(obj, time, vars));
};
flux.update = function (deltatime) {
for (let i = 0; i < this.list.length; i++) {
var t = this.list[i];
if (t._delay > 0) {
t._delay = t._delay - deltatime;
}
else {
if (!t.inited) {
flux.clear(t.obj, t.vars);
t.init();
}
if (t._onstart) {
t._onstart();
t._onstart = null;
}
t.progress = t.progress + t.rate * deltatime;
var p = t.progress;
var x = p >= 1 ? 1 : flux.easing[t._ease](p);
for (var k in t.vars) {
var v = t.vars[k];
t.obj[k] = v.start + x * v.diff;
}
if (t._onupdate) { t._onupdate(); }
if (p >= 1) {
flux.remove(i);
if (t._oncomplete) { t._oncomplete(); }
}
}
}
};
flux.clear = function (obj, vars) {
var object = this.objects.find(object => object.obj == obj);
if (object) {
for (let i = 0; i < object.tweens.length; i++) {
var t = object.tweens[i];
if (t.inited) {
for (var k in vars) {
delete t.vars[k];
}
}
}
}
};
flux.add = function (tween) {
var obj = tween.obj;
var object = this.objects.find(object => object.obj == obj);
if (object == null) {
object = { obj: obj, tweens: [] };
this.objects.push(object);
}
object.tweens.push(tween);
this.list.push(tween);
tween.parent = this;
return tween;
};
flux.remove = function (x) {
if (typeof (x) == 'number') {
var obj = this.list[x].obj;
var indexObject = this.objects.findIndex(object => object.obj == obj);
var object = this.objects[indexObject];
var indexTween = object.tweens.indexOf(this.list[x]);
object.tweens.splice(indexTween, 1);
if (object.tweens.length == 0) { this.objects.splice(indexObject, 1); }
this.list[x] = this.list[this.list.length - 1];
return this.list.pop();
}
for (let i = 0; i < this.list.length; i++) {
if (this.list[i] == x) {
return this.remove(i);
}
}
};
return flux;
};
const getTween = function () {
var tween = {};
var makefsetter = function (field) {
return function (x) {
if (typeof (x) != 'function') {
console.error('expected function or callable');
}
var old = this[field];
this[field] = old ? function () { old(); x(); } : x;
return this;
};
};
var makesetter = function (field, checkfn, errmsg) {
return function (x) {
if (checkfn && !checkfn(x)) {
console.logerror(errmsg.replace('$x', x.toString()));
}
this[field] = x;
return this;
};
};
tween.ease = makesetter('_ease',
function (x) { return flux.easing[x]; },
'bad easing type \'$x\'');
tween.delay = makesetter('_delay',
function (x) { return typeof (x) == 'number'; },
'bad delay time; expected number');
tween.onstart = makefsetter('_onstart');
tween.onupdate = makefsetter('_onupdate');
tween.oncomplete = makefsetter('_oncomplete');
tween.new = function (obj, time, vars) {
var self = getTween();
self.obj = obj;
self.rate = time > 0 ? 1 / time : 0;
self.progress = time > 0 ? 0 : 1;
self._delay = 0;
self._ease = 'quadout';
self.vars = {};
for (var k in vars) {
var v = vars[k];
if (typeof (v) != 'number') {
console.error('bad value for key \'' + k + '\'; expected number');
}
self.vars[k] = v;
}
return self;
};
tween.init = function () {
for (var k in this.vars) {
var v = this.vars[k];
var x = this.obj[k];
if (typeof (x) != 'number') {
console.error('bad value on object key \'' + k + '\'; expected number');
}
this.vars[k] = { start: x, diff: v - x };
}
this.inited = true;
};
tween.after = function (...args) {
var t;
if (args.length == 2) {
t = tween.new(this.obj, ...args);
}
else {
t = tween.new(...args);
}
t.parent = this.parent;
var that = this;
this.oncomplete(function () { flux.add.apply(that.parent, [t]); });
return t;
};
tween.stop = function () {
flux.remove.apply(this.parent, [this]);
};
return tween;
};
export const flux = getFlux();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment