block by shawnbot 9259701

Geo thumbnails (Mercator)

Full Screen

This tweak to my original example uses a Mercator projection rather than Albers USA, which straightens out many of the state borders and puts Alaska and Hawaii in their right places.

Good call, Jeremy Stucki!

index.html

<!DOCTYPE html>
<html>
  <head>
    <title>d3 geo thumbnails</title>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="//d3js.org/topojson.v1.min.js"></script>
    <style>

      svg.thumb {
        width: 90px;
        height: 94px;
        display: block;
        float: left;
        margin: 5px 0 0 5px;
      }

      path {
        vector-effect: non-scaling-stroke;
        stroke-width: 1;
      }

      .thumb .bg,
      .thumb use {
        fill: #ddd;
        stroke: #ccc;
      }

      .thumb .fg {
        fill: #8cba3d;
        stroke: none;
      }

    </style>
  </head>
  <body>
    <div id="thumbnails"></div>
    <svg id="shared">
    </svg>
    <script>

      var root = d3.select("#thumbnails"),
          proj = d3.geo.mercator()
            .center([-98, 38]),
          path = d3.geo.path()
            .projection(proj),
          // how much space to give the features from
          // the edge of their container
          margin = 10;

      d3.json("us-states.json", function(error, topology) {
        var collection = topojson.feature(topology, topology.objects["states"]);

        // draw the whole collection once to a path in the shared <defs>
        d3.select("#shared")
          .append("defs")
            .append("path")
              .datum(collection)
              .attr("id", "states-bg")
              .attr("d", path);

        // sort the states by name
        collection.features.sort(function(a, b) {
          return d3.ascending(a.properties.name, b.properties.name);
        });

        // filter out the territories & DC
        var states = collection.features.filter(function(d) {
          return +d.id <= 70 && d.id != 11;
        });

        var svg = root.selectAll(".thumb")
          .data(states)
          .enter()
          .append("svg")
            .attr("id", function(d) {
              return d.properties.name;
            })
            .attr("class", "thumb")
            .attr("viewBox", function(d) {
              // get the projected bounds
              var bounds = path.bounds(d),
                  width = bounds[1][0] - bounds[0][0],
                  height = bounds[1][1] - bounds[0][1],
                  // get the proportion of the bounds' longest side
                  // to the container's shortest side
                  scale = Math.max(width, height) / Math.min(this.offsetWidth, this.offsetHeight),
                  // and multiply the desired margin by this
                  m = margin * scale;
              return [
                bounds[0][0] - m,
                bounds[0][1] - m,
                width + m * 2,
                height + m * 2
              ].join(" ");
            });

        // place the shared states path here
        svg.append("use")
          .attr("xlink:href", "#states-bg");

        // and draw the individual states on top
        svg.append("path")
          .attr("class", "fg")
          .attr("d", path);
      });

    </script>
  </body>
</html>