I took a slightly different approach from Phrogz. I tried removing the path's marker and instead draw it using a new path that goes to the arc's midpoint and whose stroke is invisible. Computing the midpoint is a little finicky so if you want to change the characteristics of the arc you might be better served with Phrogz's approach, or some hybrid.
In this case the trig is not so bad because if you look closely you will notice the arc used to generate the links are from a circle with the same radius and the distance between the nodes. So you have an equilateral triangle and all you need to do really is compute the distance passed the midpoint of the link line segment to the arc midpoint.
I think I need a diagram to explain:
So triangle ABC is equilateral and EC bisect AB. Since we have coordinates for A and B finding M is easy (average the coordinates). It means we also know the slope from A to B (delta y / delta x) so the slope from M to E is the negative inverse. Knowing M and the slope to E means we are almost there, we just need to know how far to go.
To do that we use the fact that ACM is a 30-60-90 triangle and so
|CM| = sqrt(3) * |AM|
but |AM| = |AB| / 2 and |CE| = |AB|
So
|ME| = |AB| - sqrt(3) * |AB| / 2
In order for this length to make sense we will have to normalize it with the length of the slope vector, which we already know is the same as the circle's radius.
Anyway, putting it all together you get:
var markerPath = svg.append("svg:g").selectAll("path.marker")
.data(force.links())
.enter().append("svg:path")
.attr("class", function(d) { return "marker_only " + d.type; })
.attr("marker-end", function(d) { return "url(#" + d.type + ")"; });
... later in the tick handler
markerPath.attr("d", function(d) {
var dx = d.target.x - d.source.x,
dy = d.target.y - d.source.y,
dr = Math.sqrt(dx * dx + dy * dy);
// We know the center of the arc will be some distance perpendicular from the
// link segment's midpoint. The midpoint is computed as:
var endX = (d.target.x + d.source.x) / 2;
var endY = (d.target.y + d.source.y) / 2;
// Notice that the paths are the arcs generated by a circle whose
// radius is the same as the distance between the nodes. This simplifies the
// trig as we can simply apply the 30-60-90 triangle rule to find the difference
// between the radius and the distance to the segment midpoint from the circle
// center.
var len = dr - ((dr/2) * Math.sqrt(3));
// Remember that is we have a line's slope then the perpendicular slope is the
// negative inverse.
endX = endX + (dy * len/dr);
endY = endY + (-dx * len/dr);
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + endX + "," + endY;
});
Check it out here. Note that my path css for the marker path's is set to a transparent red, normally you would want to set stroke to 'none' to hide the lines.