In this D3.js graph I'm using the magic numbers 20
when the line is straight and 30
when the line is at an angle as the margin to withdraw from the path in order to add a margin between the circles (graph nodes) and the paths (graph edges).
I'm also using the fairly random number 1.5
as a multiplier to further the distance from the circle of the path's end, since it has a marker-end
attached to it.
Given the circle radius of 19
and the arrow path coordinates M0,0 V4 L2,2 Z
, I assume it should be possible to calculate the exact distance ("margin") the paths should have from the circles, but my math skills just aren't up for it. I also assume it's possible to figure out the direction of the paths so the margin inversion is no longer required.
If you have ideas on how the distance and margin calculation within the withMargins()
function can be optimized, please provide an answer. All optimizations and code reductions are welcome. Here's the relevant code:
this.withMargins = function() {
var diff = {
x: edge.end.x - edge.start.x,
y: edge.end.y - edge.start.y
};
var margins = {
start: {
x: 0,
y: 0
},
end: {
x: 0,
y: 0
}
};
if (diff.x > 0 && diff.y === 0) {
margins.start.x = 30;
} else if (diff.x < 0 && diff.y === 0) {
margins.start.x = -30;
} else if (diff.x > 0) {
margins.start.x = 20;
} else if (diff.x < 0) {
margins.start.x = -20;
}
if (diff.y > 0 && diff.x === 0) {
margins.start.y = 30;
} else if (diff.y < 0 && diff.x === 0) {
margins.start.y = -30;
} else if (diff.y > 0) {
margins.start.y = 20;
} else if (diff.y < 0) {
margins.start.y = -20;
}
if (margins.start.x != 0) {
margins.end.x = margins.start.x < 0 ?
Math.abs(margins.start.x * 1.5) :
margins.start.x * -1.5;
}
if (margins.start.y != 0) {
margins.end.y = margins.start.y < 0 ?
Math.abs(margins.start.y * 1.5) :
margins.start.y * -1.5;
}
// The top branch edges are inverted, so their margins
// needs to be inverted too.
if (edge.branch === 'top') {
var startX = margins.start.x;
var startY = margins.start.y;
margins.start.x = margins.end.x * -1;
margins.start.y = margins.end.y * -1;
margins.end.x = startX * -1;
margins.end.y = startY * -1;
}
edge.start.x += margins.start.x;
edge.start.y += margins.start.y;
edge.end.x += margins.end.x;
edge.end.y += margins.end.y;
return edge;
};
The code might look a bit wonky, but that can largely be explained by it being torn out of a Reveal.js presentation I'm working on. I'm all up for ideas on how to improve other parts of the code as well, but it's particularly the body of the withMargins()
function I'm unhappy with.
As far I understand - you have center of the first circle (x0,y0), center of the second circle (x1,y1), circle radius R, desired margin from circle circumference M, and want to find starting and ending coordinates of arrow.
(Seems you are using full distance from circle center, in this case set Marg)
That's all.