alchemi.dev/drift.js

68 lines
2.0 KiB
JavaScript

const m = 76667 * 78887;
const nextRandom = x => x ** 2 % m
const generateRandomArray = (initialSeed, count) => (
count <= 0
? []
: [initialSeed].concat(generateRandomArray(nextRandom(initialSeed), count - 1)))
const zip = (f, ...lists) => (
lists.some(l => l.length == 0)
? []
: [f(...lists.map(l => l[0]))].concat(zip(f, ...lists.map(l => l.slice(1)))))
const goopZoneElem = document.getElementById("goop-zone");
const goopHeader = document.getElementById("header-box");
const nextState = (state, width, height) => document.hidden ? state : state.map(orig => {
const projectedNewX = orig.x + orig.vx;
const projectedNewY = orig.y + orig.vy;
const [newX, newVX] =
projectedNewX < 0 || projectedNewX > width
? [orig.x - orig.vx, -orig.vx]
: [projectedNewX, orig.vx];
const [newY, newVY] =
projectedNewY < -50 || projectedNewY > height - 20
? [orig.y - orig.vy, -orig.vy]
: [projectedNewY, orig.vy];
return ({
elem: orig.elem,
x: newX,
y: newY,
vx: newVX,
vy: newVY
})
});
const mkInitialState = (drifters, width, height) => zip(
(elem, random1, random2, random3) => (direction =>
({ elem: elem
, x: random1 % width
, y: random2 % height
, vx: 20 * Math.cos(direction)
, vy: 20 * Math.sin(direction)
})
)(random3 % 2000 / 1000 * Math.PI),
drifters,
generateRandomArray(5737051, drifters.length),
generateRandomArray(5457297, drifters.length),
generateRandomArray(3631413, drifters.length))
const applyState = states => states.map(s => {
s.elem.setAttribute('style', `transform: translate(${s.x}px, ${s.y}px)`)
});
loop = (state) => {
setInterval(() => {
const goopZoneWidth = goopZoneElem.width.baseVal.value/2;
const goopZoneHeight = goopZoneElem.height.baseVal.value/2;
goopHeader.setAttribute("x", (goopZoneWidth - 300)/2);
state = nextState(state, goopZoneWidth, goopZoneHeight);
applyState(state)
}, 500)
}
const drifters = Array.from(document.getElementsByClassName("glob"));
loop(mkInitialState(drifters, goopZoneElem.width.baseVal.value/2, goopZoneElem.height.baseVal.value/2));