canvas = {
const n = 80;
const height = Math.ceil(width * screen.height / screen.width);
const margin = 100
let w = width - margin * 2
let x0 = margin
let h = height - margin * 2
let y0 = margin
const context = DOM.context2d(width, height);
const particles = Array.from({length: n}, (d,i) => {
let angle = Math.PI * 2 * i / n
let speed = 1
let dx = 1
let dy = 1
let ivx = 1 + Math.random()
let ivy = 1 + Math.random()
return {
x: margin + Math.random() * w,
y: margin + Math.random() * h,
dx: dx,
dy: dy,
ivx: ivx,
ivy: ivy,
vx: (dx * ivx * speed) * Math.cos(angle),
vy: (dy * ivy * speed) * Math.sin(angle),
r: 20 * Math.random() + 10,
speed: speed,
angle: angle
}
});
const quadtree = d3.quadtree()
.x(d => d.x)
.y(d => d.y)
.addAll(particles);
context.canvas.style.background = "#fff";
context.strokeStyle = "red";
while (true) {
context.fillStyle = "rgba(255,255,255,0.07)"
context.fillRect(0,0, width, height)
context.fillStyle = "blue";
context.font = '14px san-serif';
context.strokeStyle = "rgba(25, 205, 58, 0.7)"
context.lineWidth = 2
let p;
for(var i = 0; i < particles.length; i++) {
p = particles[i]
if(p.x > x0 + w) {
if( Math.cos(p.angle) >= 0) {
p.dx = -1
} else {
p.dx = 1
}
}
if(p.y > y0 + h) {
if( Math.sin(p.angle) >= 0) {
p.dy = -1
} else {
p.dy = 1
}
}
if(p.x < x0) {
if( Math.cos(p.angle) >= 0) {
p.dx = 1
} else {
p.dx = -1
}
}
if(p.y < y0) {
if( Math.sin(p.angle) >= 0) {
p.dy = 1
} else {
p.dy = -1
}
}
let nx1 = p.x - p.r,
nx2 = p.x + p.r,
ny1 = p.y - p.r,
ny2 = p.y + p.r;
let touching = false;
quadtree.visit((visited, x1, y1, x2, y2) => {
if (visited.data && (visited.data !== p)) {
let x = p.x - visited.data.x,
y = p.y - visited.data.y,
l = Math.sqrt(x * x + y * y),
r = p.r + visited.data.r;
if (l < r) {
touching = true;
p.x += .05 * x
p.y += .05 * y
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
if(touching) {
p.angle += Math.PI * 0.01
}
p.vx = p.dx * p.ivx * p.speed * Math.cos(p.angle)
p.vy = p.dy * p.ivy * p.speed * Math.sin(p.angle)
p.x += p.vx
p.y += p.vy
context.beginPath()
context.arc(p.x, p.y, p.r, 0, Math.PI*2)
context.stroke()
}
yield context.canvas;
}
}