Data Driven Documents, or D3.js, is “a JavaScript library for manipulating documents based on data”. Or to put it more simply, D3.js is a data visualization library. It was developed by Mike Bostock with the idea of bridging the gap between static display of data, and interactive and animated data visualizations.

D3 is a powerful library with a ton of uses. In this tutorial, I’ll discuss one particularly compelling application of D3: map making. We’ll go through the common challenges of building a useful and informative web map, and show how in each case, D3.js gives capable JavaScript developers everything they need to make maps look and feel beautiful.

Use this D3.js tutorial to develop web maps

What is D3.js used for?

D3.js can bind any arbitrary data to a Document Object Model (DOM), and then, through the use of JavaScript, CSS, HTML and SVG, apply transformations to the document that are driven by that data. The result can be simple HTML output, or interactive SVG charts with dynamic behavior like animations, transitions, and interaction. All the data transformations and renderings are done client-side, in the browser.

At its simplest, D3.js can be used to manipulate a DOM. Here is a simple example where D3.js is used to add a paragraph element to an empty document body, with “Hello World” text:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>D3 Hello World</title>
    <script src="http://d3js.org/d3.v3.min.js"></script>
  </head>
  <body>
    <script type="text/javascript">
      d3.select("body").append("p").text("Hello World");
    </script>
  </body>
</html>

The strength of D3.js, however, is in its data visualization ability. For example, it can be used to create charts. It can be used to create animated charts. It can be even used to integrate and animate different connected charts.

D3 for Web Maps and Geographic Data Visualization

But D3.js can be used for much more than just DOM manipulation, or to draw charts. D3.js is extremely powerful when it comes to handling geographical information. Manipulating and presenting geographic data can be very tricky, but building a map with a D3.js is quite simple.

Here is a D3.js example that will draw a world map based on the data stored in a JSON-compatible data format. You just need to define the size of the map and the geographic projection to use (more about that later), define an SVG element, append it to the DOM, and load the map data using JSON. Map styling is done via CSS.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>D3 World Map</title>
    <style>
      path {
        stroke: white;
        stroke-width: 0.5px;
        fill: black;
      }
    </style>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="http://d3js.org/topojson.v0.min.js"></script>
  </head>
  <body>
    <script type="text/javascript">
      var width = 900;
      var height = 600;

      var projection = d3.geo.mercator();
      
      var svg = d3.select("body").append("svg")
          .attr("width", width)
          .attr("height", height);
      var path = d3.geo.path()
          .projection(projection);
      var g = svg.append("g");
      
      d3.json("world-110m2.json", function(error, topology) {
          g.selectAll("path")
            .data(topojson.object(topology, topology.objects.countries)
                .geometries)
          .enter()
            .append("path")
            .attr("d", path)
      });
    </script>
  </body>
</html>

Geographic Data for D3

For this D3.js tutorial, keep in mind that map building works best with data formatted in JSON formats, particularly the GeoJSON and TopoJSON specifications.

GeoJSON is “a format for encoding a variety of geographic data structures”. It is designed to represent discrete geometry objects grouped into feature collections of name/value pairs.

TopoJSON is an extension of GeoJSON, which can encode topology where geometries are “stitched together from shared line segments called arcs”. TopoJSON eliminates redundancy by storing relational information between geographic features, not merely spatial information. As a result, geometry is much more compact and combined where geometries share features. This results with 80% smaller typical TopoJSON file than its GeoJSON equivalent.

So, for example, given a map with several countries bordering each other, the shared parts of the borders will be stored twice in GeoJSON, once for each country on either side of the border. In TopoJSON, it will be just one line.

Map Libraries: Google Maps and Leaflet.js

Today, the most popular mapping libraries are Google Maps and Leaflet. They are designed to get “slippy maps” on the web fast and easy. “Slippy maps” is a term referring to modern JavaScript-powered web maps that allow zooming and panning around the map.

Leaflet is a great alternative to Google Maps. It is an open source JavaScript library designed to make mobile-friendly interactive maps, with simplicity, performance and usability in mind. Leaflet is at its best when leveraging the big selection of raster-based maps that are available around the internet, and brings the simplicity of working with tiled maps and their presentation capabilities.

Leaflet can be used with great success when combined with D3.js’s data manipulation features, and for utilizing D3.js for vector based graphics. Combining them together brings out the best in both libraries.

Google Maps are more difficult to combine with D3.js, since Google Maps are not open source. It is possible to use Google Maps and D3 together, but this is mostly limited to overlaying data with D3.js over Google Maps background maps. Deeper integration is not really possible, without hacking.

Projections - Beyond Spherical Mercator

The question of how to project maps of the 3-dimensional spherical Earth onto 2-dimensional surfaces is an old and complex problem. Choosing the best projection for a map is an important decision to make for every web map.

In our simple world map D3.js tutorial above, we used the Spherical Mercator projection coordinate system by calling d3.geo.mercator(). This projection is also known as Web Mercator. This projection was popularized by Google when they introduced Google Maps. Later, other web services adopted the projection too, namely OpenStreetMap, Bing Maps, Here Maps and MapQuest. This has made Spherical Mercator a very popular projection for online slippy maps.

All mapping libraries support the Spherical Mercator projection out of the box. If you want to use other projections, you will need to use, for example, the Proj4js library, which can do any transformation from one coordinate system to another. In the case of Leaflet, there is a Proj4Leaflet plugin. In the case of Google Maps, there is, well, nothing.

D3.js brings cartographic projections to a whole new level with built-in support for many different geographic projections. D3.js models geographic projections as full geometric transformations, which means that when straight lines are projected to curves, D3.js applies configurable adaptive resampling to subdivide lines and eliminate projection artifacts. The Extended Geographic Projections D3 plugin brings the number of supported projections to over 40. It is even possible to create a whole new custom projection using d3.geo.projection and d3.geo.projectionMutator.

Raster Maps

As mentioned before, one of the main strengths of D3.js is in working with vector data. To use raster data there is an option to combine D3.js with Leaflet. But there is also an option to do everything with just D3.js using d3.geo.tile to create slippy maps. Even with just D3.js alone, people are doing amazing things with raster maps.

Vector Manipulation on the Fly

One of the biggest challenges in classic cartography is map generalization. You want to have as much detailed geometry as you can, but that data needs to adapt to the scale of the displayed map. Having too high a data resolution increases download time and slows down rendering, while too low a resolution ruins details and topological relations. Slippy maps using vector data can run into a big problem with map generalization.

One option is to do map generalization beforehand: to have different datasets in different resolutions, and then display the appropriate dataset for the current selected scale. But this multiplies datasets, complicates data maintenance, and is prone to errors. Yet most mapping libraries are limited to this option.

The better solution is to do map generalization on the fly. And here comes D3.js again, with its powerful data manipulation features. D3.js enables line simplification to be done in browser.

I want more!

D3 data visualization is a great solution for map building projects like this example.

D3.js is not easy to master and it has a steep learning curve. It is necessary to be familiar with a lot of technologies, namely JavaScript objects, the jQuery chaining syntax, SVG and CSS, and of course D3’s API. On top of that, one needs to have a bit of design skill to create nice graphics in the end. Luckily, D3.js has a big community, and there are a lot of resources for people to dig into. A great starting point for learning D3 is these tutorials.

If you like learning by examining examples, Mike Bostock has shared more than 600 D3.js examples on his webpage. All D3.js examples have git repository for version control, and are forkable, cloneable and commentable.

If you are using CartoDB, you’ll be glad to hear that CartoDB makes D3 maps a breeze.

And for a little bonus at the end, here’s one of my favorite examples showing off the amazing things D3 is capable of:

  • earth, a global animated 3D wind map of the entire world made with D3.js. Earth is a visualization of global weather conditions, based on weather forecasts made by supercomputers at the National Centers for Environmental Prediction, NOAA / National Weather Service and converted to JSON. You can customize displayed data such as heights for the wind velocity readings, change overlaid data, and even change Earth projection.

About the author

Tomislav Bacinger, Croatia
member since May 1, 2014
Tomislav is a cartographer and software engineer with extensive experience in data manipulation and creation of immersive interactive map visualizations and charts. He has excellent knowledge of various geospatial technologies and strong experience in design and development of web and mobile applications. He is flexible and able to integrate as a standalone freelancer or within teams. Maps and visualizations are his passion. [click to continue...]
Hiring? Meet the Top 10 Freelance JavaScript Developers for Hire in September 2016

Comments

rocky bush
Great post Tomislav! I have a requirement to setup a World map with connected line (arcs) between the countries/their cities using d3js + elasticsearch + node (needs server?). How can I setup and running up the server? Could you help me.
Saepul
how to manipulation polygon data on d3+google?
Julien Fraichard
The first map with the contour line is very nice. Can you share the data and the code of this map ?
comments powered by Disqus
Subscribe
The #1 Blog for Engineers
Get the latest content first.
No spam. Just great engineering and design posts.
The #1 Blog for Engineers
Get the latest content first.
Thank you for subscribing!
You can edit your subscription preferences here.
Trending articles
Relevant technologies
About the author
Tomislav Bacinger
JavaScript Developer
Tomislav is a cartographer and software engineer with extensive experience in data manipulation and creation of immersive interactive map visualizations and charts. He has excellent knowledge of various geospatial technologies and strong experience in design and development of web and mobile applications. He is flexible and able to integrate as a standalone freelancer or within teams. Maps and visualizations are his passion.