d3.each() 索引不是从 0 开始的



我的问题与此非常相似。解决方案是有一个<div>把事情搞砸了。我的<divs>没有。

我有这个CoffeeScript代码:

data = [0, 1, 2, 3, 4]
d3.select("body")
.data(data)
.enter()
.each((d, i) =>
console.log(i, d)
)

所需的控制台输出为:

0 0
1 1
2 2
3 3
4 4

实际控制台输出为:

1 1
2 2
3 3
4 4

我可以用以下代码获得所需的输出:

data = [0, 1, 2, 3, 4]
d3.select("body")
.data(data)
.each((d, i) =>
console.log(i, d)
).enter()
.each((d, i) =>
console.log(i, d)
)

但是有两个 .each() 调用感觉不对。

>d3.each()确实从索引0开始。在代码中看到的是预期的行为,给定代码中的内容。

这里的问题很简单:当然,页面中有一个<body>元素。您的数据数组有 5 个元素,其中一个元素绑定到<body>

让我们展示一下。看看"输入"选择的大小:

data = [0, 1, 2, 3, 4]
var foo = d3.select("body")
.data(data)
.enter();
console.log("Size of enter selection: " + foo.size())
<script src="https://d3js.org/d3.v4.js"></script>

我们还可以证明数组中的第一个元素绑定到<body>

data = [0, 1, 2, 3, 4]
var foo = d3.select("body")
.data(data)
.enter();
console.log("Data of body: " + d3.select("body").data())
<script src="https://d3js.org/d3.v4.js"></script>

显示这一点的另一种方法是使用第三个参数(技术上讲,参数),即当前组:

data = [0, 1, 2, 3, 4]
d3.select("body")
.data(data)
.enter()
.each((d, i, p) =>
//           ^---- this is the third argument
console.log(p)
)

在这里我无法提供有效的 Stack 代码段,因为如果我们尝试记录 D3 选择,它会崩溃。但结果将是这样的:

[undefined × 1, EnterNode, EnterNode, EnterNode, EnterNode]

undefined是"更新"选择(正文),4EnterNode是"输入"选择。这就让我们解释了为什么each()在你的代码中以这种方式行事。

如果你看一下源代码...

function(callback) {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
if (node = group[i]) callback.call(node, node.__data__, i, group);
}
}
return this;
}

您将看到它将节点与组进行比较,并且您的组包含"更新"选择和"输入"选择。更新选择对应于索引0,输入选择对应于索引1234

>解决方案

这是你想要的,注意selectAllnull

data = [0, 1, 2, 3, 4]
d3.select("body")
.selectAll(null)
.data(data)
.enter()
.each((d, i) =>
console.log(i, d)
)
<script src="https://d3js.org/d3.v4.js"></script>

因此,如您所见,选择null向我们保证我们的"输入"选择始终包含数据数组中的所有元素。


奖励selectselectAll的行为不同。大多数人认为唯一的区别是前者只选择1个元素,而后者选择所有元素。但还有更微妙的差异。看看这个表:

selectAll()style="文本对齐:居中;">选择与选择器字符串匹配的第一个元素
Methodselect()
选择选择与选择器字符串匹配的所有元素
分组不影响分组影响分组
数据传播传播数据不传播数据

看看这个 基本上是这样的: https://stackoverflow.com/a/19726610/3433323

引用:You need to select the non-existent elements as well for the selections to work properly. ... At the moment, the selection you're matching data against contains only the one element这意味着您仅针对身体进行选择。

总之:

data = [0, 1, 2, 3, 4]
d3.selectAll("body")
.selectAll('div') // add this
.data(data)
.enter()
.each((d, i) =>
console.log(i, d)
)

斯菲德尔

关于全选

最新更新