【问题标题】:d3.each() index doesn't begin at 0d3.each() 索引不是从 0 开始
【发布时间】:2017-12-10 13:26:52
【问题描述】:

我的问题与this 非常相似。那里的解决方案是有一个<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() 调用感觉不对。

【问题讨论】:

    标签: javascript d3.js foreach each


    【解决方案1】:

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

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

    让我们展示一下。看看“enter”选择的大小:

    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)
      )
    

    这里我无法提供一个工作堆栈 sn-p,因为如果我们尝试记录 D3 选择,它会崩溃。但结果会是这样:

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

    undefined 是“更新”选择(主体),4 个 EnterNodes 是“输入”选择。这让我们解释了为什么 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)
      )
    &lt;script src="https://d3js.org/d3.v4.js"&gt;&lt;/script&gt;

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


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

    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

    【讨论】:

    • +1 很好很完整!我不知道select(null)。这是否意味着body 不会附加数据?使用select(null) 时有什么注意事项吗?
    • 没有。 select(null)selectAll(null) 是更安全、最重要、更快速的方法,可确保数据方法将数据与空选择进行比较。
    • 信息量很大。感谢您的宝贵时间,并且该解决方案对我有用:)
    【解决方案2】:

    看看this 基本上是这样的: 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)
      )
    

    jsfiddle

    About selectAll

    【讨论】:

    • 这很有趣。我看到它在 jsfiddle 中工作,但在我的情况下它不起作用。不过谢谢你:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-13
    • 2013-12-15
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    相关资源
    最近更新 更多