了解D3.js如何将数据绑定到节点上

81
我是一个有用的助手,可以为您翻译文本。

我正在阅读D3.js文档,发现很难理解文档中的selection.data方法

以下是文档中提供的示例代码:

var matrix = [
  [11975,  5871, 8916, 2868],
  [ 1951, 10048, 2060, 6171],
  [ 8010, 16145, 8090, 8045],
  [ 1013,   990,  940, 6907]
];

var tr = d3.select("body").append("table").selectAll("tr")
    .data(matrix)
  .enter().append("tr");

var td = tr.selectAll("td")
    .data(function(d) { return d; })
  .enter().append("td")
    .text(function(d) { return d; });

我理解这段代码的大部分内容,但是var td语句中的.data(function(d) { return d; })部分是什么意思呢?
我的猜测如下:
  • var tr语句将一个四元素数组绑定到每个tr节点上
  • 然后var td语句使用那个四元素数组作为它的数据,不知道是怎么做到的
但是.data(function(d) { return d; })是怎么获取数据的?它返回什么?

3
阅读这篇教程可能会有所帮助。 - Phrogz
谢谢!我现在明白代码中.enter()部分的作用了。不过,我想我可能需要等待未来的教程才能理解数据键函数的作用。 - Richard
4
我希望很快能够写一篇新的教程,涵盖关键功能和分层选择(selectAll.selectAll)。 - mbostock
3个回答

74

当你写下以下代码:

.data(someArray).enter().append('foo');
D3会创建一堆<foo>元素,每个元素对应数组中的一个条目。更重要的是,它还将每个条目的数据与DOM元素相关联,作为一个__data__属性。
尝试一下:
var data = [ {msg:"Hello",cats:42}, {msg:"World",cats:17} ]; 
d3.select("body").selectAll("q").data(data).enter().append("q");
console.log( document.querySelector('q').__data__ );

您将在控制台中看到对象{msg:"Hello",cats:42},因为它与第一个创建的q元素相关联。

如果您稍后执行:

d3.selectAll('q').data(function(d){
  // stuff
});

d的值实际上是__data__属性。(此时由你来确保将// stuff替换为返回新值数组的代码)

这里有另一个例子,显示了绑定到HTML元素的数据以及重新绑定子集数据到较低元素的能力:

  无描述


22
理解这段代码的关键是要认识到选择集是DOM元素的“数组中的数组”。最外层的数组被称为“选择集”,内部的数组被称为“组”,而这些组包含了DOM元素。您可以通过在d3js.org的控制台中进行选择,例如d3.selectAll('p'),然后您将看到一个包含“p”元素的数组。
在您的示例中,当您首次调用selectAll('tr')时,您会获得一个包含所有'tr'元素的单个组的选择集。然后将每个 matrix 元素与每个'tr'元素匹配。
但是,当您在该选择集上调用selectAll('td')时,该选择集已经包含一组'tr'元素。这次每个这些元素都将成为'td'元素的组。组只是一个数组,但它还具有引用旧选择集(在本例中为'tr'元素)的parentNode属性。
现在,当您在这些新的'td'元素的选择集上调用 data(function(d) { return d; }) 时, d 表示绑定到每个组的父节点的数据。因此,在示例中,第一组中的'td'将绑定到数组[11975、5871、8916、2868]。第二组'td'将绑定到[1951、10048、2060、6171]。
您可以在这里阅读迈克·博斯托克(Mike Bostock)本人关于选择集和数据绑定的优秀解释:http://bost.ocks.org/mike/selection/

谢谢!我认为这个答案非常清晰,直截了当;比其他答案更加明确(其他答案也提供了有用的信息,无意冒犯)。 - wires
感谢Kim提供的链接。这对我来说已经足够详细了。此外,这也促使我访问了http://bost.ocks.org/mike/nest/。 - VivekDev
2
尽管Phrogz的评论提供了一些非常有用的信息,但这个答案清晰地解释了所问问题的确切内容。我曾经有过同样的困惑,当我看到return d;返回父节点时,一切都恍然大悟了。混淆在于某些方法在不同的层次结构上起作用。例如,attr适用于单个元素,而data则不同。谢谢! - Mike Williamson

1
使用计数器i来显示正在使用的数据的索引。
var tr = d3.select("body").append("table").selectAll("tr")
.data(matrix)
.enter().append("tr") //create a row for each data entry, first index
.text(function(d, i) { return i}); // show the index i.e. d[0][] then d[1][] etc.

var td = tr.selectAll("td")
.data(function(d) { return d; })
.enter().append("td")
.style("background-color", "yellow") //show each cell
.text(function(d,i) { return i + " " + d; }); // i.e d[from the tr][0] then d[from the tr][1]...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接