block by mapsam c76ed3ac3a79d9736dd7

Outer & Inner loop drawings, TopoJSON

Full Screen

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.

index.html

<!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="//d3js.org/d3.v3.min.js"></script>
<script src="//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>

donut.json

{"type":"Topology","objects":{"donut":{"type":"GeometryCollection","crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}},"geometries":[{"type":"Polygon","arcs":[[0],[1]]}]}},"arcs":[[[5174,9999],[31,-226],[54,-69],[121,-26],[177,-65],[168,-128],[140,54],[213,-107],[57,4],[155,116],[162,-149],[170,-159],[140,-137],[134,-132],[17,-108],[41,-40],[-11,-41],[47,-13],[33,43],[9,-98],[35,-65],[48,0],[25,-50],[-21,-73],[180,-193],[37,-374],[35,-357],[-51,-243],[-81,-226],[-39,-144],[-3,-43],[19,-59],[59,-65],[43,0],[202,220],[178,64],[227,205],[3,42],[-16,125],[-28,81],[79,65],[170,2],[159,0],[55,160],[22,32],[183,296],[78,76],[263,3],[319,0],[18,102],[55,20],[74,64],[61,187],[53,320],[132,311],[58,-109],[116,70],[77,-118],[0,-561],[113,-233],[30,-135],[-185,-199],[-178,-142],[-183,-122],[-92,-244],[-29,-92],[-2,-219],[57,-218],[72,-10],[-18,150],[52,-91],[-14,-118],[-117,-66],[-83,8],[-128,-72],[-75,-21],[-101,-20],[-144,-119],[254,77],[51,-77],[-242,-124],[-111,-1],[6,51],[-53,-114],[51,-19],[-38,-296],[-126,-316],[-13,105],[-38,22],[-56,103],[36,-222],[43,-73],[2,-155],[-55,-160],[-98,-329],[-16,17],[54,279],[-88,158],[-21,341],[-33,-177],[37,-261],[-115,64],[120,-132],[7,-392],[50,-28],[18,-143],[24,-411],[-110,-305],[-179,-122],[-114,-242],[-87,-26],[-87,-151],[-25,-138],[-190,-267],[-98,-196],[-82,-244],[-26,-292],[30,-286],[58,-352],[77,-291],[1,-177],[82,-478],[-5,-277],[-8,-160],[-43,-251],[-52,-52],[-85,50],[-27,180],[-66,95],[-92,354],[-81,314],[-26,161],[36,273],[-49,227],[-135,344],[-67,63],[-175,-187],[-31,21],[-84,192],[-109,101],[-195,-51],[-154,45],[-132,-28],[-72,-64],[31,-110],[-3,-167],[37,-81],[-33,-54],[-64,61],[-65,-78],[-126,13],[-129,217],[-151,-51],[-126,95],[-108,-29],[-146,-96],[-157,-305],[-173,-177],[-94,-197],[-40,-185],[-2,-284],[9,-197],[33,-140],[-68,-12],[-123,90],[-135,128],[-48,193],[-38,288],[-103,234],[-60,241],[-86,282],[-123,164],[-141,-8],[-109,-325],[-144,123],[-90,125],[-43,226],[-57,215],[-103,181],[-89,130],[-63,145],[-300,1],[0,-170],[-138,0],[-344,-3],[-395,289],[-262,200],[16,81],[-220,-45],[-197,-31],[-29,210],[-112,236],[-81,49],[-19,118],[-97,21],[-62,111],[-161,41],[-44,66],[-21,226],[-168,413],[-144,572],[6,95],[-77,136],[-134,345],[-24,335],[-92,225],[38,341],[-6,353],[-55,315],[67,387],[21,374],[22,373],[-32,552],[-54,352],[-51,191],[21,80],[250,-140],[93,-388],[43,108],[-28,338],[-59,337],[492,0],[514,0],[171,0],[528,0],[511,0],[519,0],[520,0],[589,0],[593,0],[358,0],[1,158],[58,2]],[[1405,7841],[666,-2543],[1136,-1023],[1502,651],[1619,2201],[-771,1520],[-1266,620],[13,-2667],[-1319,1148],[209,-1582],[-1410,2543],[-379,-868]]],"transform":{"scale":[0.005772832291529937,0.0024311481148114812],"translate":[-124.68721008300783,25.08]}}