Skip to content

Instantly share code, notes, and snippets.

@mapsam
Created December 14, 2015 19:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mapsam/c76ed3ac3a79d9736dd7 to your computer and use it in GitHub Desktop.
Save mapsam/c76ed3ac3a79d9736dd7 to your computer and use it in GitHub Desktop.
Outer & Inner loop drawings, TopoJSON

This example shows how geometries with inner loops and outer loops build themselves in opposite direction. The outer loop (red) builds clockwise, while the inner loop (blue) builds counter-clockwise. This is important in order to confidently account for negative MultiPolygons instead of separate Polygon features. Here's a good summary of the importance in winding order.

Display the source blob
Display the rendered blob
Raw
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
<!DOCTYPE html>
<meta charset="utf-8">
<style>
path {
fill: none;
stroke-width: 2px;
-webkit-transition: 0.2s;
-moz-transition: 0.2s;
-ms-transition: 0.2s;
-o-transition: 0.2s;
transition: 0.2s;
}
.outer-loop {
stroke: red;
}
.inner-loop {
stroke: steelblue;
}
circle {
fill: orange;
stroke: #fff;
stroke-width: 3px;
}
</style>
<body>
<div id="main"></div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var width = 960,
height = 500;
var projection = d3.geo.albers()
.center([0, 37.7])
.scale(500);
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
d3.json("donut.json", function(error, polygon) {
var data = topojson.feature(polygon, polygon.objects.donut).features[0].geometry.coordinates;
var coordinatesOuter = data[0].map(projection);
var coordinatesInner = data[1].map(projection);
// begin string concat
dOuter = 'M' + coordinatesOuter[0].join();
dInner = 'M' + coordinatesInner[0].join();
pathOuter = svg.append('path').attr('d', dOuter);
pathInner = svg.append('path').attr('d', dInner);
var count = 0;
// start outer loop
loopOuter();
function loopOuter() {
dOuter += 'L' + coordinatesOuter[count].join();
pathOuter.attr("d", dOuter)
.attr('class', 'outer-loop')
.transition()
.duration(10)
.attr("d", dOuter)
.each("end", function(){
count++;
if (count < coordinatesOuter.length) loopOuter();
else loopInner(); // run inner loop when outer loop finishes
});
}
var innerCount = 0;
function loopInner() {
console.log(pathInner.transition());
dInner += 'L' + coordinatesInner[innerCount].join();
pathInner.attr("d", dInner)
.attr('class', 'inner-loop')
.transition()
.duration(100)
.attr('d', dInner)
.each('end', function(){
innerCount++;
if (innerCount < coordinatesInner.length) loopInner();
});
}
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment