hilbert-clock/script.js
2025-03-17 09:16:00 +00:00

87 lines
No EOL
1.9 KiB
JavaScript

let steps = 3;
console.clear();
const rules = {
"A": "+BF-AFA-FB+",
"B": "-AF+BFB+FA-",
};
let s = "A";
for(let i=0;i<steps;i++) {
let ns = "";
for(let c of s) {
ns += rules[c] || c;
}
s = ns;
}
let [x,y] = [0,0];
const m = 1/(2**steps-1);
let dir = [m,0];
let d = 'M 0 0 ';
const width = 1.5 * 2**-(steps+1);
const dots = [];
for(let c of s) {
const [dx,dy] = dir;
switch(c) {
case '+':
dir = [-dy,dx];
break;
case '-':
dir = [dy,-dx];
break;
case 'F':
x += dx;
y += dy;
d += `l ${dx} ${dy}`;
}
}
d += 'l 0.000000001 0.000001'; // make sure the final dot is drawn
const length = (2**(2*steps)-1) * m;
const curves = Array.from(document.querySelectorAll('.curve'));
for(let curve of curves) {
curve.setAttribute('stroke-width',width);
curve.setAttribute('stroke-linecap','round');
curve.setAttribute('stroke-dasharray',`${length} ${length}`);
curve.setAttribute('d',d);
}
document.getElementById('dots').setAttribute('stroke-width',width*0.4);
document.getElementById('dots').setAttribute('d',d);
document.getElementById('dots').setAttribute('stroke-dasharray',`0 ${m}`);
function easeInOutSine(x) {
return -(Math.cos(Math.PI * x) - 1) / 2;
}
function easeLinear(t) {
return 1-2*Math.abs(t % 1 - 0.5);
}
function frame() {
const period = 1000;
const pips = 2**(2*steps)-1;
let scale = 1;
curves.forEach((curve,i) => {
const dt = (new Date() - 0) / scale / period;
const m = dt % (pips);
const t = dt;
const l = (Math.floor(m) + easeInOutSine(m % 1))*length/pips;
const n = Math.max(0,easeInOutSine(t))*l;
//document.getElementById('debug').textContent = `${m.toFixed(4)} ${length} ${pips}`
curve.setAttribute('stroke-dasharray',`${l-n} ${length}`);
curve.setAttribute('stroke-dashoffset',-n);
curve.setAttribute('stroke-width',width*(easeInOutSine(t)*0.1+0.9)/2**(i+1));
scale *= pips;
})
requestAnimationFrame(frame);
}
frame();