【问题标题】:What Transformation values to calculate for scale and translate if you want to zoom如果要缩放,要计算缩放和平移的转换值
【发布时间】:2019-05-24 23:31:46
【问题描述】:

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

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)))这是通过计算widthd0d1两个数据点之间的像素差的比值来计算要应用多少比例

.translate(-x(d0), 0))这部分我没看懂。为什么x(d0) 被否定?d(0)x 坐标与需要应用多少翻译有什么关系?

【问题讨论】:

标签: d3.js


【解决方案1】:

平移值正在对齐图形,以便 x(d0) 是绘图区域中可见的最左边的 x 值。这确保了绘图区域的可见部分从d0 延伸到d1(可见子域)。如果我们的 x 尺度的完整域的最小值为 0,则 x(0) 将左移(负移)x(d0) 像素。

我会用一个sn-p来演示:

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) 将显示为绘图区域的最左侧坐标。

【讨论】:

  • 这完美地解释了它!谢谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-25
  • 1970-01-01
  • 2015-08-08
相关资源
最近更新 更多