2013-02-16 109 views
2

我使用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()等,

  1. 如何修改圖表的視覺外觀沒有任何輕搖節點?
  2. 如果我確實想要晃動節點,我可以確定哪一組節點要晃動嗎? (所以,我可以通知其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/stopresume如果應用屬性後圖形仍然在移動(如果alpha() > 0),因爲隨後的刻度將拾取新的屬性。如果圖形已經確定,調用開始將刷新它而不移動節點。

回答

1
  1. 有你打過電話force.stop()「更新節點」塊之前,和force.resume()後?

  2. 你可以根據它們的狀態對它們進行分類 - 所以你可以將.attr("id", "changed")應用到正在更新的節點上,然後在d3選擇中使用它,例如。改變節點= d3.select("#changed")

+0

如何知道要修改哪些節點(我可能使用'class'屬性而不是'id')來使後續的.select()調用起作用?我假設我有一些數據綁定到一些SVG元素;數據發生變化......我如何知道要修改哪些元素? – 2013-02-18 23:09:06

+0

我只是說'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

+0

感謝您回答問題#1:調用'force.start(); force.stop();'正確更新了外觀。至於調整已經改變的節點,那是行不通的:當我將節點和邊的集合限制到選定的集合時,它們被移動到圖表的中間,忽略了其他節點。我想我可能會修復整個節點集,然後加熱那些我想突出顯示的節點,但這看起來過於複雜。我想我需要一個更好的解決方案。 – 2013-02-19 07:06:14