0

I've a Webcola&D3 svg graph with Nodes and Links between them. Till today, between nodes the Links could be One way, if B was connected to A, it was only one way Link. enter image description here

Today i was told i need to support having 2 way Links, meaning A can send a Link to B and B can send a link to A.

Now i'm stuck about the math and how to accomplish it, i used some algorithm i found to draw links till today which i guess draw the Links from the center of the Node, i need to show the 2 way links in parallel like this : enter image description here

here is the algorithm i use to calculate Links position:

let parent = connection.parent;

        const sx = parent.source.x;
        const sy = parent.source.y;
        const tx = parent.target.x;
        const ty = parent.target.y;

        let angle = Math.atan2(ty - sy, tx - sx);
        const radiusSource = parent.source.radius;
        const radiusTarget = parent.target.radius;

        let x1 = sx + Math.cos(angle) * radiusSource;
        let x2 = tx - Math.cos(angle) * radiusTarget;
        let y1 = sy + Math.sin(angle) * radiusSource;
        let y2 = ty - Math.sin(angle) * radiusTarget;

        angle = angle * 180 / Math.PI;
        let opposite = Math.abs(angle) > 90;

        if (opposite)
            angle -= 180;

        connection.coords = [x1, y1, x2, y2, angle, opposite];
        return connection.coords;

This is a part of a function which the result goes into the 'd' attr of the path like this:

.attr('d', `M${x1} ${y1} L ${x2} ${y2}`)

The result of 2 way Links right now is that they override each other, can anyone help me improve this algorithm so it will make 2 way Links be parallel?

Sahar Sabin
  • 227
  • 2
  • 10

1 Answers1

1

Update: position of the Links need to be calculated by new radian considering offset, like:

let parent = connection.parent;

const sx = parent.source.x;
const sy = parent.source.y;
const tx = parent.target.x;
const ty = parent.target.y;
const radiusSource = parent.source.radius;
const radiusTarget = parent.target.radius;

let radian = Math.atan2(ty - sy, tx - sx);
let offset = 0.1 // Offset ratio of radian, can be adjusted
let offsetRadian;

let angle = radian * 180 / Math.PI;
let opposite = Math.abs(angle) > 90;
if (opposite) {
    angle -= 180;
    offsetRadian = radian * (1 + offset);
} else {
    offsetRadian = radian * (1 - offset);
}

let x1 = sx + Math.cos(offsetRadian) * radiusSource;
let y1 = sy + Math.sin(offsetRadian) * radiusSource;

let x2 = tx - Math.sin(offsetRadian) * radiusTarget;
let y2 = ty - Math.cos(offsetRadian) * radiusTarget;

connection.coords = [x1, y1, x2, y2, angle, opposite];
return connection.coords;
leaf
  • 1,624
  • 11
  • 16
  • This is really making them parallel and looks quite like something i already managed, the problem is that the Link isn't long enough and it looks like it has a margin from the Node. this happens because his size is calcultated somehow i think from the middle of the node and not this points – Sahar Sabin Sep 12 '17 at 11:16
  • Updated: Link's position is calculated by nodes' position. It's about geometry relation. – leaf Sep 13 '17 at 05:03
  • Can you publish the whole function? – Sahar Sabin Sep 13 '17 at 12:54
  • Sure.The function is modified based on OP. Note that `x2` and `y2` use `sin` and `cos`. – leaf Sep 14 '17 at 02:16