D3.js:enter(),update,exit(),中间有组元素

d3.js: enter(), update, exit() with group element in between

本文关键字:中间 元素 exit D3 enter js update      更新时间:2023-09-26

当我使用 D3 渲染可视化并进入、更新、退出模式时,我的 DOM 结构如下所示.js:

g
  rect
  ...
g
  rect
  ...
g
  rect
  ...

我正在我的组中使用多个元素和嵌套选择,但为简单起见,我将用矩形演示这一点。DOM 通过以下方式完成:

group = d3.select('.svg-content')
    .selectAll('g')
    .data(items, function (item) { return item.Id; });
groupEnter = group.enter()
    .append('svg:g')
    .attr('class','group-content');
// enter
groupEnter.append('svg:rect')
    .style('fill', '#000')
    .attr('x', function (item) { return item.x })
    .attr('y', function (item) { return item.y; })
    .attr('width', function (item) { return item.width; })
    .attr('height', function (item) { return item.height; });
// update
group.select('rect') 
    .attr('x', function (item) { return item.x })
    .attr('width', function (item) { return item.width; });
// remove
group.exit().remove();

这行得通!

现在我想实现以下目标:

g
  g
    rect
  ...
g
  g
    rect
  ...
g
  g
    rect
  ...

我想将矩形封装在另一个组元素中。

group = d3.select('.svg-content')
    .selectAll('g')
    .data(items, function (item) { return item.Id; });
groupEnter = group.enter()
    .append('svg:g')
    .attr('class','group-content');
// enter
groupEnter
    .append('svg:g') // NEW
    .attr('class','rect-content') // NEW
    .append('svg:rect')
    .style('fill', '#000')
    .attr('x', function (item) { return item.x })
    .attr('y', function (item) { return item.y; })
    .attr('width', function (item) { return item.width; })
    .attr('height', function (item) { return item.height; });
// update
group
    .select('.rect-content') // NEW
    .select('rect') 
    .attr('x', function (item) { return item.x })
    .attr('width', function (item) { return item.width; });
// remove
group.exit().remove(); // NOTE: without this, it works!

这段代码有什么问题?如果没有删除块,它可以工作,但我需要它来处理新的/删除的项目。如何使它正确?

问题是您正在选择要将数据绑定到的普通g元素(.selectAll('g').data(...))。当这些元素只有一个级别时,这工作正常,但是由于.selectAll()递归工作,它将选择比您拥有嵌套结构时想象的更多的元素。

也就是说,所选内容包含更多元素,这些元素"使用"绑定数据。因此,数据最终不会与正确的元素匹配。

要解决此问题,只需使选择器更具体:

group = d3.select('.svg-content')
    .selectAll('g.group-content')
    .data(...);

在此处完成演示。