block by HarryStevens 0835dd9631c30619e7441287624de09e

Multi-Layer Map

Full Screen

Use multiple TopoJSON files to put layers on your map.

index.html

<!DOCTYPE html>
<html>
<head>
    <style>

      body {
        margin: 0;
        font-family: "Helvetica Neue", sans-serif;
      }

      .subunit.ac {
        fill: #ddd;
        stroke: #fff;
        stroke-width: 1px;
      }
      .subunit.state {
        fill: none;
        stroke: #000;
        stroke-width: .5px;
      }
      .subunit-boundary {
        fill: none;
        stroke: #3a403d;
      }

      .place-label {
        font-size: .7em;
        text-shadow: 1px 1px 1px #fcfcfc, 1px 1px 1px #eee, 0 -1px 0 #fff, -1px 0 0 #fff;
      }

    </style>
</head>
<body>
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.20/topojson.min.js"></script>

    <script>
      var width = window.innerWidth, height = window.innerHeight;

      var projection = d3.geoMercator();

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

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

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

      d3.queue()
      	.defer(d3.json, "ac.json")
      	.defer(d3.json, "states.json")
      	.await(ready)

      function ready(error, map, state){
      	
      	centerZoom(map);
        drawSubUnits(map, "ac");
			
        var boundary = centerZoom(state);
        drawOuterBoundary(state, boundary);
        drawSubUnits(state, "state");        

        drawPlaces(map);

      }
      
      // This function "centers" and "zooms" a map by setting its projection's scale and translate according to its outer boundary
      // It also returns the boundary itself in case you want to draw it to the map
      function centerZoom(data){
        var o = topojson.mesh(data, data.objects.polygons, function(a, b) { return a === b; });

        projection
            .scale(1)
            .translate([0, 0]);

        var b = path.bounds(o),
            s = 1 / Math.max((b[1][0] - b[0][0]) / width, (b[1][1] - b[0][1]) / height),
            t = [(width - s * (b[1][0] + b[0][0])) / 2, (height - s * (b[1][1] + b[0][1])) / 2];

        projection
            .scale(s)
            .translate(t);

        return o;
      }

      function drawOuterBoundary(data, boundary){
        g.append("path")
            .datum(boundary)
            .attr("d", path)
            .attr("class", "subunit-boundary");
      }

      function drawPlaces(data){
        g.append("path")
            .datum(topojson.feature(data, data.objects.places))
            .attr("d", path)
            .attr("class", "place");

        g.selectAll(".place-label")
            .data(topojson.feature(data, data.objects.places).features)
          .enter().append("text")
            .attr("class", "place-label")
            .attr("transform", function(d) { return "translate(" + projection(d.geometry.coordinates) + ")"; })
            .attr("dy", ".35em")
            .attr("x", function(d) { return projection(d.geometry.coordinates)[0] <= width / 2 ? -6 : 6; })
            .style("text-anchor", function(d){ return projection(d.geometry.coordinates)[0] <= width / 2 ? "end" : "start"; })
            .text(function(d) { return d.properties.name; });
      }

      function drawSubUnits(data, cl){
        g.selectAll(".subunit." + cl)
            .data(topojson.feature(data, data.objects.polygons).features)
          .enter().append("path")
            .attr("class", "subunit " + cl)
            .attr("d", path);
      }


    </script>


</body>
</html>