代码之家  ›  专栏  ›  技术社区  ›  Krimson

如果要缩放,要为缩放和转换计算哪些转换值

  •  2
  • Krimson  · 技术社区  · 5 年前

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

    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 两个数据点之间的像素差 d0 d1

    .translate(-x(d0), 0)) 我不明白这一点。为什么是 x(d0) 否定了,那么 x 坐标系 d(0) 与需要应用多少翻译相关?

    1 回复  |  直到 5 年前
        1
  •  1
  •   Andrew Reid    5 年前

    转换值正在对齐图形,以便 x(d0) 是绘图区域中可见的最左边的X值。这样可以确保绘图区域的可见部分从 d0 通过 d1 (可见子域)。如果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>

    代码段说明:

    • 绘图区:橙色条纹
    • 全比例数据范围:灰色框。
    • 绘图区域的左侧是父级的x=0(像素) g 什么都有。

    当我们放大数据的边界时,超出了绘图区域。我们要显示数据的特定子域。我们使用比例(正如您正确推断的那样)实现了这一部分,但另一部分使用转换:我们将小于x子域的最小值的值推到左边。将整个图形左推等于 X(D0) , X(D0) 显示为绘图区域的最左侧坐标。