D3.js动画更新堆积条形图

时间:2017-01-15 20:35:06

标签: javascript d3.js stackedbarseries

我正在尝试使用转换更新堆积条形图,因为基础数据已更改。它每次都调用相同的“渲染”功能,并且在不涉及过渡时效果很好。但是,我想动画值的变化,从当前状态转换到下一个状态。

我已经解决了这个问题,但感觉我的解决方案很笨重 - 希望有更好的方法来实现叠加条形图。

我的方法是做以下事情:

  1. 加载数据
  2. 加载初始条件(转换请求)
  3. 加载最终条件(转换中)
  4. 将当前数据复制到另一个阵列: prevData
  5. 间隔后重新加载数据
  6. 使用上述方法,如果prevData具有值,则使用这些来设置初始条件。我的问题是找到并设定初始条件感觉非常笨重:

    if (prevData.length > 0) {
                                //get the parent key so we know who's data we are now updating
                                var devKey = d3.select(this.parentNode).datum().key;
    
                                //find the data associated with its PREVIOUS value
                                var seriesData = seriesPrevData.find(function (s) { return (s.key == devKey); })
                                if (seriesData != null) {
                                    //now find the date we are currently looking at
                                    var day = seriesData.find(function (element) { return (element.data.Date.getTime() == d.data.Date.getTime()); });
    
                                    if (day != null) {
                                        //now set the value appropriately
                                        //console.debug("prev height:" + devKey + ":" + day[1]);
                                        return (y(day[0]) - y(day[1]));
                                    }
                                }
    
                            }
    

    我正在做的就是找到正确的密钥数组(由d3.stack()创建),然后尝试查找适当的先前数据条目(如果存在)。但是,搜索父节点,搜索数组以查找所需的键和相应的数据元素感觉非常冗长。

    所以,我的问题是,有更好的方法吗?或部分内容?

    1. 在功能中更改之前,找到与此元素关联的以前绑定数据值或当前值。
    2. 更好地找到当前正在更新的密钥而不是使用:d3.select(this.parentNode)...?我尝试过传递关键值,但似乎没有做到正确。我所取得的最好成绩是将一个关键功能传递给父母,并按照上述方式寻找它。
    3. 对于这篇长篇文章感到抱歉,我只花了一整天的时间来解决我的解决方案,因为所有我真正需要的事情都是项目的先前值。必须做所有这些“体操”以获得我需要的东西似乎非常“不”D3.js喜欢: - )

      由于

1 个答案:

答案 0 :(得分:1)

以下是动画条形图的简单示例。它将迭代两个不同版本的数据集,以显示如何使用d3轻松处理基础数据中的更改。对于转换/动画,不需要(在此示例中)任何手动数据准备。



var data = [
  [1, 2, 3, 4, 5],
  [1, 6, 5, 3]
];

var c = d3.select('#canvas');

var currentDataIndex = -1;
function updateData() {

    // change the current data
    currentDataIndex = ++currentDataIndex % data.length;
    console.info('updating data, index:', currentDataIndex);
    var currentData = data[currentDataIndex];
  
    // get our elements and bind the current data to it
    var rects = c.selectAll('div.rect').data(currentData);

    // remove old items
    rects.exit()
        .transition()
        .style('opacity', 0)
        .remove(); 

    // add new items and define their appearance
    rects.enter()
        .append('div')
        .attr('class', 'rect')
        .style('width', '0px');

    // change new and existing items
    rects
        // will transition from the previous width to the current one
        // for new items, they will transition from 0px to the current value
        .transition()
        .duration('1000')
        .ease('circle')
        .style('width', function (d) { return d * 50 + 'px'; });
    
}

// initially set the data
updateData();

// keep changing the data every 2 seconds
window.setInterval(updateData, 2000);

div.rect {
  height: 40px;
  background-color: red;
}

div#canvas {
  padding: 20px;
  border: 1px solid #ccc;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<div id="canvas">  
</div>
&#13;
&#13;
&#13;