2015-10-06 111 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