score:19
Instead of placing the marker on an end, create your lines (<polyline>
or <path>
) with a single point in the middle of the line and use marker-mid
to apply the arrowheads.
This demo for this answer of mine uses this technique to create multiple interior points along the length of a path along with marker-mid
. You would simply be creating a single 'waypoint' instead of many.
Edit: Here's a simple hack to the existing demo showing what I mean:
Demo: http://jsfiddle.net/tk7Wv/2/
The only changes are:
- Changing
marker-end
tomarker-mid
, and - Modifying the path generation code to create two arcs (connected in the middle) instead of one.
It will require some simple trigonometry like Superboggly illustrates to pick an appropriate midpoint based on the amount of bowing you want in your lines.
score:10
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.
score:17
I'm the OP, this answer is just an addition to the excellent answers above for the sake of others with the same question.
The answers show how to achieve this for a graph with arc links. If you have straight links, the accepted answer needs to be modified slightly. This is how:
Your straight links are probably implemented with line
, they need to be converted into polyline
. Like so:
// old: svg.selectAll(".link").data(links).enter().append("line")
svg.selectAll(".link").data(links).enter().append("polyline")
Then we have to encode the polyline according to this example, so your original code that encodes the line
:
force.on("tick", function() {
link.attr("x1", function(d) {return d.source.x;})
.attr("y1", function(d) {return d.source.y;})
.attr("x2", function(d) {return d.target.x;})
.attr("y2", function(d) {return d.target.y;});
Changes into:
force.on("tick", function() {
link.attr("points", function(d) {
return d.source.x + "," + d.source.y + " " +
(d.source.x + d.target.x)/2 + "," + (d.source.y + d.target.y)/2 + " " +
d.target.x + "," + d.target.y; });
And last, don't forget the convert marker-end
to marker-mid
:
// old: link.attr("marker-end",
link.attr("marker-mid",
Credits to @Phrogz for showing the way.
Source: stackoverflow.com
Related Query
- Display an arrow head in the middle of D3 force layout link
- How to increase the length of a link in D3 force layout
- How to append the arrow marker dynamically in force layout d3.js
- Arrow head and link of the same color in D3 js graph
- How to achieve "flying Arcs" as link in the force layout of D3.js
- Connected link line animation when mouse over on the node in force layout d3
- Add and remove the class in the link d3 force layout
- Placing label in the middle of a link in d3 js tree layout
- How to update elements of D3 force layout when the underlying data changes
- D3 force layout fix root node at the center
- How to speed up the force layout animation in d3.js
- how find out if force layout done placing the nodes?
- Scaling an arrowhead on a D3 force layout link marker
- Small Box to display where we are hovering in force layout (D3.js)
- Dynamic Link Distance in D3 force layout
- how to control the simulation speed of d3 force layout
- d3 force directed layout - link distance priority
- How to force nvd3 to display the equal number of ticks as that of the values plotted on the graph-nvd3
- I want to distinguish the link of d3.js force graph by the thickness
- d3js display arrow at the end of each axis
- Multiple instances of d3 force layout on the same page
- SVG markers don't orient properly on a d3.svg.diagonal curve used as a D3 force layout link
- How to display a text when mouseover a node in D3 force layout
- How to get the same node positions in d3's force layout graph
- Change d3 force layout link style to match d3-tree look
- How to make in d3 force layout the gravity data dependant
- How to place marker head in the middle of the links
- D3: Force Layout with fixed Y ranges - Reducing link overlap
- Log the x,y coordinates of nodes in a converged D3 force layout
- Link D3 force layout network diagram with table on mouseover
More Query from same tag
- heat map hide columns by date
- Get all the data from a clicked node in C3JS
- Draw area between 2 paths
- openseadragon svg overlay - clickable area is too large
- Node.js jsdom/express response cache?
- Add text label to d3 node in Force layout
- Collapse d3js tree to a specified depth
- Uncaught SyntaxError: missing ) after argument list when using Object.assign await
- How to apply rotate transformation and don't change the coordinates system in D3.js?
- D3 with Angular - Half Pie chart Chart colors sequence
- Circle pack layout using nest() and rollup
- How to specify height and width of a d3 tree dynamically to allow it to take up all the space it needs
- Can not show labels in group bar chart d3js v6
- d3js: why doesn't first bar disappear using exit method?
- How to add specific colors to data in JSON with d3.js
- How can I draw a continuous line using d3 without needing to click&drag the mouse, but rather just use the mouseover event?
- How to use d3 with and express application - reference error: document is not defined
- Plotting 2 graphs together in Rickshaw
- Displaying SVG elements with D3 and d3.slider: Uncaught ReferenceError: svg is not defined
- d3.mouse is not a function
- Donut3D.js 3d pie chart change data event not firing
- add data and redraw D3 chord layout
- d3 ordinal x-axis, change label order and shift data position
- Visual Treelist with D3.js
- D3 example from Observable on my wordpress site
- Foreignobject from SVG is not converted and appear in PDF by TCPDF
- Filter with datum in D3js?
- Line Graph on top of MultiBar Graph NVD3, d3.js
- Get the inner content of a gzipped SVG file with ajax call
- C3 - line chart time series error: x is not defined for id = "Dates"