【问题标题】:D3 add zoom and panD3 添加缩放和平移
【发布时间】:2019-07-25 03:25:57
【问题描述】:

我需要缩放和平移一组 svg 元素,比如这个例子:

https://embed.plnkr.co/kVw0rWMo728dmbm8EjuG/

我已经完成了缩放行为,但是当我拖动鼠标(平移)时我无法移动图形。我试过了:

var zoom = d3.zoom()
  .scaleExtent([1, 100])
  .translateExtent([[150, 150],[150, 150]])
  .on('zoom', zoomFn);

  d3.select('svg')
  .select('g')
  .style("transform-origin", "50% 50% 0");

function zoomFn() {
  d3.select('svg').select('g')
    .style('transform', 'translate(' + d3.event.translate + ')' + ' scale(' + d3.event.transform.k + ')');
}

d3.select('svg')
  .select('rect')
  .call(zoom);

如何在该示例中添加平移行为?

【问题讨论】:

    标签: d3.js zooming pan


    【解决方案1】:

    有几点:

    第一

    d3.event.translate 不保存变换 x 和 y 值,使用 d3.event.transform 获取这些值。变换对象具有 x、y 和 k 属性。

    第二

    如果使用.style() 放置变换,您需要指定偏移的单位是像素:

    var t = d3.event.transform;
    d3.select("zoomedElement")
      .style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
    

    或者,您可以使用.attr() 而不使用px

    var t = d3.event.transform;
    d3.select("zoomedElement")
      .style('transform', 'translate('+[t.x,t.y]+')scale(' + t.k + ')');
    

    让我们看看你的 plunker 进行了哪些更改(并且没有翻译范围):

    var zoom = d3.zoom()
      .scaleExtent([1, 100])
      .on('zoom', zoomFn);
    
      d3.select('svg')
      .select('g')
      .style("transform-origin", "50% 50% 0");
    
    function zoomFn() {
       var t = d3.event.transform;
      d3.select('svg').select('g')
        .style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
    
    
    }
    
    d3.select('svg')
      .select('rect')
      .call(zoom);
        .zoom-layer {
          fill: #EEE;
          fill-opacity: 0.25;
        }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.0.0/d3.min.js"></script>
    <svg width="300" height="300">
        <g>
          <circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
          <rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
        </g>
      </svg>

    您可能希望做出不包含矩形的选择 - 应该保持不变,以便整个 SVG 表面保持交互性

    第三

    看起来好像你想要一个翻译范围,这有时设置起来有点棘手。 This 答案在缩放范围/平移范围上更深入,但我会介绍如何将你的圆圈限制在屏幕上:

    翻译为 [0,0] 时,您的圆圈位于 svg 的中间。如果我们翻译 [-150,-150],您的圆圈位于 svg 的左上角。如果圆以 cx=150 cy=150 为中心,则可视区域的左上角现在为 [150,150]。因此右下角是 [450,450]。可见范围为:[[150,150],[450,450]]

    翻译为 [150,150] 时,您的圆圈位于 SVG 的右下角。因为圆仍然在 [150,150],所以右下角在 [150,150] (这里的平移和圆的位置具有相同的值不利于清晰)。左上角是[-150,-150]。可见范围必须是:[[-150,-150],[150,150]]

    我们从可视范围限制中取了极端值,因为这是使圆圈保持在视野范围内的平移范围:

    var translateExtent = [[-150,-150],[450,450]]
    

    当然,如果你把东西放在各个角落而不是中间,你就会有更大的范围。

    我们可以将所有内容应用到 sn-p:

    var zoom = d3.zoom()
      .scaleExtent([1, 100])
      .translateExtent([[-150,-150],[450, 450]])
      .on('zoom', zoomFn);
    
      d3.select('svg')
      .select('g')
      .style("transform-origin", "50% 50% 0");
    
    function zoomFn() {
       var t = d3.event.transform;
      d3.select('svg').select('g')
        .style('transform', 'translate('+t.x+"px,"+t.y + 'px)scale(' + t.k + ')');
    
      console.log(t.x,t.y)
    
    }
    
    d3.select('svg')
      .select('rect')
      .call(zoom);
        
        .zoom-layer {
          fill: #aaa;
          fill-opacity: 0.25;
        }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
    <svg width="300" height="300">
        <g>
          <circle cx=150 cy=150 r=20 style="fill:#F22"></circle>
        </g>
        <rect x=0 y=0 width=300 height=300 class="zoom-layer"></rect>
      </svg>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-16
      • 2018-01-04
      • 2019-01-15
      • 1970-01-01
      • 2021-10-01
      • 2017-08-22
      相关资源
      最近更新 更多