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

标签 javascript d3.js

问题

我正在按照 example in the D3 API reference 动态追加到现有表中。问题是,当我包含 d3.v2.js 时,此代码有效,但当我切换到 d3.v3.js 时,此代码无效。

使用 d3.v2 时,所有内容都会按照我的预期进行附加。使用 d3.v3 时,只有 sessions 中的第一个对象被附加,其余的都找不到。我创建了两个显示不同行为的 fiddle 。

fiddle

我用来将 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>

我已阅读 guidelines regarding switching from 2.0 to 3.0但我还没有发现任何有用的东西。

问题

为什么使用 d3.v3.js 会改变表的附加方式?我该如何解决这个问题?

谢谢!

最佳答案

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

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

第二个问题是第一个问题的结果。由于没有数据绑定(bind)到现有元素,因此当调用关键函数时,它会检查与现有元素关联的值,并返回 undefined。 d3.v2 和 d3.v3 似乎以不同的方式处理此错误,但在这两种情况下,这都是一个错误,并且在 d3 的情况下, .enter() 选择最终包含一个额外的元素。 v3,在 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 元素的数量已经与数据集中的数据点数量相同。

如果删除 key 函数,d3 将恢复为按索引绑定(bind)数据,而不是按键绑定(bind)数据。当您执行此操作时,您会注意到您现在获得了两个 d3 版本的 5 个元素的预期结果:

d3.v2 JSFiddle

d3.v3 JSFiddle

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

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

<小时/> (1) 将“Andrew”、“Bob”、“Irene”、“Katrina”和“Ivan”条目添加到 sessions 数据中,删除现有的 html 元素表示它们,然后根据数据构建完整的表格。

Method 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; });

Method 2 JSFiddle

<小时/>

我希望这会有所帮助。如果您想了解嵌套选择和关键函数,请阅读以下来自 Mike Bostock 本人的几篇精彩文章:

Nested Selections

Object Constancy

关于javascript - d3 嵌套选择 - 表追加在 d3.v2 中有效,但在 d3.v3 中无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24457824/

相关文章:

javascript - d3.js 引用单个数组列

javascript - 浮线干扰鼠标移动功能

Javascript,数组在传递给函数时不再是数组

javascript - 以整数开头的 ID 出现错误的无法识别的表达式

javascript - 使用 setTimeout 延迟 d3 转换

javascript - 使用 javascript knockout 绑定(bind) View

javascript - 如何将数组添加到 #appcelerator 中的事件

javascript - D3 v4 在传入 Date 对象时返回 scaleTime 错误

javascript - For循环创建同心圆环图

javascript - D3.js 条形图动画未正确退出