d3连接数组中的对象键

时间:2014-03-18 17:57:08

标签: d3.js

我的数据如下:

[
   {
      name: "Joel Spolsky",
      values: [
                {
                   timestamp: 1380432214730,
                   value: 55
                },
                {
                   timestamp: 1380432215730,
                   value: 32
                },   
                {
                   timestamp: 1380432216730,
                   value: 2
                },   
                {
                   timestamp: 1380432217730,
                   value: 37
                },

                // etc
              ]     
    },
   {
      name: "Soul Jalopy",
      values: [
                {
                   timestamp: 1380432214730,
                   value: 35
                },
                {
                   timestamp: 1380432215730,
                   value: 72
                },   
                {
                   timestamp: 1380432216730,
                   value: 23
                },   
                {
                   timestamp: 1380432217730,
                   value: 3
                },

                // etc
              ]     
    },

    // and so on
]

我将此数据传递到d3.layout.stack,以便添加yy0。然后我绘制这个堆叠的布局。

当数据发生变化时,我将新数据加入旧数据。

我可以像name这样加入小组:

var nameGroups = this.chartBody.selectAll(".nameGroup")
        .data(this.layers, function (d) {
                return d.name;
             });

但是我在时间戳上加入矩形(或#34; bar")时遇到了麻烦。我能做的最好(到目前为止)是将它们加在values键上:

var rects = nameGroups.selectAll("rect")
        .data(function (d) {
                return d.values;
              });

我如何加入这个"内部数据"在timestamp键上?

我尝试过包含数组索引:

var rects = nameGroups.selectAll("rect")
        .data(function (d, i) {
                return d.values[i].timestamp;
              });

但这并不起作用,因为(我认为)时间戳匹配每个数组索引。也就是说,连接不会查看匹配的所有时间戳值,只是该索引处的值。

更新

这是我的完整更新功能:

updateChart: function (data) {
    var that = this,
        histogramContainer = d3.select(".histogram-container"),
        histogramContainerWidth = parseInt(histogramContainer.style('width'), 10),
        histogramContainerHeight = parseInt(histogramContainer.style('height'), 10),
        width = histogramContainerWidth,
        height = histogramContainerHeight,
        nameGroups, rects;

    /*
     FWIW, here's my stack function created within my
     init function:

     this.stack = d3.layout.stack()
         .values(function (d) { return d.values; })
         .x(function (dd) { return dd.timestamp; })
         .y(function (dd) { return dd.value; });

     */

    // save the new data
    this.layers = this.stack(data);

    // join the new data to the old via the "name" key
    nameGroups = this.chartBody.selectAll(".nameGroup")
        .data(this.layers, function (d, i) {
            return d.name;
        });

    // UPDATE
    nameGroups.transition()
        .duration(750);

    // ENTER
    nameGroups.enter().append("svg:g")
        .attr("class", "nameGroup")
        .style("fill", function(d,i) {
            //console.log("entering a namegroup: ", d.name);
            var color = (that.colors[d.name]) ?
                    that.colors[d.name].value :
                    Moonshadow.helpers.rw5(d.name);
            return "#" + color;
        });

    // EXIT
    nameGroups.exit()
        .transition()
        .duration(750)
        .style("fill-opacity", 1e-6)
        .remove();

    rects = nameGroups.selectAll("rect")
        .data(function (d) {

            // I think that this is where the change needs to happen

            return d.values;

        });

    // UPDATE
    rects.transition()
        .duration(750)
        .attr("x", function (d) {
            return that.xScale(d.timestamp);
        })
        .attr("y", function(d) {
            return -that.yScale(d.y0) - that.yScale(d.y);
        })
        .attr("width", this.barWidth)
        .attr("height", function(d) {
            return +that.yScale(d.y);
        });

    // ENTER 

    rects.enter().append("svg:rect")
        .attr("class", "stackedBar")
        .attr("x", function (d) {
            return that.xScale(d.timestamp); })
        .attr("y", function (d) {
            return -that.yScale(d.y0) - that.yScale(d.y); })
        .attr("width", this.barWidth)
        .attr("height",function (d) {
            return +that.yScale(d.y); })
        .style("fill-opacity", 1e-6)
        .transition()
        .duration(1250)
        .style("fill-opacity", 1);

    // EXIT

    rects.exit()
        .transition()
        .duration(750)
        .style("fill-opacity", 1e-6)
        .transition()
        .duration(750)
        .remove();
}

1 个答案:

答案 0 :(得分:1)

您实际上并未在代码中传递密钥功能。关键函数是.data()的可选第二个参数(参见the documentation)。所以在你的情况下,代码应该是

.data(function(d) { return d.values; },
      function(d) { return d.timestamp; })

这里第一个函数告诉D3如何从嵌套的上层提取值,第二个函数告诉第一个参数中提取的数组中的每个项如何获取键。