首页 > 解决方案 > 由 var 分隔的嵌套选择失败

问题描述

我认为这更像是一个一般的 JS 问题,而不是特定于 D3 的问题。当我研究如何在 D3 中进行嵌套选择时,我最初有:

var main = d3.select('#main');

main.selectAll('div')
    .data(data)
        .enter().append('div').classed("parent", true)

var child = main.selectAll('.parent')
    .data(function(d) { return d.children }) //=> can not read property 'children' of undefined
        .enter().append('div').classed("child", true)

在阅读了一些选择文档之后,我重构了以下内容:

const main = d3.select('#main').selectAll('div')
    .data(data)
        .enter().append('div').classed("parent", true)

const child = main.selectAll('.parent')
    .data(function(d) { return d.children })
        .enter().append('div').classed("child", true)

我工作并且正在产生预期的效果。我的问题是为什么第二次调用 datamain时会丢失对数据的引用?

编辑:我对以下内容进行了一些额外的测试:

const main = d3.select('#galaxy');
main.selectAll('div').data(data);
console.log(main); //=> ut {_groups: Array(1), _parents: Array(1)}

const main2 = d3.select('#galaxy').selectAll('div').data(data);
console.log(main2); //=> ut {_groups: Array(1), _parents: Array(1), _enter: Array(1), _exit: Array(1)}

所以似乎第一种方法没有得到_enter_exit方法。

标签: javascriptd3.js

解决方案


data方法接受三件事:

  1. 数组;
  2. 一个函数;
  3. 没有。

根据 API,当您使用函数时(在您的第一种方法中就是这种情况),此函数...

...将按顺序对每个组进行评估,传递组的父数据(d,可能未定义)、组索引(i)和选择的父节点(节点),并将 this 作为组的父元素. (强调我的)

因此,此功能取决于父级的数据。这可以在源代码中看到:

data = value.call(parent, parent && parent.__data__, j, parents)

这是对您问题的解释:在您的第一种方法中,您的选择没有父母的数据。您没有多个组,这些组通常是使用 a 创建的,selectAll后跟另一个selectAll. 您在第一种方法中所拥有的只是 aselect后跟 a selectAll

让我们在一个简单的演示中展示这一点:

var data = [{
    name: "foo",
    value: 10
  },
  {
    name: "bar",
    value: 17
  },
  {
    name: "baz",
    value: 42
  }
];

var main = d3.select("body");

var parent = main.selectAll(null)
  .data(data)
  .enter()
  .append('div')
  .classed("parent", true)

main.selectAll('.parent')
  .data(function(d) {
    console.log("parent's datum is: " + JSON.stringify(d))
    return 0;
  });
<script src="https://d3js.org/d3.v5.min.js"></script>

另一方面,如果您有 aselectAll 后跟 another selectAll,则您有多个组:

var data = [{
    name: "foo",
    value: 10
  },
  {
    name: "bar",
    value: 17
  },
  {
    name: "baz",
    value: 42
  }
];

var main = d3.select("body");

var parent = main.selectAll(null)
  .data(data)
  .enter()
  .append('div')

parent.selectAll(null)
  .data(function(d) {
    console.log("parent's datum is: " + JSON.stringify(d))
    return d
  });
<script src="https://d3js.org/d3.v5.min.js"></script>

为了完整起见,这是我制作的一个表格,其中包含 和 之间的差异selectselectAll注意“分组”:

表:select和 之间的差异selectAll

方法 选择() 全选()
选择 选择与选择器字符串匹配的第一个元素 选择与选择器字符串匹配的所有元素
分组 不影响分组 影响分组
数据传播 传播数据 不传播数据

推荐阅读