如果要缩放,要计算缩放和转换的转换值

时间:2018-12-26 19:56:43

标签: d3.js

我正在看这个示例,该示例说明了如何使用缩放功能来放大指定的域范围

https://bl.ocks.org/mbostock/431a331294d2b5ddd33f947cf4c81319

我对这部分感到困惑

var d0 = new Date(2003, 0, 1),
    d1 = new Date(2004, 0, 1);

// Gratuitous intro zoom!
svg.call(zoom).transition()
      .duration(1500)
      .call(zoom.transform, d3.zoomIdentity
          .scale(width / (x(d1) - x(d0))) // I think this is to caulcuate k which is the zoom factor
          .translate(-x(d0), 0)); // but what is this?

我无法理解已完成的计算。如果我的假设是错误的,请纠正我

d3.zoomIdentity这是一个转换,在应用时不执行任何操作。

.scale(width / (x(d1) - x(d0)))这是通过计算width与两个数据点d0d1之间的像素差之比来计算要应用的缩放比例

.translate(-x(d0), 0))我不理解这一部分。为什么x(d0)被否定?x的{​​{1}}坐标与需要应用多少平移有什么关系?

1 个答案:

答案 0 :(得分:1)

转换值使图形对齐,因此x(d0)是在绘图区域中可见的最左侧的x值。这样可以确保绘图区域的可见部分从d0d1(可见子域)延伸。如果我们的x比例尺的完整域的最小值为0,则x(0)将向左移(负移)x(d0)个像素。

我将使用一个片段来演示:

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>

代码段说明:

  • 绘图区域:橙色条纹
  • 数据的完整范围:灰色框。
  • 对于拥有所有内容的父级g,绘图区域的左侧为x = 0(像素)。

当我们放大数据范围时,超出了绘图区域。我们想要显示数据的特定子域。我们用比例尺(如您正确推论)实现了其中的一部分,而另一部分则是平移的:我们将小于x子域的最小值的值向左推。通过将整个图形向左推等于x(d0)的量,x(d0)将显示为绘图区域的最左坐标。

相关问题