Equatorial Orthographic Projection

This is the first post in a series of basic D3 tutorials aimed at visualizing different geographic projections. which are mathematical methods for flattening the sphere of the Earth onto a flat piece of paper or computer screen.

The first projection to be introduced is the equatorial orthographic projection. This is perhaps the most natural projection, as it depicts a hemisphere of the globe as it appears from outer space. We first saw our planet from this point of view in 1946, but this projection has been in use since the first century BCE.

Like all projections, the orthographic projection is not a perfectly accurate representation of reality. The shapes and areas of all landmasses are distorted — particularly near the edges — in an orthographic projection, which makes it unsuitable for visualization of navigation routes and comparative information.

In order to construct an orthographic projection in D3, we first need to define the projection and its attributes. A projection is a mathematical formula that transforms spherical coordinates (longitude/latitude pairs) found in geojson files into flat pixel coordinates. Here, orthographic projection math is used.

  • .center([180,180]) determines the spherical coordinate focal point of the plot
  • .scale(150) arbitrarily increasese and decreases the visualization's size
  • .translate(x,y) moves the center of the projection to a new position
  • .rotate([360,360,360]) spins the projection in three dimensions
  • .clipAngle(90) makes the opposite side of the Earth invisible
//setup our projection
<script>
var projection = d3.geo.orthographic()
    .center([0, 0])
    .scale(200)
    .translate([width/2,height/2])
    .rotate([0,0,0])
    .clipAngle(90)
;

It is also necessary to construct an svg drawing area, here appended to the body of the HTML page.

//make svg container
var width = 700;
var height = 700;

var svg = d3.select("body").append("svg")
    .style("width", width)
    .style("height", height)
;

One of the more confusing things about working with geographic displays in D3 are path generators, which take as input svg paths and output those same paths modified by a projection. As long as we pass all of our paths through the same generator, all of the geographic data will stay aligned and consistently distorted by the projection.

//load d3 path generator
var path = d3.geo.path()
    .projection(projection);

Adding a sphere to the svg area allows the styling of areas not defined in the topojson file. In this case, it is the entity that we fill and stroke for the ocean color, and for the outline around the Earth.

//create svg sphere to serve as background
svg.append("path")
  .datum({type: "Sphere"})
  .attr("d", path)
;

Often, it might be desirable to group the svg paths created by D3 for easier manipulation later on.

//create svg group to hold objects
var g = svg.append("g");

At last it is time to load the actual geographic data, which is in the form of a topojson file. The data is imported, and paths are produced based on features which are identified as "countries" in the file's header. Different topojson files found online will often have a unique identifier for their features.

// load world map!
d3.json("world-110m.json", function(error, topology) {
    g.selectAll("path")
      .data(topojson.object(topology, topology.objects.countries).geometries)
      .enter()
      .append("path")
      .attr("d", path)      
    })    
;

The final additions are simple graticules, spherical grid lines overlaid on the planet, to help with orientability.

//define and add graticules
var graticule = d3.geo.graticule()
                    .step([18, 18]);

g.append("path")
        .datum(graticule)
        .attr("d", path); 
;

Dragging will spin the visualization by dynamically adjusting the .rotation([]) values of our projection. The code for enabling this interaction will be the topic of the next tutorial.