我正在使用D3 v4绘制一些复杂的交互式SVG并遇到一些问题。我的目标是:
<g><circle></circle><circle></circle></g>
)我遇到了麻烦,因为.data()
- &gt; .exit().remove()
- &gt; .enter()
- &gt; .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()
,然后再绘制所有内容。但在这里我遇到了一个不同的问题:要么我删除并重新添加每个更新的所有形状(这使双击很困难,似乎浪费处理能力),或者我必须找出一些方法来更新只有已经改变的形状。是否使用remove和re-add方法如下所示:
// 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){...})
})
是否有更好的方法来按顺序绘制形状,同时保持它们的可更新性?