D3:将数据退出/删除/合并与元素绘制分开



我正在使用D3 v4绘制一些复杂的交互式SVG,并遇到了一些问题。我的目标是:

  • 每个数据元素对应于具有多个 SVG 形状元素的组(例如<g><circle></circle><circle></circle></g>(
  • 多个 SVG 形状元素必须按特定顺序绘制(因为它们重叠(
  • 某些形状元素
  • 在不添加或删除数据元素的情况下更新(例如,单击形状时,更改形状颜色(

我遇到了麻烦,因为.data()->.exit().remove()->.enter()->.merge()过程需要特定的顺序,并且该顺序与必要的绘制顺序以及动态更新样式的能力冲突。这是我开始的,由于绘制顺序而不起作用:

function updateGraph() {
let eachNodeG = allNodesG
.selectAll('.eachNodeG')
.data(graphData._nodes, function (d) {
return d._id;
})
eachNodeG.exit().remove();
let eachNodeGEnter = eachNodeG.enter()
.append('g')
.attr("class", "eachNodeG")
eachNodeGEnter
.append('circle')
.classed('interactivecircle', true)
.on('click', function (d) {...})
let eachNodeG = eachNodeGEnter
.merge(eachNodeG)
.style('fill', function (d) {...}) //this is here b/c it needs to change
// when data change (without them being added/removed)
// this must be separate because the background circle needs to change even
// when nodes are not added and removed; but this doesn't work here because
// the circle needs to be in the background
eachNodeG
.append('circle')
.classed('bgcircle', true)
}

我想也许我可以将数据更新过程与数据绘制过程完全分开,只需在包含数据的组上执行enter() exit() merge(),然后绘制所有内容。但是在这里我遇到了一个不同的问题:要么我在每次更新时删除并重新添加所有形状(这使得双击变得困难并且似乎浪费了处理能力(,要么我必须找到一些方法来仅更新已更改的形状。使用删除和重新添加方法是否如下所示:

// add/remove individual groups based on updated data
let eachNodeG = allNodesG
.selectAll('.eachNodeG')
.data(graphData._nodes)
eachNodeG.exit().remove();
let eachNodeGEnter = eachNodeG.enter()
.append('g')
.attr("class", "eachNodeG")
eachNodeG = eachNodeGEnter
.merge(eachNodeG)
// draw (or remove and re-draw) elements within individual groups
d3.selectAll('.bgcircle').remove()
eachNodeG.append('circle')
.classed('bgcircle', true)
d3.selectAll('.interactivecircle').remove()
eachNodeG.append('circle')
.classed('interactivecircle', true)
.style('fill', function (d) {...})
.on('click',function(d){...})
})

有没有更好的方法来按顺序绘制形状,同时保持它们可更新?

您可以使用 selection.raise 或 selection.lower 在创建圆圈后移动圆圈。

最新更新