score:0
i search online, none of the answer worked, so i made my own:
here is the code:
//arrows
svg.append("defs").selectall("marker")
.data(["suit", "licensing", "resolved"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewbox", "0 -5 10 10")
.attr("refx", 9)
.attr("refy", 0)
.attr("markerwidth", 10)
.attr("markerheight", 10)
.attr("orient", "auto")
.append("path")
.attr("d", "m0,-5l10,0l0,5 l10,0 l0, -5")
.style("stroke", "#4679bd")
.style("opacity", "0.6");
//create all the line svgs but without locations yet
var link = svg.selectall(".link")
.data(forcedata.links)
.enter().append("line")
.attr("class", "link")
.style("marker-end", "url(#suit)");
//set up the force layout
var force = d3.layout.force()
.nodes(forcedata.nodes)
.links(forcedata.links)
.charge(-120)
.linkdistance(200)
.size([width, height])
.on("tick", tick)
.start();
function tick(){
link.attr("x1", function (d) { return d.source.x; })
.attr("y1", function (d) { return d.source.y; })
.attr("x2", function (d) {
return calculatex(d.target.x, d.target.y, d.source.x, d.source.y, d.target.radius);
})
.attr("y2", function (d) {
return calculatey(d.target.x, d.target.y, d.source.x, d.source.y, d.target.radius);
});
d3.selectall("circle")
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; });
d3.select("#forcelayoutgraph").selectall("text")
.attr("x", function (d) { return d.x; })
.attr("y", function (d) { return d.y; });
}
function calculatex(tx, ty, sx, sy, radius){
if(tx == sx) return tx; //if the target x == source x, no need to change the target x.
var xlength = math.abs(tx - sx); //calculate the difference of x
var ylength = math.abs(ty - sy); //calculate the difference of y
//calculate the ratio using the trigonometric function
var ratio = radius / math.sqrt(xlength * xlength + ylength * ylength);
if(tx > sx) return tx - xlength * ratio; //if target x > source x return target x - radius
if(tx < sx) return tx + xlength * ratio; //if target x < source x return target x + radius
}
function calculatey(tx, ty, sx, sy, radius){
if(ty == sy) return ty; //if the target y == source y, no need to change the target y.
var xlength = math.abs(tx - sx); //calculate the difference of x
var ylength = math.abs(ty - sy); //calculate the difference of y
//calculate the ratio using the trigonometric function
var ratio = radius / math.sqrt(xlength * xlength + ylength * ylength);
if(ty > sy) return ty - ylength * ratio; //if target y > source y return target x - radius
if(ty < sy) return ty + ylength * ratio; //if target y > source y return target x - radius
}
score:2
you may order the svg elements such that the circles will be rendered first, the lines with arrows thereafter (in d3 there is a .order
method, see here for details. for the record, the corrsponding part of the raphael api is discussed here).
score:5
this is really funny; i just solved this problem yesterday.
what i did is to end the path at the edge of the node, not at the centre. my case is more complicated because i use bezier curves, not straight lines, but this might help you:
svg.append("svg:defs").selectall("marker")
.data(["default"])
.enter().append("svg:marker")
.attr("id", string)
.attr("viewbox", "0 -3 6 6")
.attr("refx", 5.0)
.attr("refy", 0.0)
.attr("markerwidth", 6)
.attr("markerheight", 6)
.attr("orient", "auto")
.append("svg:path")
.attr("d", "m0,-2.0l5,0l0,2.0");
links
.attr("fill", "none")
.attr("d", function(d) {
var tightness = -3.0;
if(d.type == "straight")
tightness = 1000;
// places the control point for the bezier on the bisection of the
// segment between the source and target points, at a distance
// equal to half the distance between the points.
var dx = d.target.x - d.source.x;
var dy = d.target.y - d.source.y;
var dr = math.sqrt(dx * dx + dy * dy);
var qx = d.source.x + dx/2.0 - dy/tightness;
var qy = d.source.y + dy/2.0 + dx/tightness;
// calculates the segment from the control point q to the target
// to use it as a direction to wich it will move "node_size" back
// from the end point, to finish the edge aprox at the edge of the
// node. note there will be an angular error due to the segment not
// having the same direction as the curve at that point.
var dqx = d.target.x - qx;
var dqy = d.target.y - qy;
var qr = math.sqrt(dqx * dqx + dqy * dqy);
var offset = 1.1 * node_size(d.target);
var tx = d.target.x - dqx/qr* offset;
var ty = d.target.y - dqy/qr* offset;
return "m" + d.source.x + "," + d.source.y + "q"+ qx + "," + qy
+ " " + tx + "," + ty; // to "node_size" pixels before
//+ " " + d.target.x + "," + d.target.y; // til target
});
by the way; you'll have to do the same for the 'source' arrow head (i only have it at the target)
score:6
this is an old question, but here is my solution if you want your arrowheads to be at the edge of your nodes instead of on top of or beneath them. my approach was also to draw the path connecting the nodes such that the end points were on the nodes' edges rather than at the nodes' centers. starting from the mobile patent suits example (http://bl.ocks.org/mbostock/1153292), i replaced the linkarc method with:
function linkarc(d) {
var sourcex = d.source.x;
var sourcey = d.source.y;
var targetx = d.target.x;
var targety = d.target.y;
var theta = math.atan((targetx - sourcex) / (targety - sourcey));
var phi = math.atan((targety - sourcey) / (targetx - sourcex));
var sintheta = d.source.r * math.sin(theta);
var costheta = d.source.r * math.cos(theta);
var sinphi = d.target.r * math.sin(phi);
var cosphi = d.target.r * math.cos(phi);
// set the position of the link's end point at the source node
// such that it is on the edge closest to the target node
if (d.target.y > d.source.y) {
sourcex = sourcex + sintheta;
sourcey = sourcey + costheta;
}
else {
sourcex = sourcex - sintheta;
sourcey = sourcey - costheta;
}
// set the position of the link's end point at the target node
// such that it is on the edge closest to the source node
if (d.source.x > d.target.x) {
targetx = targetx + cosphi;
targety = targety + sinphi;
}
else {
targetx = targetx - cosphi;
targety = targety - sinphi;
}
// draw an arc between the two calculated points
var dx = targetx - sourcex,
dy = targety - sourcey,
dr = math.sqrt(dx * dx + dy * dy);
return "m" + sourcex + "," + sourcey + "a" + dr + "," + dr + " 0 0,1 " + targetx + "," + targety;
}
note that this code expects an "r," or radius, attribute to be in the node data. to place the points of the arrows at the correct positions, i changed the refx and refy attributes so that the point of the arrow was at the edge of the node:
svg.append("defs").selectall("marker")
.data(["suit", "licensing", "resolved"])
.enter().append("marker")
.attr("id", function(d) { return d; })
.attr("viewbox", "0 -5 10 10")
.attr("refx", 10)
.attr("refy", 0)
.attr("markerwidth", 6)
.attr("markerheight", 6)
.attr("orient", "auto")
.append("path")
.attr("d", "m0,-5l10,0l0,5");
Source: stackoverflow.com
Related Query
- linking nodes of variable radius with arrows
- How to create a beeswarm plot with variable radius in d3js v5?
- D3 Force Graph With Arrows and Curved Edges - shorten links so arrow doesnt overlap nodes
- Setting the circle radius in d3js with a dynamic variable
- How can I add a variable number of nodes with D3 append() function depending on data
- Drawing multiple edges between two nodes with d3
- D3 force layout - linking nodes by name instead of index
- drawing circle with radius specified in meters on a map
- How can I start with all the nodes collapsed in d3js?
- d3js create a force layout with fixed nodes
- D3 updating graph with new elements create edges with the wrong nodes
- Sankey-diagram PowerBI custom visual with color nodes and ordering
- D3 force layout graph with nodes positioned in a grid
- How to check d3 js force graph for nodes with no links and remove them?
- D3 Linking nodes based on names rather than index
- Dragging nodes with labels in d3 v4 force layout glitches
- d3js (v4) canvas force layout with text on nodes
- D3 .append() with variable
- Problems positioning nodes with d3.js force-layout. Nodes "re-entering" each data update, example inside
- d3 adding and removing nodes with force
- Speed up d3 force layout with many nodes and links
- Arrows are not touching to nodes in d3.js
- D3js force layout - line with gradient between nodes
- D3: Tree diagram with images and circles as nodes
- d3 force collapsible layout - start page with all nodes collapsed
- How to use D3 force layout with existing SVG elements as nodes
- Javascript syntax: variable declaration with "<<" or ">>"
- d3 graphs on google maps with link between nodes
- How to Limit Size of Radius With d3.js
- d3.js dynamically append swarms with variable force bounds
More Query from same tag
- How to add specific colors to data in JSON with d3.js
- d3.js not able to parse json data
- Javascript closure property manipulation
- D3 bar chart by date with context brushing
- D3 draw children paths under parents
- getting data for d3.js from mysql with php
- what tools can I use to build drill down graphs?
- d3.js: sort not working on text strings
- Working with JSON and Angular NVD3
- nodes and clusters and cluster-to-cluster links using D3
- failing unit test for d3.csv() using Karma and Jasmine
- How do I catch xlink:href errors in D3?
- Change label text color in row chart
- D3 Tree layout: how to highlight a whole path
- d3 multiline update path and transition path does not work with nested data
- d3 timeout like angular $.timeout
- Labeling lines in d3 parallel coordinates
- D3 treemap call resulting in NaN x0, x1, y0, y1 values
- Ignore missing images in SVG with D3 data and enter methods
- D3 js Drag and Drop Zoomable Tree help in collapsing nodes connected by a certain link
- Un-check and check all for multiple sets of checkbuttons in JavaScript
- Using .translateExtent in D3 returns 'NaN' x & y values when zooming
- SVG tag mousedown event with D3
- Path intersection causes parts of them to disappear [D3 Path Generation]
- D3: Add data value labels to multi line graph
- Reversing x domain on dc.js series chart
- d3.js opening a new tab by dbclick event
- csv implementation with cal-heatmap jquery
- c3js Hide data after legend click and data update
- d3 bar chart transition from csv