selectAll仅在D3中工作一次

时间:2014-03-31 23:29:21

标签: javascript d3.js selection

我对这一个很生气...... 第一次调用时,refreshGraph()完美运行:显示我的图表 接下来的电话,没有任何反应。 selectAll()按预期返回一个数组数组,但我的图形不会改变 但是......如果我使用select()而不是selectAll(),它就可以了! 最糟糕的...如果我在join.selectAll(" .bar")之前添加join.select(" .bar"),它也可以!

任何人都可以解释我为什么?

我不明白这种行为。我完全理解select()和selectAll()应该返回什么。在两个返回的子选择上调用style()应该给出相同的结果,因为数据是相同的,即使按组使用selectAll进行组织,并使用select进行平展。我是对的吗?

var srcData = [4, 8, 15, 16, 23, 42];

x = d3.scale.linear().domain([0, 42]).range([0, 420]);

function refreshGraph() {

    join = d3.select(".chart").selectAll(".container").data(srcData);

    join.enter()
    .append("span").attr("class","container")
    .append("div").attr("class","bar");

    join
    .selectAll(".bar") // wont work, but will if select() instead of selectAll()
    .style("width", function(d) { 
        return x(d) + "px";
    });
}

function doChange() {
    for (var i = 0; i < srcData.length; i++) {
        srcData[i] /= 2;
    }
    refreshGraph();
}

refreshGraph();

2 个答案:

答案 0 :(得分:5)

这里的问题是数据绑定到子元素时。

  • 每次再次调用.container时,.selectAll('.container').data(srcData)元素的初始数据都会被绑定,而重新绑定时,新数据会被绑定。< / p>

  • .bar元素的数据在创建时绑定,当它们附加到.container元素时,但绑定新数据时会反弹到.container

修复方法是每次拨打.bar时强行将refreshData数据重新绑定到其父级:

join
    .selectAll(".bar")
    .data(function(d) { return [d]; })
    .style("width", function(d) { 
        return x(d) + "px";
    });

答案 1 :(得分:5)

经过几个小时的阅读文档,然后踩到D3代码,我终于明白了。我结合了几个案例,这让我陷入困境。 那么,这是关于什么的?

 join = d3.select(".chart").selectAll(".container").data(srcData);
 join.enter()
.append("span").attr("class","container")
.append("div").attr("class","bar");

append()函数可以帮助您:

将具有指定名称的新元素追加为当前选择中每个元素的最后一个子元素,并返回包含附加元素的新选择。 每个新元素都会以与选择子选择相同的方式继承当前元素的数据(如果有)。

但是...... 继承这个词有误导性。您必须阅读:每个新元素从当前元素 接收副本数据

正如D3的工作方式,没有魔法绑定。与每次要反映值更改时重新绑定数据的方式相同,您必须在正确的节点中设置数据。 append()函数为你完成了工作,select()函数也可以这样做,但是selectAll()没有。

对于当前选择中的每个元素,选择与指定选择器字符串匹配的后代元素。 ... 子选择不会从当前选择继承数据;

在我的问题代码中,在第一次调用时,数据通过append()从.container复制到.bar元素。由于数据的数量没有变化(没有新值/没有更少的值),后续调用绕过append()函数(enter()部分为空)而selectAll()将获得正确的节点(.bar分类)仍然有以前的数据版本。调用style()时,这不是应用的新数据。

当然,使用select()可以使它工作,因为它将数据从祖先复制到子选择元素。

nrabinowitz给出了正确的答案:如果你绝对想要使用selectAll,你必须使用一个函数来检索分组节点的数据。

selectAll()doc说:返回的选择按当前选择中的祖先节点分组...如果数据值被指定为函数,则会调用此函数使用祖先节点的数据d和组索引i来确定子选择的数据绑定。

希望它会有所帮助...