Public
Edited
Mar 3, 2024
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Set Up the Canvas: Create a canvas element where the animation will take place.
canvas = {
const context = DOM.context2d(width, height);
context.fillStyle = "black";
context.fillRect(0, 0, context.canvas.width, context.canvas.height);
return context.canvas;
}

Insert cell
width = 600
Insert cell
height = 600
Insert cell
Insert cell
particles = Array.from({length: numParticles}, () => {
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * particleSpeed;
return {
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed
};
});

Insert cell
Insert cell
updateParticles = (particles) => {
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
// Implement wrapping at edges
if (p.x > width) p.x = 0;
if (p.y > height) p.y = 0;
if (p.x < 0) p.x = width;
if (p.y < 0) p.y = height;
});
}

Insert cell
Insert cell
// drawParticles = (context, particles) => {
// context.clearRect(0, 0, context.canvas.width, context.canvas.height);
// context.fillStyle = "white";
// particles.forEach(p => {
// context.beginPath();
// context.arc(p.x, p.y, 1, 0, Math.PI * 2);
// context.fill();
// });
// }

Insert cell
Insert cell
animation = {
const context = canvas.getContext("2d");
let frame = 0;
const particles = Array.from({length: numParticles}, () => {
const angle = Math.random() * Math.PI * 2;
const speed = Math.random() * 5; // Adjust if necessary
return {
x: Math.random() * canvas.width,
y: Math.random() * canvas.height,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed
};
});

yield* Generators.observe(function(notify) {
const centerX = canvas.width / 2;
const centerY = canvas.height / 2;

const update = () => {
particles.forEach(p => {
// Modify velocity based on the particleSpeed slider
p.x += p.vx * particleSpeed;
p.y += p.vy * particleSpeed;

// Attraction to center
const dx = centerX - p.x;
const dy = centerY - p.y;
const distance = Math.sqrt(dx * dx + dy * dy);
const attraction = distance ? attractionForce / distance : 0;

// Apply attraction force towards the center
p.vx += dx * attraction;
p.vy += dy * attraction;

// Apply noise influence
p.vx += (Math.random() - 0.5) * noiseInfluence;
p.vy += (Math.random() - 0.5) * noiseInfluence;

// Update position
p.x += p.vx;
p.y += p.vy;

// Boundary conditions
if (p.x > canvas.width) p.x = 0;
if (p.y > canvas.height) p.y = 0;
if (p.x < 0) p.x = canvas.width;
if (p.y < 0) p.y = canvas.height;
});

// Clear and redraw
context.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach(p => {
context.beginPath();
context.arc(p.x, p.y, 2, 0, 2 * Math.PI);
context.fill();
});

notify(canvas);
};

(function animate() {
update();
frame = requestAnimationFrame(animate);
})();

return () => cancelAnimationFrame(frame);
});
}

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