我正在制作一个运动图,通过更新图表上相应圆圈的位置和大小来显示某些数据点随时间的发展(类似于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 ...
。我认为这就是问题所在,但我现在不明白正确的方法会是什么样子。
简短回答
当你绑定数据时,你需要一个关键功能:
.data(dataForKey(keyIndex), function(d){ return d.name})
这是你最新的小提琴:https://jsfiddle.net/7kyvzkwe/
长答案
这里发生的事情是,你是我们所说的对象恒定性的受害者,或者更准确地说,没有正确设置对象恒定性(这是Mike Bostock写的一篇关于它的好文章)。
问题是,在D3中,数据按照元素的顺序绑定到元素:
如果没有指定键函数,则数据中的第一个数据被分配给第一个选定的元素,第二个数据被指定给第二个选定的元件,依此类推
那么,让我们看看发生了什么。你的代码有三个圆圈,按照这个顺序:
- 最小的圆,r=3
- 中圆,r=10
- 最大的圆,r=15
数据按上述顺序追加。但是,当你做sort(order)
:时
function order(a, b){
return radius(b) - radius(a);
}
你对元素进行排序,现在你有了:
- 最大圆,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}];
你可以看到,即使调用sort
,圆圈也会保持原位。这是小提琴:https://jsfiddle.net/9p1tL43j/
发生这种情况是因为下次运行函数next
时,最小圆的数据会绑定到最小圆(在DOM中),依此类推…
因此,简而言之,如果要保持对象的恒定性,就需要键函数。关键功能:
。。。可以指定为控制将哪个基准指定给哪个元素,用索引替换默认联接。