d3嵌套选择 - 表附加在d3.v2中但不在d3.v3中

时间:2014-06-27 17:41:46

标签: javascript d3.js

问题

我在example in the D3 API reference之后动态追加到现有表。问题是,这个代码在我包含d3.v2.js时有效,但在切换到d3.v3.js时不起作用。

使用d3.v2时,所有内容都会按照我的预期添加。使用d3.v3时,只会附加sessions中的第一个对象,其余部分无处可寻。我创建了两个显示不同行为的小提琴。

小提琴

我将用于将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会改变表格的附加方式?我该怎么做才能解决它?

谢谢!

1 个答案:

答案 0 :(得分:1)

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

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

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

您可以通过在关键功能中将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将恢复为按索引而不是按键绑定数据。执行此操作时,您会注意到现在可以获得包含d3版本的5个元素的预期结果:

d3.v2 JSFiddle

d3.v3 JSFiddle

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

尽管如此,请将它们全部放在一边,因为这不是你想要完成的事情。您希望输出中包含10个元素,从数据集中新创建的原始5和5。要做到这一点,你需要:

<小时/> (1)sessions数据中添加'Andrew','Bob','Irene','Katrina'和'Ivan'的条目,删除代表它们的现有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