2017-03-01 102 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相同的技巧是我错过的。 –