在D3中获取转换值

Getting transition values in D3

本文关键字:转换 获取 D3      更新时间:2023-09-26

我每100ms得到一个位置,并将它们应用到DOM中,如下所示:

const div = d3.select(container).selectAll('div').data(positions)
div.enter()
  .append('div')
div.transition()
  .duration(100)
  .style({
    top: d => d.y,
    left: d => d.x,
  })
div.exit()
  .remove()

因此,元素在获得下一个位置所需的100毫秒内,可以获得到新位置的平滑动画。这很好用。

但是我在DOM中有不同的元素,它们取决于第一个元素的位置。它们是用相同的位置数据渲染的,但在软件的不同模块中。

我的问题是,这种转换会插入其他模块无法使用的数据。这些其他模块的元素似乎提供了"光学错误"的可视化,因为它们是基于原始数据的。

示例:一个点移动到一个正方形中,该正方形会高亮显示,但该点的位置是插值的,而该正方形用于检查是否应该高亮显示的位置不是。因此,即使点不在正方形内,正方形也会突出显示。

我该如何解决这个问题?我可以在某个地方获取这些插值吗?

我能想到的最简单的方法是使用转换的attrTween、styleTween或tween方法(https://github.com/mbostock/d3/wiki/Transitions#attrTween)。它们接受一个必须返回函数(插值器)的函数。该插值器将被多次调用以执行转换,因此您可以继续调用回调(cb),该回调将通知其他模块有关更改的信息。

selection.styleTween('top', function(){
  var interpol = d3.interpolate(0,10); //interpolate from 0 to 10
  return function(t) { // this guy will be called many times to calc transition
    // t will be changing from 0 to 1
    var val = interpol(t);
    cb(val); // <-- callback that will notify other modules about the change in value
    return val; // <-- you have to return val so d3 transitions element
  }
});

如果我理解正确,你想完全控制tween函数:

  div
    .transition()
    .duration(1000)
    .tween("postion", function(d) {
      var div = d3.select(this),
        startTop = parseInt(div.style('top')),
        startLeft = parseInt(div.style('left')),  
        yInterp = d3.interpolateRound(startTop, d.y),
        xInterp = d3.interpolateRound(startLeft, d.x);
      return function(t) {            
        div.style("top", yInterp(t) + "px");
        div.style("left", xInterp(t) + "px");
      };
    });

工作代码:

<!DOCTYPE html>
<html>
  <head>
    <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
  </head>
  <body>
    <div id="parent">
      <div style="width: 20px; top: 20px; left: 30px; height: 20px; background-color: steelblue; position: absolute"></div>
      <div style="width: 20px; top: 0px; left: 40px; height: 20px; background-color: orange; position: absolute"></div>
    </div>
    <script>
    
      var positions = [
        {x: 50, y: 50},
        {x: 100, y: 100}
      ];
    
      var div = d3.select('#parent')
        .selectAll('div')
        .data(positions);
      div
        .transition()
        .duration(1000)
        .tween("postion", function(d) {
          var div = d3.select(this),
            startTop = parseInt(div.style('top')),
            startLeft = parseInt(div.style('left')),  
            yInterp = d3.interpolateRound(startTop, d.y),
            xInterp = d3.interpolateRound(startLeft, d.x);
          return function(t) {            
            div.style("top", yInterp(t) + "px");
            div.style("left", xInterp(t) + "px");
          };
        });
    </script>
  </body>
</html>