我有一个数组,看起来像
一样简单var labels = ['label 1', 'label2', ..., 'label n']
现在,如果我想将它们作为视觉元素放在图表中,我可以这样做:
var legendItem = legendArea
.selectAll('g')
.data(labels)
.enter()
.append('g')
.attr({class: 'legend-element'});
legendArea
现在成为所有标签的父级。但是,我有一个更复杂的场景,我需要将标签直接放在legendArea
中,但首先在g
内创建一个包装legendArea
元素,然后它将包含一组标签,取决于我从每个标签获得的一些标准。
因此,我将拥有一些g
元素,其中包含一组标签,一个可以有5个,另一个可以有8个,任意数字,因为它们不均匀分布。
我现在看到的是,我需要在所有标签数组元素中运行循环,检查当前标签是否符合条件,如果需要,创建一个新的包装元素然后追加。但是这个解决方案似乎不是D3风格的,因为在大多数情况下,可以使用D3进行功能样式代码,而不是for..loop
。
我怀疑我可以在这里做一些更自定义的事情,例如:
var legendItem = legendArea
.selectAll('g')
.data(labels)
.enter()
// Do some unknown D3 magic here to create a new wrapper element and append the label to it.
.attr({class: 'legend-element'});
请告知如何以D3方式进行操作。
答案 0 :(得分:0)
我会得到一个类别列表,将其用作g
元素的数据,然后使用过滤器添加其余类别:
var cats = svg.selectAll("g").data(categories)
.enter().append("g")
.attr("transform", function(d, i) { return "translate(10," + ((i+1) * 30) + ")"; });
cats.selectAll("text")
.data(function(d) { return data.filter(function(e) { return e.category == d; }); })
.enter().append("text")
.text(function(d) { return d.label; });
这类似于nested selections,除了嵌套不是数据本身(尽管你也可以修改数据结构),但是通过引用不同的数据结构。
第一个代码块只为每个类别添加一个g
元素。第二个代码块执行嵌套选择(因此能够在之前引用绑定到g
元素的数据)。在.data()
函数中,我们获取所有数据并过滤掉与当前类别匹配的项目。其余的再次是沼泽标准D3。
完整演示here。