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>