我使用d3.js來使用強制佈局佈置節點和鏈接圖。節點由圓圈表示;按行連結。在某些情況下,我想改變線或節點的視覺特徵(例如,顏色,大小,不透明度等)以表示圖上的一些狀態改變。我已經能夠通過重新繪製圖表來做到這一點,但是這會抖動所有節點,導致混淆而不是清晰。修改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()
等,
- 如何修改圖表的視覺外觀沒有任何輕搖節點?
- 如果我確實想要晃動節點,我可以確定哪一組節點要晃動嗎? (所以,我可以通知其linkor節點有自己的視覺外觀變化的用戶。)
EDITED
我已經放棄了對輕搖節點爲是的時間,但下面的代碼(基於由@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
),因爲隨後的刻度將拾取新的屬性。如果圖形已經確定,調用開始將刷新它而不移動節點。
如何知道要修改哪些節點(我可能使用'class'屬性而不是'id')來使後續的.select()調用起作用?我假設我有一些數據綁定到一些SVG元素;數據發生變化......我如何知道要修改哪些元素? – 2013-02-18 23:09:06
我只是說'id',因爲你已經有了一個'qNode'類,我不想搞砸......如果你在數據改變的時候對數據設置了一些任意的屬性會怎麼樣 - 所以無論你在哪裏改變或更新數據,添加如下內容:'nodes.forEach(function(d,i){d.changed = true});' - 那麼我想你可以稍後通過定期調用'.select'來進行選擇使用選擇器函數:'nodes.select(function(d,i){return d.changed == true?this:null}' - 參見[this](https:// github。com/mbostock/d3/wiki/Selections#wiki-filter)獲取更多關於過濾的信息 – defenestrated 2013-02-19 01:42:09
感謝您回答問題#1:調用'force.start(); force.stop();'正確更新了外觀。至於調整已經改變的節點,那是行不通的:當我將節點和邊的集合限制到選定的集合時,它們被移動到圖表的中間,忽略了其他節點。我想我可能會修復整個節點集,然後加熱那些我想突出顯示的節點,但這看起來過於複雜。我想我需要一個更好的解決方案。 – 2013-02-19 07:06:14