Created
May 20, 2022 22:01
-
-
Save Sheepolution/6b44e0522c10a0c8344d93a7c2e9976e to your computer and use it in GitHub Desktop.
rxi's flux in JavaScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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