【问题标题】:d3.js - v3 and v4 - Enter and Update differencesd3.js - v3 和 v4 - 输入和更新差异
【发布时间】:2018-04-12 10:11:08
【问题描述】:

我正在尝试获取 xy 的值以使用 d3.js v4 创建一个圆圈。使用以下代码,我设法创建了类似于圆圈行为的图表,但是当我尝试在 v4 中运行相同的代码时,它不再起作用了。我知道 v4 的更新存在一些差异,但我没有找到任何有关它的信息。所以我想知道是否有人可以帮助我在 d3.js v4 中运行这段代码。

这是使用 v3 的代码(使用 v4 会中断):

var svg = d3.select('body').append('svg')
  .attr('width', 250)
  .attr('height', 250);

//render the data
function render(data) {
  //Bind 
  var circles = svg.selectAll('circle').data(data);

  //Enter
  circles.enter().append('circle')
    .attr('r', 10);
  //Update
  circles
    .attr('cx', function(d) {
      return d.x;
    })
    .attr('cy', function(d) {
      return d.y;
    });


  //Exit
  circles.exit().remove();
}



var myObjects = [{
  x: 100,
  y: 100
}, {
  x: 130,
  y: 120
}, {
  x: 80,
  y: 180
}, {
  x: 180,
  y: 80
}, {
  x: 180,
  y: 40
}];


render(myObjects);
<script src='https://d3js.org/d3.v3.min.js'></script>

【问题讨论】:

    标签: javascript html d3.js version


    【解决方案1】:

    这是预期的行为,我之前已在 this answer 中解释过这一点(但不是重复的)。

    发生的事情是,D3 的创建者 Mike Bostock 在 D3 v2 中引入了一种魔法行为,他在 D3 v3.x 中保留了该行为,但决定在 D3 v4.x 中放弃。要了解更多信息,请看这里:What Makes Software Good?这是他所说的:

    D3 2.0 引入了一个更改:追加到输入选择现在会将输入元素复制到更新选择中 [...] D3 4.0 移除了 enter.append 的魔力。 (事实上​​,D3 4.0 完全消除了输入选择和普通选择之间的区别:现在只有一类选择。)

    让我们看看吧。

    这是您使用 D3 v3 的代码:

    var svg = d3.select('body').append('svg')
      .attr('width', 250)
      .attr('height', 250);
    
    //render the data
    function render(data) {
      //Bind 
      var circles = svg.selectAll('circle').data(data);
    
      //Enter
      circles.enter().append('circle')
        .attr('r', 10);
      //Update
      circles
        .attr('cx', function(d) {
          return d.x;
        })
        .attr('cy', function(d) {
          return d.y;
        });
    
      //Exit
      circles.exit().remove();
    }
    
    var myObjects = [{
      x: 100,
      y: 100
    }, {
      x: 130,
      y: 120
    }, {
      x: 80,
      y: 180
    }, {
      x: 180,
      y: 80
    }, {
      x: 180,
      y: 40
    }];
    
    
    render(myObjects);
    <script src='https://d3js.org/d3.v3.min.js'></script>

    现在使用相同的代码,使用 D3 v4。它会“破裂”:

    var svg = d3.select('body').append('svg')
      .attr('width', 250)
      .attr('height', 250);
    
    //render the data
    function render(data) {
      //Bind 
      var circles = svg.selectAll('circle').data(data);
    
      //Enter
      circles.enter().append('circle')
        .attr('r', 10);
      //Update
      circles
        .attr('cx', function(d) {
          return d.x;
        })
        .attr('cy', function(d) {
          return d.y;
        });
    
      //Exit
      circles.exit().remove();
    }
    
    var myObjects = [{
      x: 100,
      y: 100
    }, {
      x: 130,
      y: 120
    }, {
      x: 80,
      y: 180
    }, {
      x: 180,
      y: 80
    }, {
      x: 180,
      y: 40
    }];
    
    
    render(myObjects);
    <script src='https://d3js.org/d3.v4.min.js'></script>

    “中断”是指将附加圆圈,但它们不会在“输入”选择中接收xy 属性,并且它们将默认为零。这就是您在左上角看到所有圆圈的原因。

    解决方案:合并选择:

    circles.enter().append('circle')
      .attr('r', 10)
      .merge(circles) //from now on, enter + update
      .attr('cx', function(d) {
        return d.x;
      })
      .attr('cy', function(d) {
        return d.y;
      });
    

    根据APImerge()...

    ... 通常用于在数据连接后合并输入和更新选择。分别修改进入和更新元素后,可以合并两个选择,对两者进行操作,不重复代码。

    这是带有merge()的代码:

    var svg = d3.select('body').append('svg')
      .attr('width', 250)
      .attr('height', 250);
    
    //render the data
    function render(data) {
      //Bind 
      var circles = svg.selectAll('circle').data(data);
    
      //Enter
      circles.enter().append('circle')
        .attr('r', 10)
        .merge(circles) //from now on, enter + update
        .attr('cx', function(d) {
          return d.x;
        })
        .attr('cy', function(d) {
          return d.y;
        });
    
      //Exit
      circles.exit().remove();
    }
    
    var myObjects = [{
      x: 100,
      y: 100
    }, {
      x: 130,
      y: 120
    }, {
      x: 80,
      y: 180
    }, {
      x: 180,
      y: 80
    }, {
      x: 180,
      y: 40
    }];
    
    
    render(myObjects);
    <script src='https://d3js.org/d3.v4.min.js'></script>

    【讨论】:

    • 感谢您的回答,我现在了解 v3 和 v4 之间的区别。
    【解决方案2】:

    d3v4 中的更新模式已更改。 摘自documentation

    此外, selection.append 不再将输入节点合并到 更新选择;使用 selection.merge 组合输入和更新 数据连接后。

    你应该这样重写你的代码:

    var svg = d3.select('body').append('svg')
                .attr('width', 250)
                .attr('height', 250);
    
        //render the data
        function render(data){
                //Bind 
                var circles = svg.selectAll('circle').data(data);
    
                //Enter
                circles.enter().append('circle')
                    .attr('r', 10).merge(circles) // <== !!!
                    .attr('cx', function(d) { return d.x; })
                    .attr('cy', function(d) { return d.y; });
    
    
                //Exit
                circles.exit().remove();
        }
    
       
    
        var myObjects = [
            {x: 100, y: 100},
            {x: 130, y: 120},
            {x: 80, y: 180},
            {x: 180, y: 80},
            {x: 180, y: 40}
        ];
        
    
        render(myObjects);
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.11.0/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 感谢您的回答,它对我帮助很大!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-24
    • 1970-01-01
    • 2020-10-11
    相关资源
    最近更新 更多