我正在使用 d3.js 使用强制布局来布局节点和链接图。节点用圆圈表示;逐行链接。在某些情况下,我想改变线条或节点的视觉特征(例如,颜色、大小、不透明度等)以表示图形上的某些状态变化。我已经能够通过重绘图表来做到这一点,但这会抖动所有节点,导致混乱而不是清晰。
创建图表的代码:
force = d3.layout.force()
.charge(-120)
.gravity(0.2)
.linkDistance(30)
.size([width-pad, height-pad]);
nodeSet = svg.selectAll(".qNode");
// BIND NODE DATA
nodeSet = nodeSet.data(chartData.nodes);
// CREATE NODES
nodeSet.enter().append("circle")
.attr("class", "qNode")
.attr("r", function(d) { return d.size();})
.style('stroke-opacity', function(d) { return d.opacity(); })
.style('stroke', function(d) { return d.color(); })
.style("fill", function(d) { return color(1); });
//similarly for links.
force.nodes(chartData.nodes).links(chartData.links).start();
为了更新图表,我使用了这个片段:
// SELECT NODES
nodeSet = svg.selectAll('.qNode');
// JOIN NODES
nodeSet = nodeSet.data(force.nodes());
// UPDATE NODES
nodeSet.attr("class", "qNode")
.attr("r", function(d) { return d.size();})
.style("fill", function(d) { return color(1); })
.style('stroke', function(d) { return d.color(); })
.style('stroke-opacity', function(d) { return d.opacity(); })
.style('opacity', 1)
.call(force.drag);
// CREATE NODES
nodeSet.enter().append("circle")
.attr("class", "qNode")
.attr("r", function(d) { return d.size();})
.style("fill", function(d) { return color(1); })
.call(force.drag);
// DELETE NODES
nodeSet.exit().remove();
// START SHOW
force.start();
当它运行时,整个图形在应用新的笔画属性之前会稍微晃动。
所以我有两个问题:假设数据对象中的状态变化将返回不同的值d.size()
,d.color()
等等,
- 如何在不抖动任何节点的情况下修改图形的视觉外观?
- 如果我确实想摇动节点,我可以确定要摇动哪组节点吗?(这样我就可以向用户发出信号通知哪个链接器节点的视觉外观发生了变化。)
已编辑
我暂时放弃了抖动节点,但以下代码(基于@defenestrated的建议)似乎可以更新图中某些节点和边的属性:
var allLinks = ... // my links from a d3 selectAll
var allNodes = ... // my nodes from a d3 selectAll
force = ... // my d3 force layout
function updateGraph(graph, nodeSubset, linkSubset) {
for (var i=0; i<allLlinks.length; i++)
allLinks[i].selected = false;
for (var i=0; i<allNodes.length; i++)
allNodes[i].selected = false;
for (var i=0; i<linkSubset.length; i++)
linkSubset[i].selected = true;
for (var i=0; i<nodeSubset.length; i++)
nodeSubset[i].selected = true;
// these functions modify the selected nodes and links
linkSubset.call(setLinkAttributes);
nodeSubset.call(setNodeAttributes);
if (force.alpha() == 0) {
force.start();
force.stop();
}
}
function setLinkAttributes(links) {
link.style(...);
}
function setNodeAttributes(nodes) {
nodes.style(...);
}
在应用属性后,我不需要调用start
/stop
或resume
图表是否仍在移动(如果alpha() > 0
),因为后续的刻度会拾取新属性。如果图形已经稳定,调用 start 会刷新它而不移动节点。