-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
96 lines (76 loc) · 2.87 KB
/
index.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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import init, { BoidFlock } from './pkg/boids.js';
const canvas = document.querySelector('canvas');
resize()
window.addEventListener('resize', resize);
const main = async () => {
try {
let wasm = await init();
const memory = wasm.memory;
const ctx = canvas.getContext('2d', { antialias: false });
const flock = new BoidFlock(25);
const count = flock.count();
const positions = flock.positions();
const velocities = flock.velocities();
for (let i = 0; i < count * 2; i += 2) {
positions[i] = Math.random() * canvas.width;
positions[i + 1] = Math.random() * canvas.height;
velocities[i] = 2 * Math.random() - 1;
velocities[i + 1] = 2 * Math.random() - 1;
}
let fadeInFrame = 0;
const maxFadeInFrames = 300;
// Repel boids with the mouse cursor
canvas.addEventListener("mousemove", event => {
const boundingRect = canvas.getBoundingClientRect();
const scaleX = canvas.width / boundingRect.width;
const scaleY = canvas.height / boundingRect.height;
const canvasLeft = (event.clientX - boundingRect.left) * scaleX;
const canvasTop = (event.clientY - boundingRect.top) * scaleY;
flock.set_repulsor(canvasLeft, canvasTop);
});
canvas.addEventListener("mouseleave", event => {
flock.unset_repulsor();
});
const renderLoop = () => {
flock.set_width(canvas.width)
flock.set_height(canvas.height)
flock.update();
// The memory locations change over time, so we need to refresh them in the loop.
const positions = flock.positions();
const velocities = flock.velocities();
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'grey';
ctx.strokeStyle = 'grey';
// Fade in the boids to hide the delayed load
if (fadeInFrame <= maxFadeInFrames) {
ctx.globalAlpha = fadeInFrame / maxFadeInFrames;
fadeInFrame += 1;
}
for (let i = 0; i < 2 * count; i += 2) {
const halfWidth = 2;
const height = 8;
// Calculate the heading of the boid.
const angle = Math.atan2(velocities[i + 1], velocities[i]);
const cos = Math.cos(angle);
const sin = Math.sin(angle);
// Draw a triangle.
ctx.beginPath();
ctx.moveTo(-sin * halfWidth + positions[i], cos * halfWidth + positions[i + 1]);
ctx.lineTo(sin * halfWidth + positions[i], -cos * halfWidth + positions[i + 1]);
ctx.lineTo(cos * height + positions[i], sin * height + positions[i + 1]);
ctx.lineTo(-sin * halfWidth + positions[i], cos * halfWidth + positions[i + 1]);
ctx.fill();
ctx.stroke();
}
window.requestAnimationFrame(renderLoop);
};
renderLoop();
} catch (error) {
console.error("Error:", error);
}
};
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
main();