2017-03-01 30 views
0

我有一個功能完備的強制有向圖。我正在嘗試使用方向箭頭。根據邊緣厚度縮放箭頭,讓它們接觸大小不同的節點的外邊

每個節點的大小成正比,它的入度和出度和環節的厚度根據以下鏈接特性變化:

.attr("stroke-width",function(d) {return d.total_amt/60;}) 

我想有箭鏃以這樣的方式,他們是在與筆畫寬度以及節點大小成比例。

使用多個標記不是選項,因爲筆劃寬度的變化不知道,因爲它取決於d.total_amount這是鏈接屬性之一。

所以我試圖用數學計算X2Y2爲線值:

​​

下面是一個使用lineX2lineY2節點蜱功能

 function ticked() { 
    link 
     .attr("x1", function(d) { 
     return d.source.x; 
     }) 
     .attr("y1", function(d) { 
     return d.source.y; 
     }) 
     .attr("x2", lineX2) 
     .attr("y2", lineY2) 

    node 
     .attr("cx", function(d) { 
     return d.x; 
     }) 
     .attr("cy", function(d) { 
     return d.y; 
     }); 
    } 

以下是標記定義:

svg.append("svg:defs").selectAll("marker") 
    .data(["end"])  // Different link/path types can be defined here 
    .enter().append("svg:marker") // This section adds in the arrows 
    .attr("id", String) 
    .attr("viewBox", "0 0 10 10") 
    .attr("refX", "4") 
    .attr("refY", "3") 
    .attr("markerUnits", "strokeWidth") 
    .attr("markerWidth", "7") 
    .attr("markerHeight", "2") 
    .attr("orient", "auto") 
    .append("svg:path") 
    .attr("d", "M 0 0 L 10 5 L 0 10 z") 

現在,這似乎部分工作的地方,箭頭看起來似乎與邊緣厚度成比例。

但是,當節點大小很小時,箭頭似乎不會觸及節點的外邊緣並終止得更早。

我一樣)嘗試使用d3.scaleLinear(而不是nodeRadiuslineX2lineY2的計算而是使整個圖形非常怪異。

var minRadius = 5 
     var maxRadius = 20 
     var scale = (length - d3.scaleLinear().range([minRadius,maxRadius]))/length 

weird graph

而且,即使箭頭似乎是成正比的邊緣厚度,控制檯還拋出下面的錯誤:

Error: <line> attribute x2: Expected length, "NaN". 
(anonymous) @ d3.v4.min.js:2 
797d3.v4.min.js:2 Error: <line> attribute y2: Expected length, "NaN". 

以下是一個演示的問題fiddle

+0

不是一個確切的重複,但類似的問題[我在這裏回答](http://stackoverflow.com/questions/41226734/align-marker-on-node-edges-d3-force-layout/41229068#41229068 ) – Mark

+0

明天我會檢查一下。但通過一眼就可以看出,您正在使用的.Weight屬性在d3 v4中無效。 –

回答

1

今天早上重新審視這個問題。你的數學與我在評論中鏈接的答案中使用的非常相似。我認爲這個問題有兩個方面:

  1. 你nodeRadius固定爲20時,有時會在目標節點是5小,這會導致你回退太遠
  2. 你不考慮「回退」中標記的大小。

一個小試驗和錯誤導致我:

var lineX2 = function(d) { 

    var mw = d.total_amt/60, // marker width 
    ms = Math.sqrt((mw * mw) + (mw * mw)) * 1.2; // marker size plus "fudge" 

    var weight = d.target.inDegree ? d.target.inDegree : 0 + d.target.outDegree ? d.target.outDegree : 0; 
    weight = weight >= 20 ? 20 : (weight < 5 ? 5 : weight); 
    var r = weight + ms; // final radius 

    var length = Math.sqrt(Math.pow(d.target.y - d.source.y, 2) + Math.pow(d.target.x - d.source.x, 2)); 
    var scale = (length - r)/length; 
    var offset = (d.target.x - d.source.x) - (d.target.x - d.source.x) * scale; 
     return d.target.x - offset; 
}; 

running

+0

太棒了。使用該標記寬度並使其與total_amt相同的技巧是我錯過的。 –