block by shawnbot 69a713cc4ef753c574db

Weird topology artifacts

Full Screen

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="//d3js.org/topojson.v1.min.js"></script>
    <style>
      body {
        margin: 0;
        padding: 1em;
      }

      p {
        margin: 0 0 1em 0;
      }

      svg {
        max-width: 960px;
      }

      path.feature {
        fill: yellow;
        fill-opacity: .05;
        stroke: red;
      }

      path.mesh {
        fill: none;
        stroke: #69c;
      }
    </style>
  </head>
  <body>
    <p>
      These maps demonstrate a peculiar rendering artifact of
      <a target="_top" href="https://github.com/18F/eiti-data/blob/fa02b34b9f67d72474abda8d0cc319ef7d6a09d4/output/geo/offshore.json">this
        offshore US areas topology</a>. The <b style="color: red">red</b> lines
      are the GeoJSON geometries extracted with <tt>topojson.feature()</tt>,
      and the <b style="color: #69c">bluish</b> ones are the topological meshes
      courtesy of <tt>topojson.mesh()</tt>, with a slight offset to make them
      more visible. The features are also drawn with a very transparent yellow
      fill to make overlaps more obvious.
    </p>

    <p>
      As you can see, the state boundaries from
      <a target="_top" href="https://github.com/18F/eiti-data/blob/gh-pages/output/geo/us-states-simple.json">this
        topology</a> look great in the first map:
    </p>

    <svg id="onshore"></svg>

    <p>
      In this map, however, you can see two things: First, that all of the
      features are being drawn on top of each other across the outer clip
      extent of the projection. Second, you can see that the
      <tt>topojson.feature()</tt> is producing polygons with rings that
      coincide with <i>each</i> of the <a target="_top" href="https://github.com/mbostock/d3/wiki/Geo-Projections#albersUsa">Albers USA</a>
      clip extents for the lower 48, Alaska and Hawaii:
    </p>

    <svg id="offshore"></svg>
  </body>
  <script>

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

    d3.json('us-states.json', function(error, onshore) {
      if (error) return alert(error.responseText);
      var states = render('#onshore', onshore);
      d3.json('offshore.json', function(error, offshore) {
        if (error) return alert(error.responseText);
        var regions = render('#offshore', offshore);

        var height = document.body.getBoundingClientRect().height;
        d3.select(self.frameElement).style('height', ~~height + 'px');
      });
    });

    function render(selector, collection) {
      var meshes = [];
      var features = [];

      if (collection.type === 'Topology') {
        features = Object.keys(collection.objects)
          .reduce(function(features, key) {
            var obj = collection.objects[key];
            var feature = topojson.feature(collection, obj);
            var mesh = topojson.mesh(collection, obj);
            mesh.id = key;
            meshes.push(mesh);
            return features.concat(feature.features);
          }, []);
      } else {
        features = collection.features;
      }

      var svg = d3.select(selector)
        .attr('viewBox', '0 0 960 510');

      svg.selectAll('path.feature')
        .data(features)
        .enter()
        .append('path')
          .attr('class', 'feature')
          .attr('id', function(d) { return d.id; })
          .attr('d', path);

      svg.selectAll('path.mesh')
        .data(meshes)
        .enter()
        .append('path')
          .attr('class', 'mesh')
          .attr('transform', 'translate(4,4)')
          .attr('id', function(d) { return d.id; })
          .attr('d', path);

      return features;
    }

  </script>
</html>