Published
Edited
Sep 7, 2021
Insert cell
Insert cell
Insert cell
totalNodes = 32
Insert cell
viewof canvasGrid = {
const q5 = new Q5();
q5.createCanvas(width, height);
const el = html`${q5.canvas}`;
el.value = q5;
yield el;

const bgcolor = d3.hcl(chance.pickone(colors));
// bgcolor.l += 10;
bgcolor.c += 20;
// bgcolor.c -= 1;

q5.background(bgcolor.hex());
// q5.background("#FFF");
q5.colorMode(q5.HSB, 100);
// q5.noFill();
q5.noStroke();

// q5.fill("black");

while (true) {
if (clear) q5.clear();
simulation.nodes().forEach((n, i) => {
q5.fill(n.color);
q5.stroke(n.color);
// q5.circle(n.x, n.y, n.r * (t * n.trate));
q5.circle(n.x, n.y, n.r);
});
yield el;
}
}
Insert cell
simulation = {
more;
const simulation = d3
.forceSimulation(nodes)
// .force("center", d3.forceCenter(width / 2, height / 2))
// .force("charge", d3.forceManyBody().strength(-0.12))
.force(
"collide",
d3
.forceCollide()
.radius((d) => {
return d.r * 0.96;
})
.strength(0.1)
)
.alpha(alpha)
// .alphaMin(0.0001)
.alphaDecay(0.0001)
.velocityDecay(0.001)
// .velocityDecay(0.1)

.on("tick", () => {
nodes.forEach((n) => {
const newVelocity = 0.5;
// n.r += _.clamp(simulation.alpha() * 0.05, 0, 100);
n.r += 0.12;
if (chance.bool()) n.vx += chance.floating({ min: -0.1, max: 0.1 });
if (chance.bool()) n.vy += chance.floating({ min: -0.1, max: 0.1 });
const nodeColor = d3.hcl(n.color);
nodeColor.h += chance.floating({ min: -0.18, max: 0.18 });
// nodeColor.l += 0.25;
nodeColor.l -= chance.floating({ min: -0.2, max: 0.2 });
n.color = nodeColor.hex();

let goodX = Math.max(n.r, Math.min(width - n.r, n.x));
let goodY = Math.max(n.r, Math.min(width - n.r, n.y));
// goodX > n.x ? (n.vx -= newVelocity) : (n.vx += newVelocity);
// goodX > n.y ? (n.vy -= newVelocity) : (n.vy += newVelocity);
// n.x = goodX;
// n.y = goodY;
});
});
return simulation;
}
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
function makeNode(i = 0) {
const startMargin = 25;
const maxV = 2500;
const nodeColor = chance.pickone(colors);
return {
// x: width / 2,
// y: height / 2,
// x: chance.integer({ min: 0, max: width }),
// y: chance.integer({ min: 0, max: height }),
x:
width / 2 +
chance.integer({ min: -width / startMargin, max: width / startMargin }),
y:
height / 2 +
chance.integer({ min: -height / startMargin, max: height / startMargin }),
vy: chance.floating({ min: -maxV, max: maxV }),
// vx: 0,
// r: chance.integer({ min: 1, max: width / 32 }),
r: totalNodes * 0.333,
// color: chance.pickone(colors)
color: nodeColor
};
}
Insert cell
nodes = {
more;
const nodes = [];
for (let nodeCount = 0; nodeCount < totalNodes; ++nodeCount) {
nodes.push(makeNode(nodeCount));
}
return nodes;
}
Insert cell
simulation.nodes()
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
palettes
Insert cell
colors = {
more;
const paletteName = chance.pickone(Object.keys(palettes));
return chance.pickone(palettes[paletteName]);
// return ["#000", "#FFF"];
// return ["#7bdff2", "#b2f7ef", "#eff7f6", "#f7d6e0", "#f2b5d4"];
}
Insert cell
_ = require("lodash")
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