Animating Maps with D3 and TopoJSON
An easy, lightweight path-animation technique inspired by the NYT
Not long ago, it became possible to create maps using Mike Bostock’s D3.js and TopoJSON, a library that brings maps into the SVG world. This started a new era of plain and simple maps. If we need to create a quick visualization of average personal income per state in the USA, it’s extremely easy with D3.js and TopoJSON. Just take the USA states JSON shape file, drop in D3.js, and add some CSS, and a nice-looking static map is done. But what if we want it to be dynamic?
Last year the New York Times interactive news team came up with a clever idea how to make SVG maps move. In their The Russia Left Behind feature they created a path of the railway between Moscow and St. Petersburg that gets filled with color as we scroll through the the page. To me this was an amazing approach to keep the reader informed of where in the feature they are.
How It Works
I was working on The Welcoming Face of North Korea when the The Russia Left Behind was published, so I decided to find out how the New York Times feature was made to see if I could use the same approach. It turned out that the solution was very elegant. Apart from D3.js and TopoJSON that were used to create the path and render the names of the towns along it, the only thing that was needed to fill it with color was the
stroke-dasharray attribute of the
path element in SVG. This attribute was introduced to allow designers create custom-dashed styles of paths. The value of the attribute is a comma-separated list of number pairs: length of the dash and length of the gap.
When used creatively, this property can control the fill volume of the path.
This is exactly what the New York Times team did: They created two path elements with the same data and two different colors, where one sits on top of the other. The
stroke-dasharray attribute of the second visited element is filled in proportion to the current position of the scroll position of the page.
dashed value = ((vertical offset of the map - top of the map) / height of the map) * path length
Putting It All Together
The North Korea story I was working on covered several destinations within a single trip. I wanted to link the parts of the story together with an animated map. What I ended up doing was an extended version of the above method.
First, I wanted to make a minimalist map of North Korea and neighboring countries. To create it I used TileMill, which (as experienced users will know) comes with a CSS-like language to create map styles and understands data in Shapefile format. By default, MapBox comes with a public domain data source that includes shapes of the land of all the countries in the world and their international borders. It also includes several map styles that are easy to modify. After a bit of fiddling with it I got a nice looking map that I exported as a PNG image. TileMill lets you adjust geographical coordinates of the exported rectangle.
Then I needed the routes of the trips that the tourist group we were tracking in our story took during their visit, as well as coordinates of the key towns they visited. I used Google Earth to put in markers and draw the paths, then exported these features as a KML file, converted this file to GeoJSON using the ogr2ogr tool, and converted the result to TopoJSON format with topojson utility.
Once I had both the map image and trip paths, it was relatively easy to put them all together as SVG. I rendered the map as image element and the trip routes as path elements twice, with different colors. To make the path move, in the
onscroll event handler I used the formula from the previous section to get the visited percentage of the path that was used to set the new
You can see it live on The Welcoming Face of North Korea page.
Founder @flystein | Photo-videography | digital storytelling | digital nomad.