Smooth zooming

This notebook demonstrates using d3.interpolateZoom to implement smooth pan-and-zoom transitions between two views. See also d3.zoom’s transitions, which also allows freeform zooming.

const theta = Math.PI * (3 - Math.sqrt(5));
const height = 500;
const radius = 6;
const step = radius * 2;

const data = Array.from({length: 2000}, (_, i) => {
  const r = step * Math.sqrt(i += 0.5), a = theta * i;
  return [
    width / 2 + r * Math.cos(a),
    height / 2 + r * Math.sin(a)
  ];
});

let currentTransform = [width / 2, height / 2, height];

const svg = d3.create("svg")
    .attr("width", width)
    .attr("height", height);

const g = svg.append("g");

g.selectAll("circle")
  .data(data)
  .join("circle")
    .attr("cx", ([x]) => x)
    .attr("cy", ([, y]) => y)
    .attr("r", radius)
    .attr("fill", (d, i) => d3.interpolateRainbow(i / 360))

function transition() {
  const d = data[Math.floor(Math.random() * data.length)];
  const i = d3.interpolateZoom(currentTransform, [...d, radius * 2 + 1]);

  g.transition()
      .delay(250)
      .duration(i.duration)
      .attrTween("transform", () => (t) => transform(currentTransform = i(t)))
      .on("end", transition);
}

function transform([x, y, r]) {
  return `
    translate(${width / 2}, ${height / 2})
    scale(${height / r})
    translate(${-x}, ${-y})
  `;
}

display(svg.call(transition).node());
✎ Suggest changes to this page