我使用D3构建一个小型可视化,需要将几个不同的东西绑定到同一个数据元素。我有一个观点,我似乎能够让这个工作的唯一方法是通过执行Data()
的多次调用,我觉得这可能是低效的。
这里的例子是我的加入代码:
// Sort out the data joins
var joinedGroups = segments.selectAll(".menu").data(pie(data));
var joinedSegments = segments.selectAll(".menu-segment").data(pie(data));
var joinedIcons = segments.selectAll("circle").data(pie(data));
这是一张有助于说明我正在构建的图片:
在我的DOM中,您可以看到它们之间的关系:
<g>
<path>
<circle>
这是DOM的输出,用于说明:
<g class="menu">
<path class="menu-segment" d="" style="fill: rgb(255, 0, 0);"></path>
<circle r="5" cx="29.999999999999996" cy="-51.96152422706632"></circle>
</g>
然后我使用joinedGroups
添加新的<g>
,<path>
和<circle>
元素。那时我转而使用joinedSegments
来更新我的饼段。这是我觉得错误的一点:
// Update existing segments and icons
joinedSegments.attr("d", arc);
joinedIcons.attr("cx", function(d) { return calcMidPoint(d).x; })
.attr("cy", function(d) { return calcMidPoint(d).y; });
在考虑了这一点后,我得出结论,我现在应该能够接受joinedGroups
并选择所有.menu-segment
个实例,以取代我所有的<path>
元素。
joinedGroups.selectAll(".menu-segment").attr("d", arc);
此时我认为我破解了它,我不再使用joinedSegments
所以我在顶部取出了Data()
电话,然后它停止了正常工作,错过了一个应该分段在那里。因此,我对调用Data()
的副作用感到有些困惑 - 任何人都可以解释发生了什么事吗?
你可以在这里看到一个例子JSFiddle - 注释掉#123&amp; #124 说明了我引用的Data()
的副作用,因为黄色部分会消失。
答案 0 :(得分:1)
潜在的问题是您有嵌套元素,并且每个元素(g
,path
和circle
)都需要将数据绑定到它们,因为您正在设置基于数据的属性。
您明确地将数据绑定到g
元素(第122行),这样就可以了。一切都适用于输入选择,因为.append()
具有将绑定数据“继承”到附加元素的副作用。问题在于更新选择。您用来选择嵌套元素并更新其属性的.selectAll()
(第143和144行)不更新绑定数据,您在要设置的函数中依赖这些数据属性值。
有两种方法可以解决这个问题。第一个是你已经拥有的 - 明确选择那些嵌套元素并更新它们的数据。然而,这需要额外的代码并且依赖于嵌套元素的顺序与它们的父元素相同,这是不可保证的。
更好的方法是使用.selectAll()
简单地将第143和144行中的.select()
替换为g
。这是可能的,因为每个类型只有一个元素嵌套在.selectAll()
下面,所以选择只包含一个元素。在这种情况下,.select()
和.selectAll()
之间的主要区别在于,虽然.select()
不会更新绑定到所选元素的数据,但{{1}}会更新。效果与当前解决方案相同 - 绑定到嵌套元素的数据会正确更新,除非您不需要任何其他代码,也不依赖于所选元素的顺序。
完整演示here。