最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Drawing multiple links between fixed nodes - Stack Overflow

programmeradmin2浏览0评论

I have a force directed graph with links between each nodes. Now some node pairs have multiple links going to each other. I have found this example : Drawing multiple edges between two nodes with d3.

This worked great, I thought. But if you have fixed nodes and drag, the paths end up overlapping each other. I have put together an edited version of this example : /

Click the button to fix the nodes and move them around to see what I mean.

Code for working out amount of arc :

//sort links by source, then target
links.sort(function(a,b) {
    if (a.source > b.source) {return 1;}
    else if (a.source < b.source) {return -1;}
    else {
        if (a.target > b.target) {return 1;}
        if (a.target < b.target) {return -1;}
        else {return 0;}
    }
});
//any links with duplicate source and target get an incremented 'linknum'
for (var i=0; i<links.length; i++) {
    if (i != 0 &&
        links[i].source == links[i-1].source &&
        links[i].target == links[i-1].target) {
            links[i].linknum = links[i-1].linknum + 1;
        }
    else {links[i].linknum = 1;};
};

Can anyone think of another way of doing this or fixing this way maybe ? I could have 3 maybe even 4 links between two nodes.

I have a force directed graph with links between each nodes. Now some node pairs have multiple links going to each other. I have found this example : Drawing multiple edges between two nodes with d3.

This worked great, I thought. But if you have fixed nodes and drag, the paths end up overlapping each other. I have put together an edited version of this example : http://jsfiddle/thatOneGuy/7HZcR/502/

Click the button to fix the nodes and move them around to see what I mean.

Code for working out amount of arc :

//sort links by source, then target
links.sort(function(a,b) {
    if (a.source > b.source) {return 1;}
    else if (a.source < b.source) {return -1;}
    else {
        if (a.target > b.target) {return 1;}
        if (a.target < b.target) {return -1;}
        else {return 0;}
    }
});
//any links with duplicate source and target get an incremented 'linknum'
for (var i=0; i<links.length; i++) {
    if (i != 0 &&
        links[i].source == links[i-1].source &&
        links[i].target == links[i-1].target) {
            links[i].linknum = links[i-1].linknum + 1;
        }
    else {links[i].linknum = 1;};
};

Can anyone think of another way of doing this or fixing this way maybe ? I could have 3 maybe even 4 links between two nodes.

Share Improve this question edited May 23, 2017 at 11:58 CommunityBot 11 silver badge asked May 24, 2016 at 15:09 thatOneGuythatOneGuy 10.7k9 gold badges58 silver badges92 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 6

The important code is the one giving the radius of the arc. I propose the following function:

path.attr("d", function(d) {
 var curve=2;
 var homogeneous=3.2;
 var dx = d.target.x - d.source.x,
     dy = d.target.y - d.source.y,
     dr = Math.sqrt(dx*dx+dy*dy)*(d.linknum+homogeneous)/(curve*homogeneous);  //linknum is defined above
 return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
});

The main difference is that it scales linearly with the node distance (which I think is best). Then, there are these two parameters which I call curve and homogeneous: you should play with them until you find suitable values.

See http://jsfiddle/7HZcR/504/

PS: the overlap happens when the radius given for the arc is smaller than half the distance between the nodes (then the radius is increased to reach this value, and all arcs get the same radius).

Based on the solutions above I have a refined solution that has links evenly spread out, using the sweep parameter of the ellipse: http://jsfiddle/bigman73/v03x572h/

function tick() { 
   path.attr("d", function(d) { 
   let dx = d.target.x - d.source.x,
       dy = d.target.y - d.source.y,
       t = Math.sqrt(dx * dx + dy * dy),
       half_n = Math.floor(links.length / 2) + links.length % 2,
       dr =  d.linknum == half_n ? t * 100 : 2.25 * t * (half_n - 
       Math.abs(d.linknum - half_n)) / links.length,
       sweep = d.linknum <= half_n ? 1 : 0;
       return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0," + sweep + " " + d.target.x + "," + d.target.y;

});

The curve shape is currently hard coded to 2.25, but that's easy to refactor. It should also work generically with different number of links (though I only tested on 3)

发布评论

评论列表(0)

  1. 暂无评论