Reputation: 132
I am creating a force directed graph using v4 of d3.js. The links in the graph are always pointing to the left hand corner of the rectangular nodes.
I think the problem is either in my tick function or my drag handlers. I am not really sure which one is it and what is the problem.
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var simulation = d3.forceSimulation().nodes(nodes_data);
simulation
.force("centre_force", d3.forceCenter(width / 2, height / 2))
.force("charge_force", d3.forceManyBody().strength(-90))
var nodes = svg.append("g")
.attr("class", "nodes")
.selectAll("rect")
.data(nodes_data)
.enter()
.append("g");
var rect_width = 80;
var rect_height = 50;
nodes.append("rect")
.attr("width", rect_width)
.attr("height", rect_height)
.attr("rx", 10)
.attr("ry", 10)
.style("stroke", "black");
nodes.append("text")
.attr("text-anchor", "middle")
.attr("x", rect_width / 2)
.attr("y", rect_height / 2)
.attr("dy", "0.35em")
.text(function (d) { return d.name; });
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links_data)
.enter().append("line")
.attr("stroke-width", 2);
//defining force for links
var link_force = d3.forceLink(links_data)
.id(function (d) { return d.name; })
.distance(150)
.strength(0.5);
//calling the defined force
simulation.force("links", link_force);
simulation.on("tick", function () {
nodes.attr("transform", function (d) { return "translate(" + d.x + "," + d.y + ")"; });
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; });
nodes.attr("x", (d) => { return d.x; })
.attr("y", (d) => { return d.y; });
})
//drag function definitions
function drag_start(d) {
simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function drag_end(d) {
simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
//drag function binding
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);
drag_handler(nodes);
I want them to point at the edge of the rectangle and the edge should change dynamically if the position is changed so.
Following is the actual result:
Following is the expected result:
Upvotes: 1
Views: 604
Reputation: 132
I solved the problem.
First of all, I removed the following code
nodes.attr("x", (d) => { return d.x; })
.attr("y", (d) => { return d.y; });
There was no need for it.
Next, I changed the x and y co-ordinates of the rect element to point to the center of the rect. The default values for x and y is 0 and 0. In my case, I changed the x to -40 and to y to -25 as following
let rect_width = 80;
let rect_height = 50;
nodes.append("rect")
.attr("width", rect_width)
.attr("height", rect_height)
.attr("rx", 10)
.attr("ry", 10)
.attr("x", -(rect_width / 2))
.attr("y", -(rect_height / 2))
.style("stroke", "black");
Following is my result now
Possibly unecessary information- but to move the links behind my node, I drew the links first and then the nodes later in my code. Referred this answer
Upvotes: 2