d3嵌套选择-表追加在d3.v2中有效,但在d3.v3中无效

d3 Nested Selections - Table Appending Works in d3.v2 but not in d3.v3

本文关键字:d3 有效 但在 无效 v3 选择 嵌套 追加 v2      更新时间:2023-09-26

问题

我将按照D3 API引用中的示例动态地附加到现有表中。问题是,当我包含d3.v2.js时,这段代码可以工作,但当我切换到d3.v3.js时就不工作了。

当使用d3.v2时,所有的东西都会按照我的预期进行追加。当使用d3.v3时,只有sessions中的第一个对象被追加,其余的都找不到了。我创造了两个小提琴来展示不同的行为。

Fiddles

  • JSFiddle:v2行为
  • JSFiddle:v3行为

我用来将sessions中的项目附加到表hurricanes的代码如下所示:

Javascript

var sessions = [
    {name: 'Fred',     year: 2014},
    {name: 'Bill',     year: 1970},
    {name: 'Pookie',   year: 1892},
    {name: 'Hurry',    year: 1941},
    {name: 'Nick',     year: 1953}
];
d3.select('#hurricanes').select('tbody').selectAll('tr')
        .data(sessions, function(d) { return d; })
    .enter().append('tr')
        .selectAll('td')
        .data(function(d) { return d3.values(d); })
    .enter().append('td')
        .text(function(d) { return d; });

HTML

<table id='hurricanes'>
  <tbody>
    <tr>
      <td>Andrew</td>
      <td>1992</td>
    </tr>
    <tr>
      <td>Bob</td>
      <td>1991</td>
    </tr>
    <tr>
      <td>Irene</td>
      <td>2011</td>
    </tr>
    <tr>
      <td>Katrina</td>
      <td>2005</td>
    </tr>
    <tr>
      <td>Ivan</td>
      <td>2004</td>
    </tr>
  </tbody>
</table>

我已经阅读了关于从2.0切换到3.0的指南,但我没有发现任何有用的东西。

问题

为什么使用d3.v3.js会改变表的附加方式?我能做些什么来修复它

谢谢!

有两个问题会导致您得到奇怪的结果。

第一个问题是,页面上的现有元素没有绑定到它们的数据,所以当您进行初始选择时,您选择的是5个现有的tr元素。这意味着我们应该期望.enter()选择为空,并且不会创建任何新元素。

第二期是第一期的结果。由于没有绑定到现有元素的数据,因此当调用键函数时,它会检查与现有元素关联的值,并返回undefined。看起来d3.v2和d3.v3处理这个错误的方式不同,但在这两种情况下,它都是一个错误,并且在d3.v3的情况下,.enter()选择最终包含一个额外元素,在d3.v2的情况下包含5个额外元素。

您可以通过将d的值记录到您的键函数中的控制台来看到这一点

d3.select('#hurricanes').select('tbody').selectAll('tr')
  .data(sessions, function(d) { 
     console.log(d);
     return d; 
  })

你会注意到输出是

undefined
undefined
undefined
undefined
undefined
Object {name: "Fred", year: 2014}
Object {name: "Bill", year: 1970}
Object {name: "Pookie", year: 1892}
Object {name: "Hurry", year: 1941}
Object {name: "Nick", year: 1953}

你说它在d3.v2中起作用,但事实并非如此。你只是得到了一个不同的错误结果。由于数据数组中只有5个对象,因此在连接数据后,输出中应该只有5个tr元素。换句话说,.enter()选择中不应该有任何内容,因为已经有与数据集中的数据点相同数量的tr元素。

如果删除键函数,d3将恢复为按索引而不是按键绑定数据。当你这样做的时候,你会注意到你现在得到了5个元素的预期结果,这两个d3版本都是:

d3.v2 JSFiddle

d3.v3 JSFiddle

现在,数据已绑定到最初存在的元素。但现在有一个问题,因为绑定的数据没有反映在元素本身中。换句话说,写着"Andrew 1992"的行绑定到数据{name: 'Fred' year: 2014},依此类推。要更新到新值,您需要选择现有节点,并使用.text()函数用新绑定的数据更新元素。

尽管如此,还是把这些都放在一边吧,因为这不是你想要实现的。您希望在输出中有10个元素,原始的5个和从数据集中新创建的5个。要做到这一点,您需要:


(1(将"Andrew"、"Bob"、"Irene"、"Katrina"answers"Ivan"的条目添加到sessions数据中,删除表示它们的现有html元素,然后根据数据构建一个完整的表。

方法1 JSFiddle



(2(tbody中创建一个空的选择,并将新元素附加到其中:

d3.select('#hurricanes').select('tbody').selectAll('.new-entry')
  .data(sessions)
  .enter().append('tr')
    .attr('class', 'new-entry')
    .selectAll('td')
      .data(function(d) { return d3.values(d); })
      .enter().append('td')
        .text(function(d) { return d; });

方法2 JSFiddle


我希望这能有所帮助。如果你想了解嵌套选择和关键函数,这里有几个来自Mike Bostock本人的优秀帖子:

嵌套选择

对象常数