Public
Edited
Jan 24, 2024
1 star
Insert cell
Insert cell
{
const frameDuration = 60;
let lastUpdate;
const { width, height } = dimensions;
console.log(dimensions.width, dimensions.height);
const ctx = DOM.context2d(width, height, 1);
const n = 20;
let fishes = [];
for (let i = 0; i < n; i++) {
fishes.push(randomFish(width, height));
}
function updateAndDrawFishes(t) {
if (!lastUpdate) {
lastUpdate = t;
}
const elapsedFrames = Math.floor((t - lastUpdate) / frameDuration);
if (elapsedFrames > 0) {
ctx.clearRect(0, 0, width, height);
lastUpdate = t;
}
let replaceFish = [];
fishes.forEach((fish, i) => {
fish.tick(elapsedFrames);
fish.draw(ctx);
if (fish.x > width + 100) {
replaceFish.push(i);
}
});
replaceFish.forEach((idx) =>
fishes.splice(idx, 1, randomFish(width, height, -100))
);

const id = requestAnimationFrame((t) => updateAndDrawFishes(t));
invalidation.then(() => cancelAnimationFrame(id));
}
const id = requestAnimationFrame(updateAndDrawFishes);
invalidation.then(() => cancelAnimationFrame(id));
ctx.canvas.style.background =
"linear-gradient(20deg, lightblue 0%, beige 50%, white 100%)";
return ctx.canvas;
}
Insert cell
function randomFish(w, h, x) {
const rndScale = 1 - 0.5 * Math.random();
const rndX = x || Math.random() * w;
const rndY = -15 + Math.random() * (h - 60);
const rndV = 1 + Math.random() * 10;
return new Fish(rndX, rndY, rndScale, rndV);
}
Insert cell
class Fish {
constructor(x, y, scale, velocity) {
this.x = x;
this.y = y;
this.scale = scale;
this.velocity = velocity;
}

tick(i) {
this.x += i * this.velocity;
}

draw(ctx) {
ctx.translate(this.x, this.y);
ctx.scale(this.scale, this.scale);
drawFish(ctx);
ctx.resetTransform();
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more