block by mbostock 6287633

Dynamic Simplification III

Full Screen

A variation of the dynamic simplification demonstration using a filled polygon rather than a stroked mesh. As a result, the effect of simplification is almost imperceptible during zooming. Aside from the fluid framerate achieved by faster rendering, of course!

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<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 chesapeake = [-75.959, 38.250];

var scale,
    translate,
    area; // minimum area threshold for simplification

var clip = d3.geo.clipExtent()
    .extent([[0, 0], [width, height]]);

var simplify = d3.geo.transform({
  point: function(x, y, z) {
    if (z >= area) this.stream.point(x * scale + translate[0], y * scale + translate[1]);
  }
});

var zoom = d3.behavior.zoom()
    .size([width, height])
    .on("zoom", zoomed);

// This projection is baked into the TopoJSON file,
// but is used here to compute the desired zoom translate.
var projection = d3.geo.mercator()
    .translate([0, 0])
    .scale(4000)
    .precision(0);

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

var context = canvas.node().getContext("2d");

var path = d3.geo.path()
    .projection({stream: function(s) { return simplify.stream(clip.stream(s)); }})
    .context(context);

d3.json("us.json", function(error, json) {
  if (error) throw error;

  canvas
      .datum(topojson.feature(topojson.presimplify(json), json.objects.land))
      .call(zoomTo(chesapeake, 0.05).event)
    .transition()
      .duration(5000)
      .each(jump);
});

function zoomTo(location, scale) {
  var point = projection(location);
  return zoom
      .translate([width / 2 - point[0] * scale, height / 2 - point[1] * scale])
      .scale(scale);
}

function zoomed(d) {
  translate = zoom.translate();
  scale = zoom.scale();
  area = 1 / scale / scale;
  context.clearRect(0, 0, width, height);
  context.beginPath();
  path(d);
  context.fill();
}

function jump() {
  var t = d3.select(this);
  (function repeat() {
    t = t.transition()
        .call(zoomTo(chesapeake, 1.25).event)
      .transition()
        .call(zoomTo(chesapeake, 0.05).event)
        .each("end", repeat);
  })();
}

</script>