-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathharmonograph.js
76 lines (60 loc) · 2.02 KB
/
harmonograph.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
function Harmonograph() {
let ctx, size, scale, timer, settings, line;
function init(_settings) {
settings = _settings;
ctx = document.querySelector('canvas').getContext('2d');
canvasContainer = document.querySelector('.canvasContainer');
size = window.innerHeight < canvasContainer.offsetWidth ? window.innerHeight : canvasContainer.offsetWidth;
const canvas = document.querySelector('canvas');
canvas.style.width = size + 'px';
canvas.style.height = size + 'px';
const dpr = window.devicePixelRatio;
canvas.width = size * dpr;
canvas.height = size * dpr;
ctx.scale(dpr, dpr);
scale = d3
.scaleLinear()
.domain([-2, 2])
.range([0, size]);
line = d3
.line()
.x(d => scale(d[0]))
.y(d => scale(d[1]));
}
function update(min, max) {
let { xFreq, yFreq, rotaryFreq, type, rotaryAmp, rotaryType, decay, size, phase, fade } = settings;
const range = d3.range(min, max, 0.4);
const data = range.map(d => {
const theta = d / 60;
let x = Math[phase === 'open' ? 'cos' : 'sin'](theta * xFreq);
let y = Math.sin(theta * yFreq);
if (type === 'rotary') {
x += Math.cos(theta * rotaryFreq) * rotaryAmp * (rotaryType === 'countercurrent' ? -1 : 1);
y += Math.sin(theta * rotaryFreq) * rotaryAmp;
}
x *= (1 - decay * 0.005) ** theta;
y *= (1 - decay * 0.005) ** theta;
x *= size - 0.02;
y *= size - 0.02;
return [x, y];
});
ctx.lineWidth = settings.lineWidth * (1 - fade * 0.0001) ** min;
ctx.beginPath();
line.context(ctx)(data);
ctx.stroke();
return range[range.length - 1] || 0;
}
function startAnimation() {
timer && timer.stop();
ctx.clearRect(0, 0, size, size);
ctx.strokeStyle = settings.darkMode ? '#fff' : '#000';
let last = 0;
timer = d3.timer(elapsed => {
last = update(last, elapsed * settings.speed);
});
}
function applySettings(_) {
settings = _;
}
return { init, startAnimation, applySettings };
}