Search code examples
htmlsvgbeziermarkers

SVG: how to correct for off-centered markers with bezier curved paths?


Context

I want to get an arrowhead on a path to a node in a graph that I am making. Because I am using bezier curves it is easier to use the center of the points to / from which the path ends / starts respectively.

In the attached JSFiddle (below) we see a simple triangle of points, one of which is the control points for a quadratic bezier curve. In addition the end markers have been offset to make contact with the node rather than being partially behind it; this is due to paths being drawn to the centers of the points rather than the edges.

Aesthetically there are a few things not quite right with this drawing:

  • the tip of the arrow head is thiner than the path

  • although the tip is angled correctly for the arrowhead on the bezier curve, the path is not centered at the point the arrow head appears.

These aesthetic flaws occur because:

  • the point of an arrow head is obviously thiner than a path / the path extends through the node

  • the arrow head is so large in respect to the curvature of the path, there is no satisfactory solution to the arrow head problem (given the current code)

Now one could jury-rig the second issue by making a tight cubic bezier curve as done in the second SVG of the JSFiddle.

However, as seen in the third SVG, this does not work with extreme curvature either.

Questions

Is there either a simple way to ensure that the angle of the arrow-head's point and positions of the path when the arrow head joins are centered; alternatively a way to simply scale the arrow head to be small enough where one would not notice?

Is there a way to make the path starting at the arrowhead to the end invisible? / alternatively a simple way to get paths to end prior to hitting the node?

# code to meet SO requirements
# look at this code

JSFiddle

SVG Marker Demo


Solution

  • For your specific application, try adding a viewBox to the marker to make it smaller so it looks somewhat aligned with the end of the bezier. (SVG markers do not currently align with curves.) Change refX to 'slide' the arrow a bit forward to the end of the line. e.g.

    <marker id="arrow" viewBox="0 0 25 25" markerWidth="20" markerHeight="10" refX="20" refY="5" orient="auto" markerUnits="strokeWidth">