I'm visualizing a force lay-out network with D3 and I have a problem with positioning the arrowheads along the edges between my nodes. As you can see in the picture, I am scaling the size of my nodes according to the value of a property of each node. Basically I need some sort of method to dynamically caculate/change the position of my arrowhead on my edges (according to same value used for scaling the nodes) to make them visible and prevent them from overlapping with the nodes. Actually I want my arrowheads to "touch" the outer edge of my nodes. Does anyone a way to do this? These code fragments show how I create my arrowheads. Maybe I should use another way?
p.s. I know I can change to order of my drawings to draw the arrowheads on top of my nodes but that's not what I want.
...
svg.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("refX", 5) /*must be smarter way to calculate shift*/
.attr("refY", 2)
.attr("markerWidth", 6)
.attr("markerHeight", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0,0 V 4 L6,2 Z");
...
path.enter()
.append("svg:path")
.attr("class", function (d) {
return "link " + d.type;
})
.attr("id", function (d) {
return "path_" + d.id;
})
.attr("marker-end", "url(#arrowhead)")
.transition().duration(8000)
.style("stroke-width", stylePathStrokeWidth)
...
I solved the problem based on Mark's answer to this question Align Marker on node edges D3 Force Layout. This is my code inside the tick function:
function tick() {
// fit path like you've been doing
path.attr("d", function (d, i) {
dr = 550 / d.linknum;
var result = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
return result;
});
// recalculate and back off the distance
path.attr("d", function (d, i) {
var pl = this.getTotalLength();
//this is the magic
var r = d.target.size + 3 * d.size; // Multiply the marker size (3) with the size of the edge (d.size) because the markers are scaling with the edge which they are attached to!!
var m = this.getPointAtLength(pl - r);
dr = 550 / d.linknum;
var result = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + m.x + "," + m.y;
return result;
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With