Currently, I am working on a force layout project. My main objective is to enable the nodes to avoid a particular div element placed in the center without utilizing gravity within the SVG. I have already implemented collision detection and bounding within the existing SVG structure.
The approach I am considering involves overlaying the SVG on top of the target div using absolute positioning and attempting to implement node avoidance logic within the tick function. However, this method is proving to be quite challenging. Are there any alternative approaches that could be more effective? Any guidance in the right direction would be greatly appreciated!
In addition to the primary issue, I am also interested in having the nodes fall into view from the top without using gravity. Since maintaining the spacing between nodes is crucial, the traditional focus method may not be suitable for this scenario. Iām unsure how to proceed with this secondary requirement.
I have included my Javascript and CSS code below for reference
width = parseInt(d3.select('#canvas').style('width'), 10),
height = parseInt(d3.select('#canvas').style('height'), 10),
padding = 30, // separation between circles
radius = 70;
//Set up the force layout
var force = d3.layout.force()
.gravity(0)
.charge(0)
.size([width, height]);
//Append a SVG to the body of the html page.
//Assign this SVG as an object to svg
var svg = d3.select("#canvas").append("svg")
.attr("width", width)
.attr("height", height);
//Read the data
d3.json("dots.json", function(error, graph) {
if (error) throw error;
//Creates the graph data structure out of the json data
force.nodes(graph.nodes)
.start();
//Do the same with the circles for the nodes - no
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("g")
.attr("class", "node")
.call(force.drag);
node.append("circle")
.attr("r", radius)
.style("fill", "black")
.call(force.drag);
node.append("text")
.attr("dx", 0)
.attr("dy", 5)
.attr("height", 10)
.attr("text-anchor", "middle")
.text(function(d) { return d.name })
.style("fill", "white");
//Now we are giving the SVGs co-ordinates - the force layout
//is generating the co-ordinates which this code is using to
//update the attributes of the SVG elements
force.on("tick", function (e) {
node.attr("cx", function(d) {
return d.x =
Math.max(
radius,
Math.min(
width - radius,
d.x
)
);
}).attr("cy", function(d) {
return d.y = Math.max(radius, Math.min(height - radius, d.y));
});
node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
node.each(collide(0.5)); //Added
});
function collide(alpha) {
var quadtree = d3.geom.quadtree(graph.nodes);
return function(d) {
var rb = 2*radius + padding,
nx1 = d.x - rb,
nx2 = d.x + rb,
ny1 = d.y - rb,
ny2 = d.y + rb;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y);
if (l < rb) {
l = (l - rb) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}
node.on("mousedown", function(d1, i) {
var $this = d3.select(this);
if(node.active) {
$this = $this.transition()
.duration(1000)
.attr("stroke-width", 0)
.attr("r", radius);
node.active = false;
} else {
$this = $this.transition()
.duration(1000)
.attr("stroke-width", 20)
.attr("stroke", "4DD2B6")
.attr("fill", "white")
.attr("r", radius * 2)
}
});
});
#canvas, #playground {
width: 100%;
height: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 1;
overflow: visible;
display: block;
}
#playground {
height: 100%;
}
header {
width: 320px;
margin: 100px auto 50px;
display: block;
z-index: 10;
background-color: red;
}