对数据连接感到困惑,选择并选择所有

时间:2013-05-14 02:25:14

标签: d3.js

我对数据连接感到困惑。

我有一个名为gEnter的输入组元素,我追加

gEnter.append("g").attr("class", "dataLabels");

dataLabels是我将要生成的每个数据标签的容器元素。

g是原始组元素的更新选择。我像这样绑定我的数据:

var dataLabels = g.select(".dataLabels")
    .selectAll(".dataLabel")
    .data(function(d) {return d;});

其中d来自父g元素。对于每个新数据点,我追加.dataLabel,并给它一个距离轴30像素的起始位置:

var dataLabelsEnter = dataLabels.enter()
    .append("g")
    .attr("class", "dataLabel")
    .attr("transform", function(d, i) { return "translate("+ (xScale(d.category) + (xScale.rangeBand() / 2)) +","+(yScale(0) - 30)+")"; });

每个.dataLabel本身就是两个text元素的容器,因此我会为每个新数据点附加它们:

dataLabelsEnter.append("text")
    .attr("class", "category")
    .attr("text-anchor", "middle")
    .style("font-weight", function(d, i) {
        return (d.category == 'Total')
            ? 'bold'
            : 'normal';
    })
    .text(function(d) {return d.category;});

dataLabelsEnter.append("text")
    .attr("class", "value")
    .attr("text-anchor", "middle")
    .attr("transform", "translate(0,20)")
    .style("font-weight", "bold")
    .style("fill", function(d, i) { 
        return (d.count >= 0)
            ? '#1f77b4'
            : '#BB1A03';
    })
    .text(function(d) {
        var accounting = d3.format(",");
        return (d.count >= 0)
            ? '+$' + accounting(d.count)
            : '-$' + accounting(-d.count);
    });

然后我转到我的更新代码,事情变得有趣。首先,我更新容器.dataLabel元素的位置。这很有效:

dataLabels
    .transition()
    .duration(duration)
    .attr("transform", function(d, i) {return "translate("+ (xScale(d.category) + (xScale.rangeBand() / 2)) +","+( yScale(d3.max([d.count,0])) - 30)+")"; });

现在我想更新标签的值。我试试这个:

dataLabels
    .selectAll(".value")
    .text(function(d, i) {
        var accounting = d3.format(",");
        // return d.count;
        return (d.count >= 0)
            ? '+$' + accounting(d.count)
            : '-$' + accounting(-d.count);
    });

但它不起作用。我尝试使用.data(function(d){return d;})重新绑定数据,但无济于事。无论我做什么,即使数据更新,这里仍然与初始绘制相同。但是,如果我切换到

dataLabels
    .select(".value")
    .text(function(d, i) {
        var accounting = d3.format(",");
        // return d.count;
        return (d.count >= 0)
            ? '+$' + accounting(d.count)
            : '-$' + accounting(-d.count);
    });

它有效。

任何人都可以解释为什么后一种选择会更新数据,但之前的选择不是吗?我读过Mike Bostock's recent article on selections,但我仍然有点困惑。我认为它与文章中的这句话有关:

  

只有selectAll有关于分组的特殊行为;选择保留现有分组。

也许selectAll正在从每个.dataLabel元素创建新组,但数据没有绑定到它们?我只是不确定。

1 个答案:

答案 0 :(得分:2)

不同之处在于selection.select将数据从父传播到子传输,而selection.selectAll则不传播。请在Non-Grouping Operations部分中再次阅读您引用的段落:

  

只有selectAll有关于分组的特殊行为;选择保留现有分组。 select方法不同,因为旧选择中每个元素的新选择中只有一个元素。因此,select也会将数据从parent传播到child,而selectAll则不传播(因此需要数据连接)!

因此,当您在dataLabels上进行数据连接时,您已更新了父元素的数据。但是当您调用dataLabels.selectAll(".value")时,它不会传播数据,因此您获得了子数据。如果切换到dataLabels.select(".value"),它会将数据传播到选定的子项,因此您可以再次获取新数据。

您也可以使用selection.data传播数据,但由于每个标签在此处都有一个值元素,因此使用selection.select更容易。

(另外,您可能需要指定key function。)