block by syntagmatic 4655179

Colored Waterman

Full Screen

Waterman Projection with an Automatically Colored World Map

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>

.background {
  fill: #b4cad7;
}

.country {
  fill: #ccc;
  stroke: #fff;
  stroke-width: .5px;
  stroke-linejoin: round;
}

.graticule {
  fill: none;
  stroke: #000;
  stroke-opacity: .5;
  stroke-width: .5px;
}
</style>
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script src="//d3js.org/d3.geo.polyhedron.v0.min.js"></script>
<script src="//d3js.org/topojson.v0.min.js"></script>
<script>

var width = 960,
    height = 500;

    var projection = d3.geo.polyhedron.waterman()
        .scale(108)
        .translate([width / 2, height / 2])
        .rotate([20, 0]);

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

var graticule = d3.geo.graticule()
    .step([10, 10])
    .extent([[-180, -80], [180, 80 + 1e-3]]);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

svg.append("defs").append("path")
    .datum({type: "Sphere"})
    .attr("id", "sphere")
    .attr("d", path);

svg.append("clipPath")
    .attr("id", "clip")
  .append("use")
    .attr("xlink:href", "#sphere");

svg.append("use")
    .attr("class", "background")
    .attr("xlink:href", "#sphere");

svg.append("g")
    .attr("class", "graticule")
    .attr("clip-path", "url(#clip)")
  .selectAll("path")
    .data(graticule.lines)
  .enter().append("path")
    .attr("d", path);

d3.json("/d/4090846/world-110m.json", function(error, world) {
  var neighbors = topojson.neighbors(world, world.objects.countries.geometries),
      colors = d3.scale.category10().range().map(function(c) { c = d3.hcl(c); c.h = 0.95*c.h + 100; return c; }),
      nColors = colors.length,
      colorByObject = {};

  world.objects.countries.geometries.forEach(function(o, index) {
    var oNeighbours = neighbors[index] || [],
        m = oNeighbours.length;
    nextColor:
    for (var i = 0; i < nColors; ++i) {
      var color = colors[i];
      for (var j = 0; j < m; ++j) {
        if (colorByObject[oNeighbours[j].id] === color) continue nextColor;
      }
      colorByObject[o.id] = color;
      break;
    }
  });

  svg.selectAll(".country")
      .data(topojson.object(world, world.objects.countries).geometries)
    .enter().insert("path", ".graticule")
      .attr("class", "country")
      .attr("clip-path", "url(#clip)")
      .attr("d", path)
      .style("fill", function(d) { return colorByObject[d.id]; });
});

topojson.neighbors = function(topology, objects) {
  var objectsByArc = topology.arcs.map(function() { return []; });

  function line(arcs, index) {
    for (var i = 0, n = arcs.length, arc; i < n; ++i) {
      if ((arc = arcs[i]) < 0) arc = ~arc;
      objectsByArc[arc].push(index);
    }
  }

  function polygon(arcs, i) {
    arcs.forEach(function(arc) { line(arc, i); });
  }

  function geometry(o, i) {
    geometryType[o.type](o.arcs, i);
  }

  var geometryType = {
    LineString: line,
    MultiLineString: polygon,
    Polygon: polygon,
    MultiPolygon: function(arcs, i) { arcs.forEach(function(arc) { polygon(arc, i); }); }
  };

  objects.forEach(geometry);

  var neighbors = [];
  objectsByArc.forEach(function(d) {
    if (d.length < 2) return;
    if (!neighbors[d[0]]) neighbors[d[0]] = [];
    if (!neighbors[d[1]]) neighbors[d[1]] = [];
    neighbors[d[0]].push(objects[d[1]]);
    neighbors[d[1]].push(objects[d[0]]);
  });
  return neighbors;
};

</script>