Public
Edited
May 20, 2022
2 stars
Insert cell
# 2D Gravity
Insert cell
<div style="display: flex; justify-content: center; align-items: center; margin: 20px;">
<svg></svg>
</div>
Insert cell
Could improve this animation by adding z-indexes and detecting when distances switches from increasing to decreasing to toggle them in front of / behind the center(s) of gravity
Insert cell
Could make this more fun by adding more centers of 2D gravity
- makeGravity would iterate over each particle, each gravity to update coordinates
Insert cell
function initGravity() {
const svgWidth = 400,
svgHeight = 400,
halfWidth = svgWidth / 2,
halfHeight = svgHeight / 2,
particleIndex = 10,
randomColor = () =>
"#" + ((Math.random() * 0xffffff) << 0).toString(16).padStart(6, "0");

const dataset = {
gravity: { x: 0, y: 0, r: 60, fill: "black" },
particles: []
};

const svg = d3
.select("svg")
.attr("width", svgWidth)
.attr("height", svgHeight)
.style("border", "1px solid black");

for (let z = 0; z < particleIndex; z++) {
dataset.particles.push({
x: Math.floor(Math.random() * svgWidth),
y: Math.floor(Math.random() * svgHeight),
fill: randomColor(),
r: 10,
velocity: {
x: Math.floor(Math.random() * 1 - 1),
y: Math.floor(Math.random() * 1 - 1)
}
});
}

function makeGravity() {
const { gravity } = dataset;

dataset.particles = dataset.particles.map((p) => {
const particle = Object.assign({}, p);

const distance =
Math.pow(particle.x - gravity.x, 2) +
Math.pow(particle.y - gravity.y, 2);
const f = 1 / Math.sqrt(distance);

particle.velocity.x += (particle.x - gravity.x) * f;
particle.velocity.y += (particle.y - gravity.y) * f;

particle.x -= particle.velocity.x;
particle.y -= particle.velocity.y;

return particle;
});

svg.selectAll("circle").remove();

svg
.selectAll("circle")
.data([dataset.gravity, ...dataset.particles])
.enter()
.append("circle")
.attr("cy", (d) => d.y + halfHeight)
.attr("cx", (d) => d.x + halfWidth)
.attr("r", (d) => d.r)
.attr("fill", (d) => d.fill);

setTimeout(makeGravity, 50);
}

makeGravity();
}
Insert cell
setTimeout(initGravity, 1000)
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