block by jczaplew 6603431

Adaptive Composite Map Projection example

Full Screen

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>Adaptive Composite Map Projection (Lite)</title>
  <style>
  body {
    background: #fcfcfa;
    height: 500px;
    position: relative;
    width: 960px;
  }
  .stroke {
    fill: none;
    stroke: #000;
    stroke-width: 3px;
  }
  .fill {
    fill: #000;
  }
  .graticule {
    fill: none;
    stroke: #fff;
    stroke-width: .5px;
    stroke-opacity: .5;
  }
  .land {
    fill: #fff;
    stroke:#777;
    stroke-width:.75px;
  }
  .boundary {
    fill: none;
    stroke: #fff;
    stroke-width: .5px;
  }
  </style>
</head>
<body>
  <script src="//d3js.org/d3.v3.min.js"></script>
  <script src="//d3js.org/d3.geo.projection.v0.min.js"></script>
  <script src="//d3js.org/topojson.v1.min.js"></script>
  <script type="text/javascript">

  function pickProjection(scale, coords) {
    if (scale <= 1.5) {
      d3.select("#proj").text("Hammer");
      currentProj = "hammer";
      return d3.geo.hammer()
         .coefficient(2)
         .precision(0.3)
         .scale(scale * 100)
         .rotate([coords[0],0]);

    } else if (scale <= 2.0) {
      d3.select("#proj").text("Modified Hammer");
      currentProj = "hammer";
      return d3.geo.hammer()
         .coefficient(2.0 - (scale-1.5) * 2.0)
         .precision(0.3)
         .scale(scale * 100)
         .rotate([coords[0],0]);

    } else if (scale <= 6.0) {
      d3.select("#proj").text("Lambert azimuthal");
      currentProj = "lambert";
      return d3.geo.azimuthalEqualArea()
         .scale(scale * 100)
         .precision(0.3)
         .clipAngle(180 - 1e-3)
         .rotate(coords);

    } else if (scale <= 12) {
        d3.select("#proj").text("Albers");
        currentProj = "albers";
        coords = (coords[0] == 0) ? [0.01, 0.01] : coords;
        return d3.geo.albers()
          .rotate([coords[0], 0])
          .center([0, -coords[1]])
          .parallels([ -coords[1] - scale, -coords[1] + scale])
          .scale(scale * 100)
          .translate([width / 2, height / 2])
          .precision(.1);

    } else {
      d3.select("#proj").text("Mercator");
      return d3.geo.mercator()
         .scale(scale * 95)
         .translate([width / 2, height / 2])
         .rotate([coords[0],0])
         .center([0, -coords[1]]);
    }
  }

  var width = 960,
      height = 500,
      scale = 1,
      currentProj;

  var rotate = [0,0];

  var projection = pickProjection(1, [0,0]);

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

  var graticule = d3.geo.graticule();

  var m0,
      o0;

  var zoom = d3.behavior.zoom()
      .center([width / 2, height / 2])
      .on("zoomstart", function(){
        m0 = [d3.event.sourceEvent.pageX, d3.event.sourceEvent.pageY];
        if (currentProj == "albers") {
          var proj = projection.rotate(),
              cent = projection.center();
          o0 = [-proj[0], cent[1]];
        } else {
          var proj = projection.rotate();
          o0 = [-proj[0],-proj[1]];
        }
        d3.event.sourceEvent.stopPropagation();
      })
      .on("zoom", function() {
        if (m0) {
          var constant = (scale < 4) ? 4 : scale * 2;
          var m1 = [d3.event.sourceEvent.pageX, d3.event.sourceEvent.pageY],
              o1 = [o0[0] + (m0[0] - m1[0]) / constant, o0[1] + (m1[1] - m0[1]) / constant];
        }

        rotate = [-o1[0], -o1[1]];
        scale = (d3.event.scale >= 1) ? d3.event.scale : 1;
        projection = pickProjection(scale, rotate);
        d3.selectAll("path").attr("d", path.projection(projection));

      });

  var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height)
      .call(zoom);
      
  svg.append("defs").append("path")
      .datum({type: "Sphere"})
      .attr("id", "sphere")
      .attr("d", path);

  svg.append("use")
      .attr("class", "stroke")
      .attr("xlink:href", "#sphere");

  svg.append("use")
      .attr("class", "fill")
      .attr("xlink:href", "#sphere");

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

  d3.json("countries_1e5.json", function(error, data) {
    svg.insert("path", ".graticule")
        .datum(topojson.feature(data, data.objects.countries))
        .attr("class", "land")
        .attr("d", path);

    d3.select("body").append("text")
      .attr("id", "info");
    d3.select("body").append("text")
      .attr("id", "proj");
  });
</script>
</body>
</html>