【问题标题】:How do you change the interpolation for a zoom behavior in d3.js如何更改 d3.js 中缩放行为的插值
【发布时间】:2020-10-18 02:05:55
【问题描述】:

我正在使用 d3.js V 4.0 在 SVG 中提供缩放和平移功能。我正在实现一个重置按钮,让我回到图像的中心。它正在工作,但它使用默认的 d3.interpolateZoom ,因此图像在过渡期间会缩小。我只希望缩放进行标准插值,但我不知道如何更改缩放行为的插值器。 这是代码的缩写版本:

var map = document.querySelector('#map');
var everything = d3.select('#everything');
var zoomBehavior = d3.zoom();
zoomBehavior.scaleExtent([0.5, 10])
  .on('zoom', zoomed);
d3.select(map).call(zoomBehavior);

function zoomed() {
  everything.attr('transform', d3.event.transform);
}

function reset() {
  d3.select(this.map)
    .transition()
    .duration(1000)
    .call(zoomBehavior.transform, d3.zoomIdentity);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.1.0/d3.min.js"></script>
<svg id="map" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <g id="everything">
    <circle r="5" cx="50" cy="15"></circle>
  </g>
</svg>
<button onclick="reset()">reset</button>

不幸的是,这并没有表现出我所看到的行为。 (在我的真实版本中,比例 k 使用 van Wijk smooth zooming 通过 0 进行插值)但问题仍然有效。如果我要更改此缩放行为的插值器,我将如何以及在哪里执行此操作?我曾尝试调用文档似乎建议的 zoomBehavior.interpolate(d3.interpolate),但我收到一条错误消息,指出 zoomBehavior.interpolate 不是函数。

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    我们遇到了同样的问题,并使用interpolate 方法解决了它。应用到您的代码中,它看起来像这样:

    zoomBehavior.interpolate(d3.interpolate).scaleExtent([0.5, 10])
      .on('zoom', zoomed);
    

    根据http://devdocs.io/d3~4/d3-zoom#zoom_interpolate,d3.interpolate 应用“两个视图之间的直接插值”,而默认值是 d3.interpolateZoom,它应用了我们都不想要的“平滑缩放”。

    【讨论】:

    • 天啊,我本来打算写一个补间函数,直到我看到这个。如此琐碎!
    【解决方案2】:

    如果没有看到您试图避免的行为,很难回答这个问题。您上面的示例代码按预期工作。也就是说,这是一个完全控制插值器并因此控制转换的示例。在这里,我将圆圈缩放回scale: 1,但x 和y 位于svg 的右下方:

    <!DOCTYPE html>
    <html>
    
    <head>
      <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.js"></script>
    </head>
    
    <body>
      <svg id="map" version="1.1" xmlns="http://www.w3.org/2000/svg">
        <g id="everything">
          <circle r="5" cx="50" cy="15"></circle>
        </g>
      </svg>
      <button onclick="reset()">reset</button>
      <script>
        var map = d3.select('#map'),
            everything = d3.select('#everything');
    
        var zoomBehavior = d3.zoom();
        zoomBehavior.scaleExtent([0.5, 10])
          .on('zoom', zoomed);
    
        map.call(zoomBehavior);
    
        function zoomed() {
          everything.attr('transform', d3.event.transform);
        }
    
        function reset() {
          d3.select(this.map)
            .transition()
            .duration(1000)
            .tween("custom", function() {
              var curZoom = d3.zoomTransform(map.node()),
                kInter = d3.interpolate(curZoom.k, 1),
                xInter = d3.interpolate(curZoom.x, 240),
                yInter = d3.interpolate(curZoom.y, 99);
              return function(t) {
                var ts = d3.zoomIdentity
                  .translate(xInter(t), yInter(t))
                  .scale(kInter(t));
                map.call(zoomBehavior.transform, ts);
              };
            });
        }
      </script>
    </body>
    
    </html>

    【讨论】:

    • 虽然您的示例在代码 sn-p 中运行良好,但当我在自己的代码中尝试时,补间中返回的函数仅被调用一次,因此转换并没有真正发生。知道什么会导致它只触发一次而不是在持续时间内重复触发吗?
    • @EricJ,很难说你提供的信息有限。您可以使用您的特定代码创建一个可重现的示例吗?
    • 我似乎无法在 sn-p 或任何其他系统上重现该问题。那个系统一定有问题。
    【解决方案3】:

    请注意,您现在可以在 d3.interpolateZoom (v2.0.1) 中使用 .rho 来自定义缩放和平移时获得的曲率量。默认为Math.sqrt(2) 而rho(0) 导致线性插值。

    这就是你的设置方式:

    let zoomBehavior = d3.zoom()
        .interpolate(d3.interpolateZoom.rho(0.9)) // 0.9 for less curvature
        .scaleExtent([0.5, 10])
        .on('zoom', zoomed);
    

    【讨论】:

      猜你喜欢
      • 2016-03-17
      • 1970-01-01
      • 2021-08-18
      • 1970-01-01
      • 2015-03-04
      • 2013-06-26
      • 1970-01-01
      • 2021-09-02
      • 2018-07-25
      相关资源
      最近更新 更多