D3 World Maps: Tooltips, Zooming, and Queue

Mapping with D3

Update: I highly recommend checking out this responsive D3.js framework with pan and zoom limits and the new D3 World Map Template.

D3 has a lot of built in support (a powerful geographic projection system) for creating Maps from GeoJSON. If you have never used D3 for maps, I think you should take a look at this D3 Map Tutorial. It covers the essentials of making a map with D3 and TopoJSON, which I will use below in more advanced examples. TopoJson encodes topology and eliminates redundancy, resulting in a much smaller file and the GeoJSON to TopoJSON converter is built with NodeJS.

Thus, I encourage you all to start using TopoJSON and below, I will go over a couple examples of building a D3 World Map with colors, tooltips, different zooming options, plotting points from geo coordinates, and listening to click events to load new maps. I will also use Mike Bostock’s queue script to load the data asynchronously.

D3 World Map with Country Tooltips and Colors

Let’s start with something basic. We want a world map in TopoJSON so I have selected the world-110m.json from the TopoJSON examples folder. We also need a data file for world country names and you can find a TSV version here. Coloring in the map was pretty simple, I have used the D3 categorial colors function and a style attribute. If you want to make sure that no adjecent countries have the same color you can use the function in this World Map Color Example. I selected the mercator projection and used the queue asynchronous library mentioned above to load all the data. At the end of my ready function, I attached a mousemove and mouseout events to every country which populate and show the tooltip with the correct country name inside. Take a look at the example to see how it all works with queue, colors, and tooltips.

D3 World Map with Smooth Mouse Zooming

So, that was easy but now I want to add zooming functionality. It is also pretty straightforward as D3 has zoom behavior and on zoom you can call a redraw function which will zoom into the map. Take a look at the demo and notice how I only added a couple of lines around 64-71 which is all that is needed for zoom functionality. You can use your mouse wheel or doubleclick on any area in the map. I changed the thickness of the borders to .1 stroke-width because that looks better when you zoom in and I also realized that once you zoom in a lot, there is a lack of detail with the world-110.json map. I threw in the world-50m.json map and it looked much better but there were 5 problematic areas above Alaska which would not match on any country name. I am guessing that this is just bad data in the world-50m.json map as I cannot even locate any land or islands above Alaska in Google Maps. So, I added a hack: just a conditional that skips over 5 points where country name is undefined.

D3 World Map that Zooms to each Country on Click

You might have seen some examples of zooming into a country so I also wanted to show an example of how to build a world map where you can click on a country and it zooms into the right area. Mike Bostock’s provided a good answer on StackOverflow which explains how to center a map to a geoJSON object and this zoom to bounding box example is a great starting point. Instead of using the map of US, I have added the changes to my world map example and it now zooms on mouse click into each country. Check out the demo. The changes are really just two extra functions for handling the mouse clicks, extra CSS, plus drawing an extra “rect” element to reset or zoom out.

After making this demo I realized that it doesn’t really work well for big countries like Russia or countries like US where Alaska and Hawaii are specially separated from the mainland. You could, however, create an event listener on the zoom and load a new country map once the user has zoomed in for further detail (something like the map here). I have started working on this and have created a demo that works with clicking into United States and clicking out. In order to finish it, you would need to generate all the appropriate topoJSON maps for each country.

D3 World Map with Zoom, ToolTips, and Data Points

Going back to the regular zoom behavior, I wanted to finally show how you would add geo locations or data points to the map. Since we are working with a world map it makes sense to throw in the country capitals according to their latitude and longitude values. For the purpose of the demo, however, I have selected 3 random cities in the world and put them into a JSON object. It is important to note that longitude goes first when you define the geo coordinates for D3. Plotting them on the world map is also pretty simple, you just loop through that JSON object and transform the geo coordinates according to the projection you are using. Check out the demo and look at lines 133-140 to see how I did it. This example was quite helpful in plotting latitude and longitude points on a mercator projection.

I’m hoping this is helpful to someone trying to build maps with D3.

External:

Natural Earth Tables
Natural Earth Data in Google Maps
Natural Earth vectors in the cloud
Clean Up for Natural Earth GeoJSON
Airport, airline and route data
Flows of refugees between countries
Colors in D3.js
Human Footprints Map
Migrations Map
Chrome Browser Percentage Map with Raphael
World Borders Dataset
Expanded Gallery of ArcGIS Online Map Data
D3.js Geo fun
Map Projection Transitions
More GEO Mapping examples with D3
Japan GeoJSON in D3 with mouseover
Hierarchical Timeline Data with D3 and EmberJS

Facebook Twitter Hacker News Reddit More...
  • Paul Jones

    This is great. i am building a map with smooth zoom and panning functionality similar to the one you show above. I notice that you can zoom to the point that the map is very tiny. I also see that you can pan the map completely off the screen. Do you know if there is a way to bound the map so that is will only zoom to certain levels and will not pan of the screen?

  • Paul Jones

    This is great. i am building a map with smooth zoom and panning functionality similar to the one you show above. I notice that you can zoom to the point that the map is very tiny. I also see that you can pan the map completely off the screen. Do you know if there is a way to bound the map so that is will only zoom to certain levels and will not pan of the screen?

    • iweczek

      Hi Paul. I have controlled zoom levels by putting an if statement in the redraw function and checking if d3.event.scale is more or less than some value. However, D3 zoom behavior does provide a zoom.scaleExtent setting that you can set. So, I would use that.

      In terms of limiting pan, that is more tricky because it depends on scale. Inside the redraw function, which listens to any pan that you do, you can grab and limit the position by looking at d3.event.translate, however the values there will change with scale. Also, there are some other issues with doing it that way.

      Mike Bostock has an example which shows how to constrain panning and zooming: https://github.com/zmaril/d2p/blob/master/examples/mercator/mercator-zoom-constrained.html

      • Paul Jones

        Thank you so much. I think that will do just what I need.

  • Tyler Fisher

    Any thoughts on how to make the mouse position adjust when you pan/zoom? Every d3 map I’ve tried does not do this, and it makes the tooltip location inaccurate in a zoomed/panned state.

  • ljegou

    Please consider using another projection than Mercator. Mercator was invented several centuries ago for sailors, and is very misleading about continent surfaces and positions. D3 has the great advantage of proposing many modern and beautiful projections, as EckertIV or Robinson.

  • Dylan MacDonald

    This map renders great in IE9: http://techslides.com/demos/d3/d3-world-map-zoom-points.html

    I noticed, however, that when I downloaded your code locally and used the latest D3 (v. 3.3.6 min, direct from d3.org) vs the one you seem to be using (v. 3.04 min), I get an Invalid Argument error related to “return this.insertBefore” in IE9. Any ideas how to resolve?

    • iweczek

      Honestly, I am not sure what has changed between the d3.js version I use (older) and the latest. I assume that it is probably something with topojson.js file. Either way, I highly recommend using the responsive D3 framework I setup here (which should work with latest): http://techslides.com/responsive-d3-map-with-zoom-and-pan-limits/

      • Dylan MacDonald

        I found that the error crops up in d3 ver. 3.2.4 (3.2.3 is fine). I email Mike Bostock about it. Thanks for the pointer to the framework you made.

  • Martin

    The map with the zoom in and out is amazing. Do you have a map with links that will bring you to another page, for example when you click on USA you will open a a page with some info about the country?
    Than you

  • Cristian Andrei

    Your map models are amazing and I would like to discuss about buying one of them, with certain modifications for my own use. Please contact me on cristianandrei6@gmail.com