根据D3的条件将元素附加到不同的容器中

时间:2015-05-10 18:42:40

标签: javascript d3.js

我有一个数组,看起来像

一样简单
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方式进行操作。

1 个答案:

答案 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