This post is easiest to read in landscape mode

Use the Force

Speeding up force simulations with spirals

One of the most enjoyable parts of the d3.js API is the d3-force module.

Using d3-force, we can create a force simulation that gives life to basic particles, moving them according to basic physical rules.

For example, say we have an array of 100 points at [0, 0].

Let's visualize them all!

Hmm, that was a little underwhelming, wasn't it?

Let's add some physical forces to prevent our dots from overlapping, so we can see them all at once.

Fun! We run into an issue, however, when we have more particles to animate.

For example, let's look at how things run when we have 600 dots to animate.

Oh boy, this simulation took ... seconds.

Instead, let's space our dots out by arranging them in a spiral.

How do I generate a spiral?
tap to show code
1.
const getSpiralPositions = (
2.
pointRadius=5, n=100, angleDiff=3, distance=1.5
3.
) => {
4.
let angle = 0
5.
return new Array(n).fill(0).map((_, i) => {
6.
const radius = Math.sqrt(i + 0.3) * pointRadius * distance
7.
angle += Math.asin(1 / radius) * pointRadius * angleDiff
8.
angle = angle % (Math.PI * 2)
9.
return {
10.
x: Math.cos(angle) * radius,
11.
y: Math.sin(angle) * radius,
12.
angle,
13.
}
14.
})
15.
}

Perfect! Let's compare our naive approach with starting our dots in a spiral configuration.

The astute reader might notice that we could just create a spiral with zero overlap, and we wouldn't need a simulation to space out our dots.

In fact, this behavior is built right into d3.js! Examining the code will show that d3 will initialize points in a Phyllotaxis arrangement when no initial x or y value is specified.

Duration:
0.0
seconds

The default Phyllotaxis arrangement is a great option if your dots are around 3-5 pixels in radius and you want them to start around [0, 0].

While this makes sense for our simple demo, the real world is often more complex. I needed both in a recent project where I was displaying a dynamic number of dots over different countries. But some countries' spirals were overlapping!

This method could also be useful for dynamically sized dots. I hope you find this technique useful, and I can't wait to see how you use it!