block by harrystevens 2317dd4dc93afc4c988c5fc8bbc6ee4f

Spin the Earth

Full Screen

Drag your mouse vertically to spin the Earth. Drag it to the bottom of the frame (100%) to view Antarctica; drag it to the top (0%) to search for Santa.

This map uses an orthographic projection with D3.js and Topojson to draw a map of the world’s countries onto a spinning globe, rendered here with a graticule that is 10° by 10°.

The world countries polygons were downloaded from ArcGIS.

index.html

<!DOCTYPE html>
<html>
  <head>
    <style>
    body {
      font-family: "Helvetica Neue", sans-serif;
      margin: 0;
    }
    </style>
  </head>
  <body>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://d3js.org/topojson.v1.min.js"></script>
    <script>
    var width = window.innerWidth, height = window.innerHeight;

    var projection = d3.geoOrthographic()
        .scale(width / 4.1)
        .translate([width / 2, height / 2])
        .precision(1);

    var path = d3.geoPath()
        .projection(projection);

    var svg = d3.select("body").append("svg")
        .attr("width", width)
        .attr("height", height)
        .style("cursor", "ns-resize");

    var g = svg.append("g");

    var graticule = d3.geoGraticule()
        .step([10, 10]);

    g.append("path")
        .datum(graticule)
        .attr("class", "graticule")
        .attr("d", path)
        .style("fill", "none")
        .style("stroke", "#ccc");

    var ph = d3.scaleLinear()
        .domain([0, height])
        .range([270, -270]);

    var y = height / 2;

    svg.append("line")
        .attr("class", "line")
        .attr("x1", 0)
        .attr("x2", width)
        .attr("y1", y)
        .attr("y2", y)
        .attr("stroke-dasharray", "5, 5")
        .style("stroke", "steelblue")
        .style("stroke-width", "2px");

    svg.append("text")
        .attr("class", "text")
        .attr("x", 10)
        .attr("y", height / 2)
        .attr("dy", -5)
        .attr("fill", "steelblue")
        .text("50%");

    svg.on("mousemove", function(){

      var y = d3.mouse(this)[1];

      d3.select(".line")
          .attr("y1", y)
          .attr("y2", y);

      d3.select(".text")
          .attr("y", y)
          .text(Math.round(y / height * 100) + "%");

    });

    d3.timer(function(elapsed) {

      projection.rotate([.05 * elapsed - 120, ph(d3.select(".line").attr("y1")), 0]);
      g.selectAll("path").attr("d", path);

    });

    var c = d3.scaleOrdinal(d3.schemeCategory20);

    d3.json("countries.json", function(error, data){

        g.selectAll(".subunit")
          .data(topojson.feature(data, data.objects.polygons).features)
        .enter().append("path")
          .attr("class", "subunit")
          .attr("d", path)
          .style("stroke", "#fff")
          .style("stroke-width", "1px")
          .style("fill", function(d,i){ return c(i); })
          .style("opacity", ".6");

    });
    </script>

  </body>
</html>