I have a force-directed graph in D3.js where the node radius is proportional to a property of that data (e.g., pageviews) and the link width is proportional to a property of the linking data (e.g., clicks). I would like to give the link curve an indicator of its direction. The problem is that the links travel to the center of the data node, so if I use marker-end
, I get:
(Data nodes are normally filled with a color linked to another data category...)
I create my ~~arcs~~ curves using:
positionLink = (d) => {
const offset = 100;
const midpoint_x = (d.source.x + d.target.x) / 2;
const midpoint_y = (d.source.y + d.target.y) / 2;
const dx = d.source.x - d.target.x;
const dy = d.source.y - d.target.y;
// Perpendicular vector
const nx = -dy;
const ny = dx;
const norm_length = Math.sqrt((nx*nx)+(ny*ny));
const normx = nx / norm_length;
const normy = ny / norm_length;
const offset_x = parseFloat(midpoint_x + offset * normx.toFixed(2));
const offset_y = parseFloat(midpoint_y + offset * normy.toFixed(2));
const arc = `M ${d.source.x.toFixed(2)} ${d.source.y.toFixed(2)} S ${offset_x} ${offset_y} ${d.target.x.toFixed(2)} ${d.target.y.toFixed(2)}`;
return arc;
};
What my code calls arc
is an SVG "S" path, which is a "Smooth curveto" but I'm not wed to that in particular: I just need to pull the arcs apart from each other so that I can show the difference between data in one direction and in the other.
How can I locate the intersection of the Bezier curve with the circle?
(Since the target of the curve is the center of the circle, I suppose this could be rephrased as "The value of the Bezier curve at distance r
from its ending point")
If I had that one point, I could make it the apex of an arrowhead.
(Even better would be if I had the slope of the Bezier at that point so I could really align it, but I think I can get away with just aligning it to the line between the midpoint and the anchor...)
Consider the following iterative method:
Using
path.getPointAtLength
, you can traverse the path until you find a point that is exactlyr
from the centre of the circle, and then redraw the path using those coordinates instead.