block by veltman 90c3fe742e1cc1f9d4b8e5d5e64eba05

Single path dasharray

Full Screen

Trying to improve the performance of drawing out a bunch of SVG lines by combining them all into a single path element and interpolating one very long stroke-dasharray pattern.

See also: Dynamic CSS line animation, Canvas line animation

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<style>
  path {
    stroke-width: 1px;
    stroke: #222;
    fill: none;
  }
</style>
<svg width="960" height="600"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/topojson.v2.min.js"></script>
<script>
var svg = d3.select("svg"),
    width = 960,
    height = 600;

d3.json("https://d3js.org/us-10m.v1.json", function(err, topo){

    var lines = topojson.mesh(topo, topo.objects.states).coordinates;

    var lengths = svg.selectAll("path")
      .data(lines)
      .enter()
      .append("path")
      .attr("d", function(d){
        return "M" + d.join("L");
      })
      .nodes()
      .map(function(node, i){
        return {
          length: node.getTotalLength(),
          gap: lines[i + 1] ? distanceBetween(lines[i][lines[i].length - 1], lines[i + 1][0]) : 0
        };
      });

    svg.selectAll("path")
      .remove();

    var path = svg.append("path")
      .attr("d", "M" + d3.merge(lines).join("L"));

    var start = d3.merge(lengths.map(function(l, i){
      return [0, l.length + l.gap];
    }));

    var end = d3.merge(lengths.map(function(l, i){
      return [l.length, l.gap];
    }));

    var interpolator = d3.interpolateArray(start, end);

    timer = d3.timer(function(t){
      var progress = 2 * Math.min(t % 5000 / 5000, 1 - t % 5000 / 5000);
      path.attr("stroke-dasharray", function(d){
          return interpolator(progress);
        });
    });

});

function distanceBetween(a, b) {
  var dx = a[0] - b[0],
      dy = a[1] - b[1];

  return Math.sqrt(dx * dx + dy * dy);
}

</script>