【问题标题】:d3js : How to select nth element of a group?d3js:如何选择组的第 n 个元素?
【发布时间】:2015-05-30 10:45:54
【问题描述】:

我创建了一个包含 9 个元素(圆圈)的组,例如:

// JS
var data=[ 1,2,3,4,5,6,7,8,9 ];
var svg = d3.select("body").append("svg");
var circles = svg.append("g").attr("id", "groupOfCircles")
    .selectAll("circle")
        .data(data)
    .enter().append("circle")
        .attr("cx", function(d){ return d*20;})
        .attr("cy", function(d){ return d*10;})
        .attr("r" , function(d){ return d;})
        .attr("fill","green");

//xml
<svg>
    <g id="groupOfCircles">
        <circle cx="20" cy="10" r="1" fill="green"></circle>
        <circle cx="40" cy="20" r="2" fill="green"></circle>
        <circle cx="60" cy="30" r="3" fill="green"></circle>
        <circle cx="80" cy="40" r="4" fill="green"></circle>
        <circle cx="100" cy="50" r="5" fill="green"></circle>
        <circle cx="120" cy="60" r="6" fill="green"></circle>
        <circle cx="140" cy="70" r="7" fill="green"></circle>
        <circle cx="160" cy="80" r="8" fill="green"></circle>
        <circle cx="180" cy="90" r="9" fill="green"></circle>
    </g>
</svg>

但是如何在不知道圈子的 id 或属性值的情况下选择groupOfCircles 组的第 n 个元素(即:第 3 个圈子)?

稍后我将通过 for 循环遍历所有元素,并为每个元素着色一秒钟。


注意:我尝试过诸如:

  circles[3].attr("fill","red") // not working
  d3.select("#groupOfCircles:nth-child(3)").attr("fill","red")  // not working
  ..

【问题讨论】:

    标签: d3.js


    【解决方案1】:

    选择器必须是circle:nth-child(3)——child表示该元素是第n个子元素,而不是选择元素的第n个子元素(见here)。

    你也可以使用:

        // JS
        var data=[ 1,2,3,4,5,6,7,8,9 ];
        var svg = d3.select("body").append("svg");
        var circles = svg.append("g").attr("id", "groupOfCircles")
            .selectAll("circle")
                .data(data)
            .enter().append("circle")
                .attr("cx", function(d){ return d*20;})
                .attr("cy", function(d){ return d*10;})
                .attr("r" , function(d){ return d;})
                .attr("fill","green");
        
        d3.select("circle:nth-child(3)").attr("fill","red"); // <== CSS selector (DOM)
        d3.select(circles[0][4]).attr("fill","blue"); // <== D3 selector (node)
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • d3 v4 怎么样?你不能再做circles[0][4]了。
    • 内部结构发生了变化,但您仍然可以这样做:circles._groups[0][4]
    【解决方案2】:

    如果你想在 d3 逻辑中这样做,匿名函数总是在数据旁边有一个索引参数:

    my_selection.attr("fill",function(d,i) {return i%3==0?"red":"green";});
    

    http://jsfiddle.net/risto/os5fj9m6/

    【讨论】:

    • 这是我通常采用的方式,但我认为当您真正想要更改单个元素时重新绘制所有选择有点过分。
    • 颜色只设置一次,绘制圆圈时。您当然不必重新选择所有内容。而您的原始方法会重新选择。
    • 其实我会 1. 画绿色圆圈; 2. 做一个更新循环,为目标圆圈重新着色 1 秒。如果我在我的 for 循环中重用您的return i===3?"red":"green",在每个循环中,我将重绘所有圆圈,并将符合条件的圆圈涂成红色。 (如果我理解 d3 很好)
    【解决方案3】:

    你也可以使用你的 circles 数组来设置元素的属性:

    d3.select(circles[3]).attr("fill","red");
    

    // JS
    var data=[ 1,2,3,4,5,6,7,8,9 ];
    var svg = d3.select("body").append("svg");
    var circles = svg.append("g").attr("id", "groupOfCircles")
        .selectAll("circle")
            .data(data)
        .enter().append("circle")
            .attr("cx", function(d){ return d*20;})
            .attr("cy", function(d){ return d*10;})
            .attr("r" , function(d){ return d;})
            .attr("fill","green");
    
    var group = document.querySelector('#groupOfCircles');
    var circleNodes = group.getElementsByTagName('circle');
    d3.select(circleNodes[3]).attr("fill", "red");
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 好吧,但它似乎不适用于我的小提琴。可以提供一份吗?
    • 这行不通,因为 D3 选择不是真正的数组,它需要类似于 circles[0][3].attr(...)d3.select(circles[0][3].node()).attr(...)
    • @Peter Ah 好的,您的 circles 不是 D3 选择,而是节点数组。在那种情况下它工作得很好,我只是假设它是像问题中那样的 D3 选择。
    【解决方案4】:

    这是使用函数作为选择器的另一种选择。

        circles.select(function (d,i) { return (i==3) ?  this : null;})
        .attr("fill", "red");
    

    如果选择器是一个函数,它将获取数据 (d) 和迭代器 (i) 作为参数。如果选中则返回对象 (this),如果未选中则返回 null。

    【讨论】:

      【解决方案5】:

      d3 v4 现在支持使用 selection.nodes() 返回此 selection 的所有元素的数组。然后,我们可以通过 d3.select(selection.nodes()[n]).attr(某事)

      // JS
      var data=[ 1,2,3,4,5,6,7,8,9 ];
      var svg = d3.select("body").append("svg");
      var circles = svg.append("g").attr("id", "groupOfCircles")
          .selectAll("circle")
              .data(data)
          .enter().append("circle")
              .attr("cx", function(d){ return d*20;})
              .attr("cy", function(d){ return d*10;})
              .attr("r" , function(d){ return d;})
              .attr("fill","green");
      
      circleElements = circles.nodes(); // <== Get all circle elements
      d3.select(circleElements[6]).attr("fill","red");
      &lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

      【讨论】:

      • 从节点重新选择可能效率不高,为什么 d3 不应该有 .eq() 的 jquery 等效项
      猜你喜欢
      • 2021-10-03
      • 1970-01-01
      • 1970-01-01
      • 2013-04-26
      • 1970-01-01
      • 2016-09-30
      • 1970-01-01
      • 2017-06-10
      • 2018-06-15
      相关资源
      最近更新 更多