by Tomislav Bacinger – Software Engineer @ Toptal
What is D3.js used for?
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:
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.
Geographic Data for D3
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
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
. 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
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!
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.