这是一个老问题,但这是我的解决方案。这个想法是绘制连接节点的路径,使得端点位于节点的边缘而不是节点的中心。从移动专利诉讼的例子开始(http://bl.ocks.org/mbostock/1153292),我将 linkArc 方法替换为:
function drawCurve(d) {
var sourceX = d.source.x;
var sourceY = d.source.y;
var targetX = d.target.x;
var targetY = d.target.y;
var theta = Math.atan((targetX - sourceX) / (targetY - sourceY));
var phi = Math.atan((targetY - sourceY) / (targetX - sourceX));
var sinTheta = d.source.r * Math.sin(theta);
var cosTheta = d.source.r * Math.cos(theta);
var sinPhi = d.target.r * Math.sin(phi);
var cosPhi = d.target.r * Math.cos(phi);
// Set the position of the link's end point at the source node
// such that it is on the edge closest to the target node
if (d.target.y > d.source.y) {
sourceX = sourceX + sinTheta;
sourceY = sourceY + cosTheta;
}
else {
sourceX = sourceX - sinTheta;
sourceY = sourceY - cosTheta;
}
// Set the position of the link's end point at the target node
// such that it is on the edge closest to the source node
if (d.source.x > d.target.x) {
targetX = targetX + cosPhi;
targetY = targetY + sinPhi;
}
else {
targetX = targetX - cosPhi;
targetY = targetY - sinPhi;
}
// Draw an arc between the two calculated points
var dx = targetX - sourceX,
dy = targetY - sourceY,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + sourceX + "," + sourceY + "A" + dr + "," + dr + " 0 0,1 " + targetX + "," + targetY;
}
请注意,此代码期望节点数据中包含“r”或半径属性。这相当于 jsfiddle 中的 size 属性。如果您想将链接绘制为直线,则可以返回此字符串:
return "M" + sourceX + "," + sourceY + "L" + targetX + "," + targetY;
为了将箭头点放置在正确的位置,我更改了 refX 和 refY 属性,使箭头点位于节点的边缘:
svg.append("defs").selectAll("marker")
.data(["suit", "licensing", "resolved"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewBox", "0 -5 10 10")
.attr("refX", 10)
.attr("refY", 0)
.attr("markerWidth", 6)
.attr("markerHeight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");