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

d3.each() index doesn't begin at 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() 调用感觉不对。

看看this 基本上是这样的: https://whosebug.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 这意味着您仅针对 body 选择。

简而言之:

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

jsfiddle

About selectAll

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是“更新”选项(正文),4个EnterNode是“输入”选项。这让我们解释了为什么 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个元素而后者选择所有元素。但还有更细微的差别。看看这个 table:

Method select() selectAll()
Selection selects the first element that matches the selector string selects all elements that match the selector string
Grouping Does not affect grouping Affects grouping
Data propagation Propagates data Doesn't propagate data