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

D3.js D3 sort()会导致奇怪的意外行为,d3.js,D3.js,我正在制作一张运动图表,通过更新图表上相应圆圈的位置和大小来显示特定数据点随时间的发展(类似于) 因为圆可以重叠,我需要在上面画最小的一个 在本例中,这是通过调用selection.sort()来实现的,但是如果我也这样做(对于较新的D3v4),我会得到一个意外的行为。排序似乎会切换与可视圆圈对象关联的数据对象 看看这把小提琴。按原样运行一次(不调用第45行中的sort(order)),这是预期的行为。每个对象的y值不变,因此圆应在水平线上移动。现在取消对第45行的注释,以便在每次更新时调用so

我正在制作一张运动图表,通过更新图表上相应圆圈的位置和大小来显示特定数据点随时间的发展(类似于)

因为圆可以重叠,我需要在上面画最小的一个

在本例中,这是通过调用
selection.sort()
来实现的,但是如果我也这样做(对于较新的D3v4),我会得到一个意外的行为。排序似乎会切换与可视圆圈对象关联的数据对象

看看这把小提琴。按原样运行一次(不调用第45行中的
sort(order)
),这是预期的行为。每个对象的y值不变,因此圆应在水平线上移动。现在取消对第45行的注释,以便在每次更新时调用sort并再次运行它。这一次,圆的路径突然交叉(因为底层对象被切换)。


API声明
selection.sort()返回包含副本的新选择…
。我假设这就是问题所在,但是我不明白正确的方法会是什么样子

简短回答

绑定数据时需要一个键函数:

.data(dataForKey(keyIndex), function(d){ return d.name})
这是你最新的小提琴:

长答案

这里发生的事情是,你是我们称之为对象恒常性的受害者,或者更准确地说,没有正确设置对象恒常性(这是一篇关于它的好文章,作者)

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

如果未指定关键功能,则数据中的第一个基准将指定给第一个选定图元,第二个基准将指定给第二个选定图元,依此类推

那么,让我们看看发生了什么。您的代码有三个圆圈,顺序如下:

  • 最小圆,r=3
  • 中间圆,r=10
  • 最大的圆,r=15
  • 数据按上述顺序追加。但是,当您执行排序(顺序)时:

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

  • 最大圆,r=15
  • 中间圆,r=10
  • 较小的圆,r=3
  • 然后问题来了:下次运行
    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}];
    
    您可以看到,即使调用
    排序
    ,圆圈也会保持其位置。这是小提琴:

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

    因此,简而言之,如果要保持对象的恒定性,就需要一个键函数。A:

    。。。可以指定,以控制将哪个基准指定给哪个图元,用索引替换默认连接


    你确定你共享了正确的提琴吗?你是对的,对不起,我更正了链接。尽管我还没有遇到过这样的问题(因为我以前从未遇到过sort+join用例),谢谢你给出了非常有启发性的答案!如果将来使用sort+数据联接,我一定会记住这一点+1 :)
    [{name:"item1", x:1, y:2, z:15},
    {name:"item2", x:1, y:4, z:10},
    {name:"item3", x:1, y:6, z:3}];