Public
Edited
Mar 12, 2019
Fork of V
Insert cell
Insert cell
Insert cell
render = {
const particleContext = DOM.context2d(width, height);
// particleContext.canvas.style.background = "#fff";
// particleContext.fillStyle = 'white';
// particleContext.fillRect(0,0,width,height);
const randomWalkParticles = Array.from({length: activeParticles},
() => [Math.random() * width,
Math.random() * height,
(Math.random() - 0.5),
(Math.random() - 0.5)]);
const minDistance2 = minDistance * minDistance;
const maxDistance2 = maxDistance * maxDistance;
let iterationCountBeforeFade = 0;
while(true){
iterationCountBeforeFade++;
if (iterationCountBeforeFade===3) {
// fade 'a lot' every 3 frames instead of fading 'a little' every frame
// workaround to fading issue due to Integer approximation
// see https://stackoverflow.com/questions/41483806/painting-in-canvas-which-fades-with-time-strange-alpha-layering-behaviour
iterationCountBeforeFade = 0;
particleContext.globalCompositeOperation = "destination-out"; // fade out destination pixels
particleContext.fillStyle = "rgba(255,255,255,0.2)";
particleContext.fillRect(0,0,width,height);
particleContext.globalCompositeOperation = "source-over"; // back to default
}
//Connections
for (let i = 0; i < activeParticles; ++i) {
for (let j = i + 1; j < activeParticles; ++j) {
const pi = randomWalkParticles[i];
const pj = randomWalkParticles[j];
const dx = pi[0] - pj[0];
const dy = pi[1] - pj[1];
const d2 = dx * dx + dy * dy;
if (d2 < maxDistance2) {
// I prefer to use alpha in strokeStyle instead of globalalpha
// particleContext.globalAlpha = d2 > minDistance2 ? (maxDistance2 - d2) / (maxDistance2 - minDistance2) : 1;
let alpha = d2 > minDistance2 ? (maxDistance2 - d2) / (maxDistance2 - minDistance2) : 1;
particleContext.strokeStyle= `hsla(220, 53%, 28%, ${alpha})`;
particleContext.beginPath();
particleContext.moveTo(pi[0], pi[1]);
particleContext.lineTo(pj[0], pj[1]);
particleContext.stroke();
particleContext.closePath();
}
}
}


yield particleContext.canvas;

for (const p of randomWalkParticles) {
//Random Walk
p[0] += p[2];
p[1] += p[3];
if (p[0] < (0 - maxDistance)) p[0] = width + maxDistance;
else if (p[0] > (width + maxDistance)) p[0] = 0 - maxDistance;
if (p[1] < (0 - maxDistance)) p[1] = height + maxDistance;
else if (p[1] > (height + maxDistance)) p[1] = 0 - maxDistance;
p[2] += 0.3 * (Math.random() - 0.5) - .01 * p[2];
p[3] += 0.3 * (Math.random() - 0.5) - .01 * p[3];
}
}
}
Insert cell
Insert cell
activeParticles = Math.max(Math.floor(width*height/(minDistance*minDistance+maxDistance*maxDistance)),3);
Insert cell
Insert cell
minDistance = width * 0.05
Insert cell
maxDistance = minDistance * 5
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