【问题标题】:Animating histogram with D3使用 D3 动画直方图
【发布时间】:2014-06-13 16:02:23
【问题描述】:

我在这个 jsFiddle here 上有一些代码,它为名为“值”的数据数组生成直方图。这一切都很好。

当我想用一个名为“newData”的新数据数组来更新这个直方图时,出现了问题。我正在尝试遵守enter()update()exit() D3 策略(我显然是非常新的)。确实会出现动画,但正如您从小提琴中看到的那样,它只是将所有内容压缩到右上角。有人能指出我在这段代码(更新)中做错了什么吗?

//Animations
d3.select('#new')
  .on('click', function(d,i) {
  var newHist = d3.layout.histogram().bins(x.ticks(bins))(newData);

  var rect = svg.selectAll(".bar")
   .data(values, function(d) { return d; });

  // enter
  rect.enter().insert("g", "g")
    .attr("class", "bar")
    .attr("transform", function(d) { return "translate(" + x(d) + "," + y(d) + ")"; });

  rect.enter().append("rect")
    .attr("x", 1)
    .attr("width", w)
    .attr("height", function(d) { return y(d); });
  rect.enter().append("text")
    .attr("dy", ".75em")
    .attr("y", 6)
    .attr("x", x(histogram[0].dx) / 2)
    .attr("text-anchor", "middle")
    .text(function(d) { return formatCount(d); });

  // update    
  svg.selectAll('.bar')
    .data(newHist)
    .transition()
    .duration(3000)
    .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; });
  svg.selectAll("rect")
    .data(newHist)
    .transition()
    .duration(3000)
    .attr("height", function(d) { return height - y(d.y); });
  svg.selectAll("text")
    .data(newHist)
    .transition()
    .duration(3000)
    .text(function(d) { return formatCount(d.y); });
    // exit
    rect.exit()
    .remove();
});

整个代码在上面链接的 JSFiddle 上。谢谢!

【问题讨论】:

    标签: javascript d3.js histogram


    【解决方案1】:

    看着上面的代码和小提琴,我突然想到了一些东西:

    • (第 85 行)您仍在绑定原始数据
    • (第 105、115 行)您正在多次绑定数据
    • (第 99 行)您仍在引用原始直方图变量,而没有使用新数据对其进行更新
    • 您正在为一组(更改)数据声明多个绑定/添加/更新/删除模式

    您在正确的轨道上,但您需要区分数据更改时需要更新的内容和数据更改时不应更新/声明的内容。您应该只需要声明一次 d3 模式(绑定、添加、更新、删除)...它将适用于更新的数据集。

    因此,在 makeHist(values) 函数之外尽可能多地声明,并且只在函数内包含需要更改数据的代码(这包括修改先前声明的比例的域和范围)。然后,on click 函数可以简单地使用新数据再次调用 makeHist 函数。

    这是一个粗略的大纲:

    // generate data
    
    // declare everything that can be static
    // (add svg to dom, declare axes, etc)
    
    // function that handles everything that new data should modify
    function makeHist(values) {
    
        // modify domains of axes, create histogram
    
        // bind data
        var rect = svg.selectAll('rect')
           .data(histogram);
    
        // add new elements
        rect.enter().append('rect');
    
        // update existing elements
        rect.transition()
            .duration(3000)
            .attr('transform', '...');
    
        // remove old elements
        rect.exit().remove();
    
    }
    
    // generate initial histogram
    makeHist(initialValues);
    
    // handle on click event
    d3.select('#new')
      .on('click', function() {
        makeHist(newData);
    });
    

    这是一个大部分工作的更新小提琴,但需要一点清理:

    http://jsfiddle.net/spanndemic/rf4cw/

    剧透警告:这两个数据集并没有那么不同

    【讨论】: