D3 sort()导致奇怪的意外行为

时间:2017-01-21 07:29:06

标签: d3.js

我正在制作一个动态图表,通过更新图表上相应圆圈的位置和大小来显示某些数据点的开发(类似于https://bost.ocks.org/mike/nations/)。

由于圆圈可以重叠,我需要在顶部绘制最小的圆圈。

在示例中,这是通过调用selection.sort()来完成的,但如果我这样做(使用较新的D3v4),我会收到意外行为。排序似乎切换与可视圆对象关联的数据对象。

检查这个小提琴看。按原样运行一次(不在第45行调用sort(order)) - 这是预期的行为。每个对象的y值都不会改变,因此圆圈应该在水平线上移动。现在取消注释第45行以在每次更新时调用排序并再次运行它。这次圆圈的路径突然交叉(因为底层物体被切换)。 https://jsfiddle.net/orj1rcy8/1/

API声明selection.sort() Returns a new selection that contains a copy ...。我认为这是问题所在,但是我现在不明白正确的方法会是什么样子。

1 个答案:

答案 0 :(得分:2)

简短回答

绑定数据时需要一个关键功能:

.data(dataForKey(keyIndex), function(d){ return d.name})

这是您更新的小提琴:https://jsfiddle.net/7kyvzkwe/

答案很长

这里发生的事情是你是我们称之为对象恒定性的受害者,或者更确切地说,没有正确设置对象的持久性(这里是一个很好的阅读,由{{3编写) }})。

问题是,在D3中,数据按顺序绑定到元素:

  

如果未指定键功能,则数据中的第一个数据将分配给第一个选定元素,第二个数据分配给第二个选定元素,依此类推。

所以,让我们看看发生了什么。您的代码按顺序有三个圆圈:

  1. 最小的圆圈,r = 3;
  2. 中等圆圈,r = 10;
  3. 最大的圆圈,r = 15。
  4. 数据附加在上述顺序中。但是,当你sort(order)时:

    function order(a, b){
        return radius(b) - radius(a);
    }
    

    您对元素进行排序,现在您已经:

    1. 最大的圆圈,r = 15;
    2. 中等圆圈,r = 10;
    3. 较小的圆圈,r = 3.
    4. 然后出现问题:下次运行next函数并绑定新数据时,您将数据绑定到新订单中的DOM元素。也就是说,关于最小圆的数据被绑定到DOM中的最大圆。使用元素的名称,您将有关item1的数据绑定到DOM中的item3(假设您有3个元素,则唯一一个始终接收正确数据的是item2 )。

      你可以在下一个小提琴中更好地理解这一点。在下一个小提琴中,我正在使用您的代码,取消注释sort函数。但是,与原始代码不同,这里我改变了数据的顺序,所以我们先得到最大的圆,然后是中等,然后是最小的圆:

      [{name:"item1", x:1, y:2, z:15},
      {name:"item2", x:1, y:4, z:10},
      {name:"item3", x:1, y:6, z:3}];
      

      你可以看到,即使打电话给sort,圈子也会留在他们的位置。这是小提琴:Mike Bostock

      这是因为下次运行函数next时,最小圆的数据被绑定到最小的圆(在DOM中),依此类推......

      因此,简而言之,如果要保持对象的持久性,则需要键函数。一个https://jsfiddle.net/9p1tL43j/

        

      ...可以指定控制将哪个数据分配给哪个元素,替换默认的join-by-index。