The Making of a Stacked and Animated Map

Remember that time when we mapped and animated the 2018 Formula 1 racing circuits?

You know, it had that wild, neon pink, retro color scheme…

Formula 1 screenshot

I promised to “walk through how D3 and flubber were used to make all this come together”.  Well then, we’ve arrived here, and along the way we looked at how to begin making web maps in D3 followed by how to wrap your mind around web map projections.  Be sure to check out those posts, too.  The concepts build on top of each other in the hopes of making this one easier to digest.

Getting to the main point:

How do you stack and animate geographical features that are located in different places?

Map projections play an important role in this technique.  I chose to project the Formula 1 circuits using the Mercator projection because it is good at maintaining the shapes of small features, specifically when rotated to each feature’s centroid and zoomed in closely.  Mercator thus is “conformal” in projection terminology.  And since it can be a pain to remember: zooming in closely on a map means using a large, local map scale.

I’ve broken out the inner workings of the stacking and animating technique into 3 separate parts which are very much alive and kicking in the CodePen demos below.  Each Formula 1 circuit is first translated from geographic coordinates to SVG space (projected) by rotating and scaling the Mercator projection to every one of these circuit features.  This is what fundamentally makes them appear stacked because they now occupy the same area of the SVG element.  Finally, instead of showing all of them at once, we only show one circuit’s shape at a time and animate to the shape of the next circuit in the stack.

Part 1: A two-dimensional globe is drawn with an orthographic projection to show how projections can be rotated to specific locations on Earth.  In the bottom area of this demo–using the Mercator projection with a large map scale–we also rotate to each circuit’s centroid location and then add the circuit to the stack.

See the Pen Stacking & Animating Formula 1 Circuits in D3 (Part 1) by Jacob Wasilkowski (@jwasilgeo) on CodePen.

Part 2: Skip the leisurely world tour and immediately make a stack of circuits.  Again, each circuit is drawn as an SVG <path> element with the assistance of a uniquely rotated Mercator map projection.

See the Pen Stacking & Animating Formula 1 Circuits in D3 (Part 2) by Jacob Wasilkowski (@jwasilgeo) on CodePen.

Part 3: By now we know how to quickly create a stack of disparate geographic features. The focus in this final demo is on the animation that morphs between all the circuits’ shapes using the flubber JavaScript library.

See the Pen Stacking & Animating Formula 1 Circuits in D3 (Part 3) by Jacob Wasilkowski (@jwasilgeo) on CodePen.

Map Projections on the Web

Following our tutorial on creating maps in the browser–Get Started Creating D3 Maps–I thought it would be fun to explore map projections on the web with JavaScript.  D3 in particular gives us the opportunity to be very creative in how we render geospatial data with the ability to choose from and customize many different projections.

See the Pen D3 Projected Halftone Pattern by Jacob Wasilkowski (@jwasilgeo) on CodePen.


Reduce those dimensions

Locations of our geospatial data exist somewhere on our three-dimensional planet, but we have to make two-dimensional maps for our flat electronic screens (or pieces of paper!).  Deciding which map projection to use is an exercise in telling your data how it needs to bend, twist, rip, and transform from a three-dimensional reality to a two-dimensional medium.

Different map projections exist for different reasons and any choice made is a trade-off for which property you’d like to preserve from your original data, including area, shape, angle, or distance.  For example, if you need to maintain the correct areas of countries, then you may have to give up caring about their shapes becoming distorted.  (This would be called an equal-area projection, by the way.)  There is no perfect map projection to fit all situations.

Center or rotate a web map?

Most of the web maps we interact with use some variation of the Mercator projection. It is known as a conformal projection and nearly always is rotated in a way that is visually very familiar and comfortable to us: north is up, south is down, and land masses closer to the poles are distorted in area and appear much bigger than they actually are.

Moving around on this kind of web map changes the center location, which is similar to shifting a paper map around on a table.  When you navigate up to view Greenland in a web map, it would be like moving a paper map down, right?  Greenland’s area is still distorted and bloated.

But when you interact with a globe in real life you rotate it.  The same is actually possible for all map projections, and in D3 we can rotate along 3 different axes.  If the world’s landmasses look unfamiliar when rotating a map’s projection it doesn’t mean we are doing something wrong.  Perhaps unconventional, but not necessarily wrong.  Our three-dimensional data is simply being instructed how to reshape itself onto a two-dimensional map.  If we were to rotate the same example web map to Greenland its area would be much more accurate, but at the cost of other landmass areas becoming distorted.

Here’s a demo showing the differences between centering and rotating.  The top row uses the Mercator projection while the bottom uses the Orthographic projection which resembles a globe (but a flat globe in 2-D).

See the Pen D3 Map Projections: Centering vs. Rotating by Jacob Wasilkowski (@jwasilgeo) on CodePen.

Circles, circles everywhere

What if we were gods and could sculpt perfectly circular islands of the same size and then place them evenly around the planet?  I suppose even on our best days we don’t have this power–sorry–but we can at least draw them on a map.  These regularly spaced circles, called Tissot’s indicatrices, show the unique distortions of each projection by stretching, warping, and also moving the circles around.

The regions in the next demo that contain evenly distributed, small circles exhibit very little or no distortion.  But as the circles grow, morph into other shapes, or move away or closer together, we are given visual cues about how the distortions of a projection affect the sizes, angles, and distances between geographical features throughout the map.

See the Pen D3 Map Projections by Jacob Wasilkowski (@jwasilgeo) on CodePen.

Which one is your favorite?  Are any of these cool enough to be a tattoo?

Go make some maps

If you want to experiment with map projections, visit Get Started Creating D3 Maps and start making changes to the Canvas demo or SVG demo.

Look for the JavaScript code block starting with var projection = d3.geoMercator() and replace it with another projection documented at d3-geo, d3-geo-projection, or perhaps d3-geo-polygon.

Learn more

Have fun distorting the shape of the world!

Get Started Creating D3 Maps

JavaScript is fun, and D3 is great.

At Petrichor Studio we like to use D3 for our interactive, web-based visualizations.

As I promised recently, we’ll spend time talking about making maps with this wildly popular JavaScript visualization library.

D3 is sometimes known for imposing a learning curve on dataviz folks and JavaScript developers, but I am convinced that once you’ve tried it out several times–regardless of success or failure–familiar patterns will start emerging in the code.  There are plenty of wonderful resources and blogs that were crucial in helping me begin to understand how to harness D3, and I have included some links at the end of this post in case they might help you out, too.

Below are a couple code samples to help you get started making a simple world map in your browser.  One approach shows you how to render GeoJSON data in your browser as graphics using SVG, while the other approach uses Canvas.  They can be compared side-by-side and I encourage you to identify their similarities and differences.

The overall pattern goes like this

  1. Set up the element that will render the graphics of your map.  Choose <svg> or <canvas> and give it an initial width and height.
  2. Establish the map projection.  We want to make a two-dimensional map, but our geographical features exist on a three-dimensional planet.  We’re going from longitude/latitude coordinates to a flat map and D3 needs to know how that should happen.  Read up on Map Projections on the Web when you’re ready.
  3. Create a D3 geographic path generator and tell it about the map projection.  This is the workhorse that instructs SVG or Canvas how to create two-dimensional graphics out of GeoJSON data.
  4. Load your spatial data.  The samples below use a network request to load publicly available world country geometries in the TopoJSON format.  TopoJSON is more or less a special format of GeoJSON.  It just takes 1 extra step to convert from TopoJSON to regular GeoJSON.  No big deal.
  5. Use the geographic path generator to convert your data into graphics.  The longitude/latitude coordinates will be drawn as map graphics in the <svg> or <canvas> element.

Simple D3 Map using SVG

See the Pen Simple D3 Map using SVG by Jacob Wasilkowski (@jwasilgeo) on CodePen.

Simple D3 Map using Canvas

See the Pen Simple D3 Map using Canvas by Jacob Wasilkowski (@jwasilgeo) on CodePen.

If you are just getting started with D3 the best advice I can give is simply what worked for me: read other people’s tutorials and code samples, all while experimenting on your own until perceived failures become replaced with tiny successes. The tiny successes will become bigger over time and failures won’t seem so scary or annoying anymore.

Good luck! We’ll revisit these topics in more depth by focusing on Map Projections on the Web.

Helpful resources

“Bring Up State” Animation Effect with D3

*Check out our What’s Your Vote Worth? data viz storytelling to see this effect in action.

Tired of falling down into web maps?

Zooming in, zooming in, and zooming in from outer space down to the Earth’s surface got you feeling sad?

Here’s another idea: demand that geographic features come up to you. Web maps typically require you to zoom in and may give the sensation of “falling down” or “diving in” towards the Earth’s surface. Why not make this everyday interaction become more user-focused?

Click on a state to get started.

See the Pen Bring Up State – D3 by Jacob Wasilkowski (@jwasilgeo) on CodePen.

In this JavaScript code sample written with D3js, called “Bring Up State”, we serve—provide, give, deliver—a state polygon that has been clicked on to give it full focus. This is the opposite from expecting your audience to freely zoom in as with traditional web map experiences. This sample goes one step further by fading away the remaining states in the background to alleviate visual clutter and bring attention to the current state. Take a look at the code to see how it is all glued together.

Just click—no need to fly down closer to the Earth—and the visualization will do the heavy lifting of bringing up the geographical feature directly to you.

Flow Mapping Bezier Curves onto the HTML Canvas

*This post was written in February 2017. It was the first collaborative geovisual project between Jacob and myself. We have since presented this mapping method at the North American Cartographic Information Society annual conference in Montreal, Quebec in October 2017.

This post presents our Canvas-Flowmap-Layer, an extension of the ArcGIS API for JavaScript (Esri JSAPI) for the purpose of mapping the flow of objects from an origin point to a destination point by using a Bezier curve. Collaboration with friend and colleague, Jacob Wasilkowski, was precisely the push I needed to finally (re)begin releasing some (non-work-related) mapping and dataviz projects into the wild. It is imperative to note that much of the responsibility for this repo rests on Jacob’s shoulders, even though it is under my name.

Flow maps, academically speaking

In Bernhard Jenny et al.’s recent article Design principles for origin-destination flow maps(2016) flow maps are defined as maps that “visualize movement using a static image and demonstrate not only which places have been affected by movement but also the direction and volume of movement” (p 1). Jenny et al.’s article points out the lack of empirical user studies for flow map design, stating that “Design principles for flow maps are largely based on expert intuition and aesthetic considerations” (p. 1). I am the type of cartographer who finds extreme liberation in these two aforementioned points, which I will restate below:

The lack of empirically based cartographic design principles results in the freedom of relying on intuition and aesthetics.

So for all the mappers out there reading this, I hope you find extreme freedom in knowing that this Canvas-Flowmap-Layer is only one of many ways to map the journey of phenomenon from one spot on Earth to another. It is one method that we are quite comfortable in presenting, and have successfully implemented versions of the Canvas-Flowmap-Layer in a few real world scenarios.

Curves with Rules

Common solutions for dynamic flow mapping include using straight lines and geodesic lines, both of which have immediate visual limitations. Using a Bezier curve for flow map lines, where each curve on the map is created with the same formula benefits mappers twofold:

  1. While straight lines are not inherently ugly, an overlapping or convergence of them across a global dataset can be. A series of Bezier curves created with the same formula, even when displaying an over-abundance, has a mathematically congruent flow that greatly improves the map’s aesthetics.

2. The single formula that is used to draw each of the Bezier curves means that map readers can immediately know the direction of the line without having to add animation (explained below).

RULE DEFINED

Ultimately, the flow line’s direction from the origin is the order of the bend (a northwest direction’s curve bends north-then-west)

  • northwest from the origin, the curvature will bend northward-then-west
  • southwest from the origin, the curvature will bend southward-then-west
  • northeast from the origin, the curvature will bend northward-then-east
  • southeast from the origin, the curvature will bend southward-then-east

As you can see from the image below, if the end point is due north (or south, east, or west) of the origin, the resulting curve is a straight line.

THE POINTS

Each point is added to the map twice – the first instance of each point is an invisible “ghost” Esri graphic with associated attribute data, geometry, etc. We call these “ghost” graphics since the symbology has no outline or fill color. These ghost graphics are required for 1) having a to- and from- point from which to connect the Bezier curve, and 2) allowing the points to provide functionality and interactivity that developers and users are familiar with.

The second instance of the points is what you actually see on the map. Each one of these points has the same radius as their ghost counterparts that lie directly beneath them, but are created by finding the screen coordinates of the ghost graphic and then placing them onto the HTML canvas. By doing this, we are able to draw the curved lines that connect the points onto the canvas.

THE LINES

I was drafting Bezier curves onto prototypes before this became an actual interactive map layer. Once it came time to add the curves to the map canvas there was no shortage of resources for figuring it out. Here is one of the many useful out there. The lines are added to the HTML canvas by finding the screen coordinates of the points, and then using those coordinates in the .bezierCurveTo() canvas method.

LINE ANIMATION

The convexity or concavity of the curve does convey the direction of the flow line, but the directionality won’t be easily intuited due to its novelty. In the event that this mapping technique catches like wildfire, we can delete the second part of the previous sentence. In the meantime, we’ve added line animations, similar to the “ants marching” effect, with a nice easing effect inspired by this Kirupa post. The Canvas-Flowmap-Layer uses two separate lines when animation is added, although two lines are not required to achieve animation. The first line is the solid static Bezier curve, and the second line is the dotted or hashed animated Bezier curve that sits on top of the first line. Those animated traveling dots are actually a curved line with really a  big gap setting in the hash pattern.

 

 

Demos and code

You’ll find out a lot more about how the Canvas-Flowmap-Layer was constructed by diving into the code, and checking out the comparison and main demos.

Limitations

Projection – This is not a limitation, just a bit of information. This particular instance of using a single formula Bezier curve for flow mapping onto the canvas was implemented with Web Mercator projection. This cartographic method is not limited Web Mercator, provided that you are mapping a projected map and grabbing the correct screen coordinates from your start and end points.

Connection vs. route – The Canvas-Flowmap-Layer is ideal for the flow of things, where the route can be abstracted to a simple conveyance of start point connected to end point. Our data did not contain route information. When mapping thematically for things like the flow of ideas, phone calls, or even the logistical flow of things that – while they do take an actual route – can be reduced to its mere start-end connectivity. (In fact, oftentimes adding actual routes can clutter the map with chart junk). There are things to note, though, when giving precedence to connectivity over actual route. Namely, for example, when you have things from Seattle being shipped to Tokyo, but the flowline travels across Europe, Kazakhstan, and China on its way to Tokyo, when the shipment might have actually traveled across the Pacific Ocean. Jacob has cleverly built in a cool feature where the flowline updates as you pan the map so that most/all of each flowline can be viewed (at the small scales). It is totally feasible to add this sort of directional information to your data (where true direction matters). It might be pretty prudent to restrict users to your dataset’s minimum and maximum extent as much as possible. We didn’t add that restriction to our sample maps.