通过索引从 d3js 选择中获取一个元素

Get one element from d3js selection, by index

我基于 3 个元素的数组创建了一组 d3js 元素:

var data = [[0,0,2],[0,23,5],[2,12,5]];
circleSet = svg.selectAll()
             .data(data)
             .enter().append('circle');

编辑:

如何 select 索引的第二个元素?

使用预设函数i变量,引用数组对象的索引

var data = [[0,0,2],[0,23,5],[2,12,5]];
circleSet = svg.selectAll()
     .data(data)
     .enter()
     .append('circle')
     .attr('fill',function(d,i){i === 1 ? return 'red' : return 'black' };

在 d3.js at this tutorial

中查找有关数组结构参考的更多信息

您还可以在分配 class.

时利用 i 索引的计数对您追加的每个元素进行编码
var data = [[0,0,2],[0,23,5],[2,12,5]];
    circleSet = svg.selectAll()
         .data(data)
         .enter()
         .append('circle')
         .attr("class",function(d,i){ return "yourclass item" + i })

var theSecondElement = d3.select(".item1")

最后,您可以使用 .each 方法和条件来定位特定元素

circleSet = svg.selectAll()
         .data(data)
         .enter()
         .append('circle')
         .each(function (d, i) {
            if (i === 1) {
              var that = this;
              (function textAdd() {
                 d3.select(that).append('h1').text(i); 
              )();   
            }
          });

仅操作一个元素的最自然方法是使用过滤函数:

var data = [[0,0,2],[0,23,5],[2,12,5]];
var circleSet = svg.selectAll()
         .data(data)
         .enter()
         .append('circle');
var filteredCircleSet = circleSet
         .filter(function (d, i) { return i === 1;})
         // put all your operations on the second element, e.g.
         .append('h1').text('foo');    

请注意,根据您对其他元素的处理方式,您可能会使用此方法的两种变体之一:

  • 变体a):在数据函数中使用过滤器(减少数据和附加元素)

  • 变体 b): 使用过滤器排除而不是包含以便在末尾删除其他元素

另见 Filter data in d3 to draw either circle or square

另一种方法是使用 selection.each 方法:https://github.com/mbostock/d3/wiki/Selections#wiki-each 通过使用带有相应索引的 if 语句,您可以为一个元素创建一个块。 例如

var data = [[0,0,2],[0,23,5],[2,12,5]];
var circleSet = svg.selectAll()
         .data(data)
         .enter()
         .append('circle')
         .each(function (d, i) {
            if (i === 1) {
              // put all your operations on the second element, e.g.
              d3.select(this).append('h1').text(i);    
            }
          });

在d3 v4及以上版本中,可以使用Selection.nodes()。假设 i 是你想要的索引号:

d3.select(someSelection.nodes()[i])

这是自然的 one-liner,而且可以说它更具可读性:您显然只是按顺序获取 i 处的节点,作为 D3 选择。


看起来 比替代方案更有效,后者涉及使用 .each() 遍历整个选择。所以,你可能认为这是 O(1),而其他选项是 O(n)

不幸的是,Selection.nodes() 本身包含一个 each 循环,所以它也是 O(n)(并不是说它在现实中可能很重要除非你在有数千个节点的选择上调用它数千次):

var nodes = new Array(this.size()), i = -1;
this.each(function() { nodes[++i] = this; });
return nodes;

但是,您可以通过这种方式将循环与获取分开,如果效率是主要问题,这可能会很有用。

例如,如果您想在选择 A 中遍历 each() 并从选择 B 中获取位于相同位置的项目,并且您希望避免 loops-within-loops,因为这些选择可能很大你多次调用它,你可以像这样构造它,这将是 O(2n) 而不是 O(n^2)

var selectionBArray = selectionB.nodes()

selectionA.each(function(d, i) {
  var iFromSelectionA = this
  var iFromSelectionB = d3.select(selectionBArray[i])
})

...或者如果您使用箭头函数来保留 this 上下文:

var selectionBArray = selectionB.nodes()

selectionA.each((d, i, nodes) => {
  var iFromSelectionA = d3.select(nodes[i])
  var iFromSelectionB = d3.select(selectionBArray[i])
})

您甚至可以 (ab) 使用 Selection._groups,但我不建议像那样使用私有 属性,因为如果 D3 更新重命名 _groups,它会中断属性, like this update did.