我是d3.js的新手,正在努力完成“D3.js in action”一书。到目前为止,我已经能够弄清楚我所有的问题,但是这个我自己无法完全回答,似乎。
我在这里发布了书中的源代码,因为它可以在书籍网站和作者主页上找到。这是bl.ocks:http://bl.ocks.org/emeeks/raw/186d62271bb3069446b5/
代码的基本思想是用div元素创建一个类似电子表格的布局,这些元素充满了虚构的twitter数据。还实现了一种排序功能,用于按时间戳对数据进行排序并对工作表重新排序。以及重建原始订单的功能。
这是代码(我省略了创建表结构的部分,除了绑定数据的部分):
<html>
<...>
<body>
<div id="traditional">
</div>
</body>
<footer>
<script>
d3.json("tweets.json",function(error,data) { createSpreadsheet(data.tweets)});
function createSpreadsheet(incData) {
var keyValues = d3.keys(incData[0])
d3.select("div.table")
.selectAll("div.datarow")
.data(incData, function(d) {return d.content})
.enter()
.append("div")
.attr("class", "datarow")
.style("top", function(d,i) {return (40 + (i * 40)) + "px"});
d3.selectAll("div.datarow")
.selectAll("div.data")
.data(function(d) {return d3.entries(d)})
.enter()
.append("div")
.attr("class", "data")
.html(function (d) {return d.value})
.style("left", function(d,i,j) {return (i * 100) + "px"});
d3.select("#traditional").insert("button", ".table")
.on("click", sortSheet).html("sort")
d3.select("#traditional").insert("button", ".table")
.on("click", restoreSheet).html("restore")
function sortSheet() {
var dataset = d3.selectAll("div.datarow").data();
dataset.sort(function(a,b) {
var a = new Date(a.timestamp);
var b = new Date(b.timestamp);
return a>=b ? 1 : (a<b ? -1 : 0);
})
d3.selectAll("div.datarow")
.data(dataset, function(d) {return d.content})
.transition()
.duration(2000)
.style("top", function(d,i) {return (40 + (i * 40)) + "px"});
}
function restoreSheet() {
d3.selectAll("div.datarow")
.transition()
.duration(2000)
.style("top", function(d,i) {return (40 + (i * 40)) + "px"});
}
}
</script>
</footer>
</html>
我还不完全了解sortSheet和restoreSheet的工作原理。
sortSheet的这一部分看起来像重新绑定数据,但在控制台日志记录之后,我认为它实际上并没有将数据重新绑定到DOM。相反,它似乎只是根据排序数组的数组索引重绘div.tablerow元素。
但那么关键功能的目的是什么? 为什么过渡有效?它如何知道哪个旧元素放在哪个新位置?
编辑:
---经过一些阅读后,我现在知道selectAll().data()
确实返回了更新选择。表示关键函数识别的已绑定数据是否重新排序以匹配新数据集中键的顺序?那是对的吗?
因此,更新选择包含现有的div.datarow
,但是以新的顺序排列。 transition()
函数适用于新订单,绘制新索引的div.datarow
以索引0开头,第一个元素确定其在页面上的位置,为最后一个元素索引n。那么以某种方式(如何?通过更新选择?)的图形转换知道重绘div.datarow
之前的位置并创建转换效果。
到目前为止这是正确的吗?---
d3.selectAll("div.datarow")
.data(dataset, function(d) {return d.content}) //why the key function?
.transition()
.duration(2000)
.style("top", function(d,i) {return (40 + (i * 40)) + "px"});
原始订单恢复后会发生什么?显然在两个操作期间都没有实际的数据重新绑定,并且DOM中div.datarow
的顺序不会改变。因此,还原功能还会根据数组索引重新绘制布局。
但.transition()的工作选择是什么? 是更新吗?这是一次更新。
为什么使用索引的绘图会导致旧布局? DOM元素的索引不应该总是0,1,...,n?我认为是。显然重绘了旧的页面布局,DOM从未改变过。但是transition()函数如何创建适当的图形效果呢?
function restoreSheet() {
d3.selectAll("div.datarow")
.transition()
.duration(2000)
.style("top", function(d,i) {return (40 + (i * 40)) + "px"});
}
我一直在想这个问题,但我想不出正确的答案。 谢谢你的帮助!
答案 0 :(得分:0)
当您了解调用所有这些函数的位置时,一切都变得清晰:json
函数内部,数据最初绑定的位置。当一个按钮调用sortSheet
函数时,会生成一个新的对象数组并绑定到这些行。转换只是从原始顺序开始,并根据数组内对象的新顺序移动行。
原始订单恢复后会发生什么?
现在出现了一个有趣的部分:restoreSheet
在json
函数内部被调用,无法访问dataset
变量。因此,restoreSheet
使用的数据是原始数据。然后,转换只是根据原始数组中对象的顺序移动行。
我只是简单地复制了这个:https://jsfiddle.net/k9012vro/2/
检查代码:我有一个包含原始数据的数组。然后,一个名为&#34; sort&#34;的按钮创建一个新数组。
点击&#34;原创&#34;矩形移回原始位置。但是该功能没有什么特别之处,没有新的数据被绑定:
d3.select("#button1").on("click", function(){
rects.transition()
.duration(500).attr("x", function(d, i){ return i * 30})
});
它将所有矩形移动到原始位置,因为此函数使用相同的原始data
。