D3.js 堆叠条形图的动画更新
D3.js animating update of stacked bar graph
我正在尝试在基础数据发生变化时更新带有过渡的堆叠条形图。它每次都调用相同的 "render" 函数,并且在不涉及转换时运行良好。但是,我想为值的变化设置动画,从当前状态过渡到下一个状态。
我已经稍微解决了这个问题,但感觉我的解决方案很笨拙 - 希望有更好的方法来为堆叠条形图执行此操作。
我的方法是执行以下操作:
- 加载数据
- 加载初始条件(转换要求)
- 加载最终条件(在转换中)
- 复制当前数据到另一个数组:prevData
- 间隔后重新加载数据
使用上述方法,如果 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() 创建),然后尝试找到适当的先前数据条目(如果存在)。但是,搜索父节点,搜索数组以找到所需的键和合适的数据元素感觉很啰嗦。
所以,我的问题是,有没有更好的方法来做到这一点?还是其中的一部分?
- 查找与此元素相关联的 previously 绑定数据值或在函数内更改之前的 current 值。
- 找到正在更新的当前密钥的更好方法而不是使用:d3.select(this.parentNode)...?我试过传递键值,但似乎没有正确传递。我取得的最好成绩是将一个关键函数传递给父级,然后按照上述方式查找它。
抱歉这么久了 post,我只是花了一整天的时间来制定我的解决方案,因为我真正需要的是项目的先前值而感到沮丧。必须做所有这些 "gymnastics" 才能得到我需要的东西似乎非常 "un" D3.js 像:-)
谢谢
以下是动画条形图的简单示例。它将遍历两个不同版本的数据集,以展示如何使用 d3 轻松处理基础数据的变化。不需要(在此示例中)为 transition/animation 进行任何手动数据准备。
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>
我正在尝试在基础数据发生变化时更新带有过渡的堆叠条形图。它每次都调用相同的 "render" 函数,并且在不涉及转换时运行良好。但是,我想为值的变化设置动画,从当前状态过渡到下一个状态。
我已经稍微解决了这个问题,但感觉我的解决方案很笨拙 - 希望有更好的方法来为堆叠条形图执行此操作。
我的方法是执行以下操作:
- 加载数据
- 加载初始条件(转换要求)
- 加载最终条件(在转换中)
- 复制当前数据到另一个数组:prevData
- 间隔后重新加载数据
使用上述方法,如果 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() 创建),然后尝试找到适当的先前数据条目(如果存在)。但是,搜索父节点,搜索数组以找到所需的键和合适的数据元素感觉很啰嗦。
所以,我的问题是,有没有更好的方法来做到这一点?还是其中的一部分?
- 查找与此元素相关联的 previously 绑定数据值或在函数内更改之前的 current 值。
- 找到正在更新的当前密钥的更好方法而不是使用:d3.select(this.parentNode)...?我试过传递键值,但似乎没有正确传递。我取得的最好成绩是将一个关键函数传递给父级,然后按照上述方式查找它。
抱歉这么久了 post,我只是花了一整天的时间来制定我的解决方案,因为我真正需要的是项目的先前值而感到沮丧。必须做所有这些 "gymnastics" 才能得到我需要的东西似乎非常 "un" D3.js 像:-)
谢谢
以下是动画条形图的简单示例。它将遍历两个不同版本的数据集,以展示如何使用 d3 轻松处理基础数据的变化。不需要(在此示例中)为 transition/animation 进行任何手动数据准备。
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>