Akhilesh Bhatia
Akhilesh Bhatia

Reputation: 132

End points of the links of the force directed graph always stuck to left corner of the rectangular node

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:

Link pointing to left

Following is the expected result:

enter image description here

Upvotes: 1

Views: 604

Answers (1)

Akhilesh Bhatia
Akhilesh Bhatia

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

Link pointing to the center

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

Related Questions