2015-10-06 84 views
1

我的問題是如何創建一個網絡可視化方案,使邊緣和/或箭頭終止在節點的邊界。鏈接和箭頭終止在D3節點的邊界

我正在使用D3.js根據Curved Links基本模型繪製有向圖,並添加了「標記」箭頭,如other question中所述。我的可視化中的節點根據其屬性改變其大小和不透明度。這引入了兩個問題:(1)當節點改變尺寸時,箭頭沒有指向節點的邊緣;(2)當邊緣部分透明時,邊緣的尾部通過節點出現。

對於第一個問題,有幾個解決方案可用:this one聲稱可以正確地獲得箭頭偏移量,但它不會影響鏈接結束端點。也有解決方案here的建議,但我沒有看到任何實際的完整工作代碼。 This JS fiddle具有我想要的箭頭形狀,但代碼是相當不透明的,而不是模塊化的,我可以找出如何應用於我自己的情況。

正如我所說,我的鏈接是基於彎曲鏈接例子定義:

graph.links.forEach(function(link) { 
    var s = nodes[link.source], 
     t = nodes[link.target], 
     i = {}, // intermediate node 
    property1 = link.property1; 
    nodes.push(i); 
    links.push({source: s, target: i}, {source: i, target: t}); 
    bilinks.push([s, i, t, property1]); 
}); 

然後,如果我的D3是如何工作的鬆散的理解是基本正確的,鏈接被吸引通過下面的代碼每個刻度:

force.on("tick", function() { 
    link.attr("d", function(d) { 
    if (d[0] == d[2]) { 
     return "M" + d[0].x + "," + d[0].y 
     + "A" + "20,20 -50 1,1 " + (1.001 * d[2].x) + "," + (1.001 * d[2].y) 
     ; 
    } else { 
    return "M" + d[0].x + "," + d[0].y 
     + "S" + d[1].x + "," + d[1].y 
     + " " + d[2].x + "," + d[2].y; 
    } 
    }); 
    node.attr("transform", function(d) { 
    return "translate(" + d.x + "," + d.y + ")"; 
    }); 
}); 

所以我的問題是,如何在達到通常期望的方式更改此代碼(我認爲正常)可視化方案使得邊緣和/或箭頭終止在節點的邊界甚至他們改變大小。

我創建了一個JS Fiddle,其中包含查看和解決問題所需的所有位。它還包括調整箭頭以匹配它們所在的鏈接,並且該功能需要與此問題的解決方案兼容。

+0

我想,基本上,你需要計算節點和鏈接的外周之間的交點...動態。這對於直線是可以的,但對於花鍵路徑,您需要計算控制點以獲得正確的接近角度。聽起來不像我有趣。 –

+0

形狀總是圓形的嗎? – Ian

+0

對於我而言,節點並不總是圓形的,但是如果我可以爲圓形做它,那麼我可以使用三角形和正方形或任何其他形狀的邊界圓。所以它不需要完全在邊界上:稍微遠離邊界稍好一點。本質上,我只是想通過每一端節點的「大小」參數(而不是圓的「r」)來抵消鏈接的末端......並將箭頭末端與鏈接的提示幾乎齊平。 –

回答

1

由於我沒有得到任何答覆,我繼續努力,通過回答我自己的問題。因此,我提出的答案可能不是最好的,因爲我對這一切仍然陌生,但它的工作原理與this answer類似......非常適合處理彎曲鏈接和反射鏈接。

必要的變化的核心是以下代碼:

force.on("tick", function() { 
    link.attr("d", function(d) { 
    diffX0 = d[0].x - d[1].x; 
    diffY0 = d[0].y - d[1].y; 
    diffX2 = d[2].x - d[1].x; 
    diffY2 = d[2].y - d[1].y; 
    pathLength01 = Math.sqrt((diffX0 * diffX0) + (diffY0 * diffY0)); 
    pathLength12 = Math.sqrt((diffX2 * diffX2) + (diffY2 * diffY2)); 
    offsetX0 = 1.00 * (diffX0 * d[0].group)/pathLength01; 
    offsetY0 = 1.00 * (diffY0 * d[0].group)/pathLength01; 
    offsetX2 = (4.0 * (diffX2/Math.abs(diffX2))) + ((diffX2 * d[2].group)/pathLength12); 
    offsetY2 = (4.0 * (diffY2/Math.abs(diffY2))) + ((diffY2 * d[2].group)/pathLength12); 

    if (d[0] == d[2]) { 
    return "M" + (d[0].x) + "," + (d[0].y - d[0].group) 
     + "A" + "20,23 -50 1,1 " 
     + " " + (d[2].x + (5.0 * 0.866) + (0.866 * d[2].group)) 
     + "," + (d[2].y + (5.0 * 0.5) + (0.5 * d[2].group)); 
    } else { 
    return "M" + (d[0].x - offsetX0) + "," + (d[0].y - offsetY0) 
     + "S" + (1.01 * d[1].x) + "," + (1.01 * d[1].y) 
     + " " + (d[2].x - offsetX2) + "," + (d[2].y - offsetY2); 
    } 
    }); 
    node.attr("transform", function(d) { 
    return "translate(" + d.x + "," + d.y + ")"; 
    }); 
}); 

這是設計成與箭頭標記偏移至6(即.attr("refX", 6))工作,使得連桿的端部是幾乎在中間的箭頭和箭頭向節點延伸約4個單位。因此箭頭和鏈接尾部與節點邊界的偏移量不同,所以如果您未使用有向圖,則需要調整目標端的偏移量以匹配源端,並將它們都放在邊界上。

下面是一個updated JSFiddle包括所有必要做一個指向的力佈局,其包括特徵:由JSON節點屬性

  • 顏色圓圈與透明度由JSON鏈路屬性
  • 彩色彎曲的邊緣和箭頭
  • 鏈接在節點邊界開始和結束,因此它們不與開始/結束節點重疊
  • 反射邊的匹配樣式(即源和目標是相同的節點)
  • 改變邊緣厚度和透明度,也支持

還有一些其他的事情,你要調整你自己的應用程序。例如,我添加了一個radius變量包括所述屬性(目前group)到圓半徑的適當的比例,那麼對於它的.attr("r", function(d) { return d.radius;}圓我的節點數據。我找不到一種方法讓節點的圈子的r在force函數中使用(我喜歡,如果有人能弄明白,我會喜歡的),所以這是我的解決方法。

我認爲包裝了大量的可視化功能,我預計標準D3一樣的工具,而是都不可能找到,有點難以實施。但是現在已經完成了,我希望這會爲其他人節省大量的時間來實現D3中的定向網絡。

+0

您的JSFiddle運行到一個跨源腳本塊中。我的叉子:http://jsfiddle.net/spamguy/tz5oxfnL/ – spamguy