有人可以解释D3.js中datum()和data()之间的区别吗?我看到两个都被使用了,我不确定你为什么要选择一个而不是另一个?
答案 0 :(得分:154)
我从迈克本人那里找到了正确答案:
D3 - how to deal with JSON data structures?
如果要将数据绑定到单个SVG元素,请使用
(...).data([data])
或
(...).datum(data)
如果要将数据绑定到多个SVG元素
(...).data(data).enter().append("svg")
.....
答案 1 :(得分:37)
以下是一些很好的链接:
关于D3“data()”的良好讨论: Understanding how D3.js binds data to nodes
根据后者:
# selection.data([values[, key]])
使用当前选择连接指定的数据数组。该 指定的值是一个数组值数组,例如数组 数字或对象,或返回值数组的函数。
...
# selection.datum([value])
获取或设置每个选定元素的绑定数据。不像 selection.data方法,此方法不计算连接(因此 不计算进入和退出选择。)
答案 2 :(得分:34)
在对此进行了一些调查之后,我发现SO上的答案并不完整,因为它们仅涵盖了您使用输入{selection.data
和selection.datum
调用{ {1}}参数。即使在那种情况下,如果选择是单个元素而不是包含多个元素,则两者的行为也不同。此外,这两种方法也可以在没有任何输入参数的情况下调用,以便查询选择中的绑定数据/数据,在这种情况下,它们再次表现不同并返回不同的东西。
编辑 - 我发布了一个稍微更详细的问题here的答案,但下面的帖子几乎抓住了关于这两种方法的所有关键点以及它们之间的差异。
提供 data
输入参数
data
会尝试在selection.data(data)
数组的元素之间执行数据连接,并选择data
,enter()
和exit()
update()
您可以随后操作的选项。最终结果是,如果传入数组data = [1,2,3]
,则尝试将每个单独的数据元素(即数据)与选择连接起来。选择的每个元素只有一个与data
绑定的基准元素。
selection.datum(data)
完全绕过数据加入过程。这简单地将整个data
分配给选择中的所有元素作为整体,而不像数据连接那样将其拆分。因此,如果要将整个数组data = [1, 2, 3]
绑定到selection
中的每个DOM元素,那么selection.datum(data)
将实现此目的。
警告: 许多人认为
selection.datum(data)
相当于selection.data([data])
但这只有在selection
包含单个元素。如果selection
包含 多个DOM元素,然后selection.datum(data)
将绑定 整数data
到选择中的每个元素。在 相反,selection.data([data])
仅绑定整个data
到selection
中的第一个元素。这符合selection.data
的数据连接行为。
不提供data
输入参数
selection.data()
将获取选择中每个元素的绑定数据,并将它们组合成一个返回的数组。因此,如果您的selection
包含3个DOM元素,其中数据"a"
,"b"
和"c"
分别绑定到每个元素,selection.data()
会返回["a", "b", "c"]
。重要的是要注意,如果selection
是单个元素(例如)与其绑定的基准"a"
,那么selection.data()
将返回["a"]
而不是"a"
{1}}正如有些人所期望的那样。
selection.datum()
仅对单个选择有意义,因为它被定义为返回绑定到选择的第一个元素的基准。因此,在上面的示例中,选择由绑定基准为"a"
,"b"
和"c"
的DOM元素组成,selection.datum()
只会返回"a"
。
请注意,即使
selection
只有一个元素,selection.datum()
和selection.data()
也会返回不同的值。前者返回选择的绑定数据(上例中的"a"
),而后者返回数组中的绑定数据(上例中的["a"]
)。
希望这有助于澄清selection.data
和selection.datum()
在提供数据作为输入参数和通过不提供任何输入参数查询绑定数据时彼此之间的差异。
PS - 了解其工作原理的最佳方法是从Chrome中的空白HTML文档开始,打开控制台并尝试向文档中添加一些元素,然后使用selection.data
开始绑定数据selection.datum
。有时候,#grok"更容易。通过阅读而不是阅读。
答案 3 :(得分:0)
我认为HamsterHuey给出的解释是迄今为止最好的。
为了扩展它并给出差异的直观表示,我创建了一个示例文档,该文档说明了data
和datum
之间的至少一部分差异。
下面的答案更多是使用这些方法得出的意见,但是如果我错了,我很乐意得到纠正。
该示例可以在下面或in this Fiddle下运行。
const data = [1,2,3,4,5];
const el = d3.select('#root');
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node => data: ${d}`);
const join= el
.selectAll('div.b')
.data(data);
join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
我认为datum
更容易掌握,因为它不进行联接,但这当然也意味着它具有不同的用例。
对我来说,一个很大的区别-尽管还有更多区别-事实上data
只是在d3图表上进行(实时)更新的自然方式,因为整个输入/更新/退出模式都可以做到这一点很简单,一旦您获得它。
datum
更适合静态表示。例如,在下面的示例中,我可以在原始数组上循环并按如下所示通过索引访问数据来达到相同的结果:
data.map((n, i) => {
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node-${n} => data: ${d[i]}`);
});
在这里尝试:https://jsfiddle.net/gleezer/e4m6j2d8/6/
再次,我认为这很容易掌握,因为您可以避免输入/更新/退出模式带来的精神负担,但是一旦您需要更新或更改选择,您肯定会更好地依靠.data()
。
const data = [1,2,3,4,5];
const el = d3.select('#root');
el
.append('div')
.classed('a', true)
.datum(data)
.text(d => `node => data: ${d}`);
const join= el
.selectAll('div.b')
.data(data);
join
.enter()
.append('div')
.classed('b', true)
.text((d, i) => `node-${i + 1} => data: ${d}`)
/* Ignore all the css */
html {
font-family: arial;
}
.l {
width: 20px;
height: 20px;
display: inline-block;
vertical-align: middle;
margin: 10px 0;
}
.l-a {
background: #cf58e4;
}
.l-b {
background: #42e4e4;
}
.a {
border-bottom: 2px solid #cf58e4;
}
.b {
border-bottom: 2px solid #42e4e4;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.6.0/d3.min.js"></script>
<div style="margin-bottom: 20px;">
<span class="l l-a"></span> .datum() <br />
<span class="l l-b"></span> .data()
</div>
<div id="root"></div>