{
replay;
const width = 600,
height = 200,
movers = cm.range(20).map((d) =>
object({
location: cm.vec(cm.random(width), cm.random(height)),
velocity: cm.vec(cm.random(-1, 1), cm.random(-1, 1)),
acceleration: cm.vec(),
mass: cm.random(2, 5),
G: 0.4
})
);
function update(app) {
app.append(cm.clear, { fill: cm.rgb(255) });
app
.data(movers)
.process(cm.each, (i) =>
app
.data(movers)
.process(cm.filter, (j) => i !== j)
.process(cm.each, (j) => attraction(j)(i))
)
.process(cm.each, move)
.append(cm.circle, {
x: (d) => d.location.x,
y: (d) => d.location.y,
r: (d) => d.mass * 2,
fill: cm.rgb(175),
stroke: "#000",
strokeWidth: 2
});
}
function dispose(app) {
invalidation.then(() => app.dispose());
}
function frame(app) {
app.node().style.border = "solid #000 1px";
}
return cm
.app({ width, height })
.on("update", update)
.call(dispose)
.call(frame)
.start()
.node();
}