block by jczaplew 6830815

Lazy composite

Full Screen

Display global views using a Hammer projection with d3.js, everything else in a web mercator with Leaflet.js.

Edit: now with additional smoke and mirrors.

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
    <link rel="stylesheet" href="//cdn.leafletjs.com/leaflet-0.6.3/leaflet.css" />
    <script src="//cdn.leafletjs.com/leaflet-0.6.3/leaflet.js"></script>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="//d3js.org/d3.geo.projection.v0.min.js" charset="utf-8"></script>
    <script src="//d3js.org/topojson.v1.min.js"></script>
    <style type="text/css">
      .countries {
        stroke: #000;
        fill: #FEFBFB;
        stroke-width: 0.5;
      }
      #map {
        height:500px;
        width:100%;
      }
      #zoom {
        position: absolute;
        margin-top:10px;
        margin-left:10px;
      }
    </style>
  </head>
  <body>
    <div id="zoom" class="leaflet-control-zoom leaflet-bar leaflet-control">
      <a class="leaflet-control-zoom-in" href="#" title="Zoom in" id="zoomIn">+</a>
      <a class="leaflet-control-zoom-out leaflet-disabled" href="#" title="Zoom out">-</a>
    </div>  
    <div id="svgMap"></div>
    <div id="map"></div>
    <script type="text/javascript">
      var map = new L.Map('map', {
        center: new L.LatLng(7, 0),
        zoom: 2,
        maxZoom:10,
        minZoom: 2
      });

      var attrib = 'Map tiles by <a href="//stamen.com">Stamen Design</a>, <a href="//creativecommons.org/licenses/by/3.0">CC BY 3.0</a> &mdash; Map data © <a href="//openstreetmap.org">OpenStreetMap</a> contributors';

      var stamen = new L.TileLayer('//{s}.tile.stamen.com/toner-background/{z}/{x}/{y}.png', {attribution: attrib}).addTo(map);

      map.on('moveend', function(d) {
        var zoom = map.getZoom();
        if (zoom < 3) {
          d3.select("#map").style("width", 0);
          d3.select("#svgMap").style("display", "block");
          d3.selectAll("path").attr("d", path);
        }
      });
      d3.select("#map").style("width", 0);

      var width = window.innerWidth,
          height = 500;
      
      var projection = d3.geo.hammer()
        .scale(165)
        .translate([width / 2, height / 2])
        .precision(.1);

      var mercator = d3.geo.mercator()
        .scale(165)
        .precision(.1)
        .translate([width / 2, height / 2]);

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

      function changeMaps(mouse) {
        var coords = mouse,
          projected = mercator.invert(coords);

        d3.select("#svgMap").style("display", "none");
        d3.select("#map").style("width", "100%");
        map.invalidateSize();

        map.setView([parseInt(projected[1]), parseInt(projected[0])], 3, {animate:false});
      }

      var zoom = d3.behavior.zoom()
        .on("zoom",function() {
          if (d3.event.sourceEvent.wheelDelta > 0) {
            changeMaps(d3.mouse(this));
          }
        });

      var svg = d3.select("#svgMap").append("svg")
        .attr("width", width)
        .attr("height", height)
        .call(zoom)
        .on("click", function() {
          changeMaps(d3.mouse(this));
        });

      svg.append("defs").append("path")
        .datum({type: "Sphere"})
        .attr("id", "sphere")
        .attr("d", path);

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

      d3.json("countries.json", function(error, data) {
        svg.append("path")
          .datum(topojson.feature(data, data.objects.countries))
          .attr("class", "countries")
          .attr("d", path);
      });

      d3.select("#zoomIn").on("click", function() {
        d3.event.stopPropagation();
        d3.select("#svgMap").style("display", "none");
        d3.select("#map").style("width", "100%");
        map.invalidateSize();

        map.setView([7,0], 3, {animate:false});
      });
    </script>
  </body>
</html>