d3强制:计算节点之间链接为弧的链接上文本的位置

时间:2016-11-02 13:55:19

标签: javascript d3.js

将链接应用于文本的一种方法是对文本元素使用force.links()数组,并将文本置于链接中点的中心。

我有一些带有双向链接的节点,我将它们渲染为在其中点弯曲的路径,以确保它们清楚地知道两个节点之间有两条链路。

对于这些双向链接,我想移动文本,使其正确位于弯曲路径上。

为此,我尝试计算以链接中心点为中心的圆的交点和垂直于链路的直线,该线也穿过其中心。我认为原则上这是有道理的,它似乎只有一半工作,但我不确定如何通过计算应用于哪个标签的交叉点来定义返回哪个坐标,以及如何阻止它们在弯曲链接之间跳转当我移动节点时(参见jsfiddle - https://jsfiddle.net/sL3au5fz/6/)。

计算电弧路径上文本坐标的功能如下:

function calcLinkTextCoords(d,coord, calling) {
    var x_coord, y_coord;        
    //find centre point of coords
    var cp = [(d.target.x + d.source.x)/2, (d.target.y + d.source.y)/2];       
    // find perpendicular gradient of line running through coords
    var pg = -1 / ((d.target.y - d.source.y)/(d.target.x - d.source.x));
    // define radius of circle (distance from centre point text will appear)
    var radius = Math.sqrt(Math.pow(d.target.x - d.source.x,2) + Math.pow(d.target.y - d.source.y,2)) / 5 ;       
    // find x coord where circle with radius 20 centred on d midpoint meets perpendicular line to d.
    if (d.target.y < d.source.y) {
        x_coord = cp[0] + (radius / Math.sqrt(1 + Math.pow(pg,2)));
    } else {
        x_coord = cp[0] - (radius / Math.sqrt(1 + Math.pow(pg,2)));
    };
    // find y coord where x coord is x_text and y coord falls on perpendicular line to d running through midpoint of d
    var y_coord = pg * (x_coord - cp[0]) + cp[1];
    return (coord == "x" ? x_coord : y_coord);
};

任何帮助以解决上述问题或提出另一种方法来实现这一点都将受到赞赏。

顺便说一下,我已经尝试使用textPath将我的文字与我的链接对齐,但是当显示30-40个节点和链接时,我发现该方法不具备高效性。

更新:修改了上述功能,现在按预期工作。更新了小提琴:https://jsfiddle.net/o82c2s4x/6/

1 个答案:

答案 0 :(得分:2)

您可以计算和弦到x和y轴的投影并将其添加到源节点坐标:

function calcLinkTextCoords(d,coord) {

        //find chord length
        var  dx = (d.target.x - d.source.x);
        var dy = (d.target.y - d.source.y);
        var chord = Math.sqrt(dx*dx + dy*dy);

        //Saggita
        // since radius is equal to chord
        var sag = chord - Math.sqrt(chord*chord - Math.pow(chord/2,2));

         //Find the angles
        var t1 = Math.atan2(sag, chord/2);
        var t2 = Math.atan2(dy,dx);
        var teta = t1+t2;

        var h = Math.sqrt(sag*sag + Math.pow(chord/2,2));

        return ({x: d.source.x + h*Math.cos(teta),y: d.source.y + h*Math.sin(teta)});

    };

以下是更新后的JsFiddle