score:1

Accepted answer

The translate value is aligning the graph so that x(d0) is the leftmost x value visible in the plot area. This ensures the visible portion of the plot area extends from d0 through d1 (the visible subdomain). If our full domain for the x scale has a minimum of 0, then x(0) will be shifted left (negative shift) x(d0) pixels.

I'll use a snippet to demonstrate:

var svg = d3.select("svg"),
    margin = {top: 10, right: 50, bottom: 70, left: 200},
    width = +svg.attr("width") - margin.left - margin.right,
    height = +svg.attr("height") - margin.top - margin.bottom;

// Scale for Data:
var x = d3.scaleLinear()
  .range([0, width])
  .domain([0,20]);
  
// Scale for Zoom:
var xZoom = d3.scaleLinear()
  .range([0,width])
  .domain([0,width]);
  
var xAxis = d3.axisBottom(x).ticks(5);
var xZoomAxis = d3.axisBottom(xZoom);

var zoom = d3.zoom()
    .scaleExtent([1, 32])
    .translateExtent([[0, 0], [width, height]])
    .extent([[0, 0], [width, height]])
    .on("zoom", zoomed);
    
var g = svg.append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

// plot area
g.append("rect")
  .attr("width",width)
  .attr("height",height)
  .attr("fill","url(#stripes)");
  
g.append("text")
  .attr("x",width/2)
  .attr("y",height/2)
  .style("text-anchor","middle")
  .text("plot area");
  
g.append("line")
  .attr("y1",0)
  .attr("y2",height)
  .attr("stroke-width",1)
  .attr("stroke","black");

// zoomed plot area:
var rect = g.append("rect")
  .attr("width",width)
  .attr("height",height)
  .attr("fill","lightgrey")
  .attr("opacity",0.4);
  
// Axis for plot:
g.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", "translate(0," + height + ")")
  .call(xAxis);
  
// Axis for zoom:
g.append("g")
  .attr("class", "axis axis-zoom-x")
  .attr("transform", "translate(0,"+(height+30)+")")
  .call(xZoomAxis);  
  
var text = g.append("text")
  .attr("y", height+60)
  .attr("text-anchor","middle")
  .text("zoom units")
  .attr("x",width/2);
  
// Gratuitous intro zoom:   
var d1 = 18;
var d0 = 8;

svg.call(zoom).transition()
 .duration(2000)
 .call(zoom.transform, d3.zoomIdentity
 .scale(width / (x(d1) - x(d0)))
 .translate(-x(d0), 0));


function zoomed() {
  var t = d3.event.transform, xt = t.rescaleX(x);
  xZoom.range([xt(0),xt(20)]);
  g.select(".axis--x").call(xAxis.scale(xt));
  g.select(".axis-zoom-x").call(xZoomAxis.scale(xZoom));
  rect.attr("x", xt(0));
  rect.attr("width", xt(20) - xt(0));
  text.attr("x", xt(10));
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<svg width="400" height="180">
<defs>
  <pattern id="stripes" patternUnits="userSpaceOnUse" width="8" height="8" patternTransform="rotate(45 0 0)">
  <rect width="3" height="8" fill="orange"></rect>
</pattern>
</defs>

</svg>

Snippet Explanation:

  • Plot area: orange stripes
  • Full scaled extent of data: grey box.
  • Left hand side of plot area is x=0 (pixels) for the parent g that holds everything.

As we zoom in the bounds of our data exceeds the plot area. We want to show a specific subdomain of our data. We achieve part of that with the scale (as you correctly deduce) but the other portion is with the translate: we push values less than the lowest value of our x subdomain to the left. By pushing the entire graph left by an amount equal to x(d0), x(d0) appears as the leftmost coordinate of the plot area.


Related Query

More Query from same tag