D3 - 从v3升级到v4时,forEach不是一个功能

时间:2017-11-02 15:17:27

标签: javascript d3.js foreach

我正在尝试将this可堆叠条形图升级到v4。 除了一件事,一切都有效。

当我过滤一个类别时,条形不会落到x轴的开头。我收到一个错误,上面写着:

  

state.selectAll(...)。forEach不是函数

我已经尝试过多种方法,但我无法解决这个问题。 这是破碎的代码:

function plotSingle(d) {

class_keep = d.id.split("id").pop();
idx = legendClassArray.indexOf(class_keep);

//erase all but selected bars by setting opacity to 0
d3.selectAll(".bars:not(.class" + class_keep + ")")
    .transition()
    .duration(1000)
    .attr("width", 0) // use because svg has no zindex to hide bars so can't select visible bar underneath
    .style("opacity", 0);

//lower the bars to start on x-axis
state.selectAll("rect").forEach(function(d, i) {

    //get height and y posn of base bar and selected bar
    h_keep = d3.select(d[idx]).attr("height");
    y_keep = d3.select(d[idx]).attr("y");

    h_base = d3.select(d[0]).attr("height");
    y_base = d3.select(d[0]).attr("y");

    h_shift = h_keep - h_base;
    y_new = y_base - h_shift;

    //reposition selected bars
    d3.select(d[idx])
        .transition()
        .ease("bounce")
        .duration(1000)
        .delay(750)
        .attr("y", y_new);

})
}

我觉得奇怪的是,这在D3 v3中完美无缺,为什么这不会在v4中运行?

1 个答案:

答案 0 :(得分:6)

在d3 v3中,selectAll返回一个数组,在d3 v4中它返回一个对象。

来自v3 notes

  

选择是元素数组 - 字面意思(可能不是字面意思......)。   D3将其他方法绑定到数组,以便您可以应用   运算符到选定的元素,例如设置属性   所有选定的元素。

changes in v4包括:

  

选择不再使用原型链注入子类化Array;   它们现在是普通物体,提高了性能。内部字段   (selection._groups,selection._parents)是私有的;请使用   记录用于操纵选择的公共API。新的   selection.nodes方法生成选择中所有节点的数组。

如果要在v4中访问每个节点,请尝试:

selection.nodes().forEach( function(d,i) { ... })

但是,这只是节点,用于获取选择每个节点所需的数据:

var data = [0,1,2];

var svg = d3.select("body").append("svg")
  .attr("width",500)
  .attr("height",200)

var circles = svg.selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", function(d,i) { return i * 20 + 50 })
  .attr("cy", 50)
  .attr("r", 4);
  
  
circles.nodes().forEach(function(d,i) {
    console.log(d3.select(d).data());
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

但是,如果您需要数据或修改选择属性,则可以更容易地使用selection.each()。 d3.each遍历d3选择本身的每个元素,并允许您为选择中的每个元素调用一个函数(请参阅API文档here):

var data = [0,1,2];

var svg = d3.select("body").append("svg")
  .attr("width",500)
  .attr("height",200)

var circles = svg.selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", function(d,i) { return i * 20 + 50 })
  .attr("cy", 50)
  .attr("r", 4);
  

  
circles.each( function() {
  console.log(d3.select(this).data());  
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"></script>

在此条形图的第3版中,在forEach循环中

`states.selectAll("rect").forEach(function(d,i) {`

d是一个节点数组(每个.g中的矩形)。

但是,在v4中,d3选择不是数组,您不能以相同的方式使用forEach循环。但是你仍然可以使用selection.nodes()获取其中的节点而不需要进行太多修改,而是让childNodes在v3版本中复制数组:

state.nodes().forEach(function(d, i) {
            var nodes = d.childNodes;

这里我们遍历state中的每个元素/节点并获取子rect,作为数组返回。这是一个更新的fiddle