Reputation: 454
How to use collision detection function for force layout d3. As i searched i got this code but if consider layout doesn't contain any circle.It contains only group with some images and text. So how can i rewrite this function.
function collide(node) {
var r = node.radius + 16,
nx1 = node.x - r,
nx2 = node.x + r,
ny1 = node.y - r,
ny2 = node.y + r;
return function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== node)) {
var x = node.x - quad.point.x,
y = node.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = node.radius + quad.point.radius;
if (l < r) {
l = (l - r) / l * .5;
node.x -= x *= l;
node.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
};}
Upvotes: 0
Views: 1323
Reputation: 14591
Since the height and width of each node is same, the only required change would be to use the size of group
instead of node.radius
in the collide
function. Ensure to have a unique data bonded to each node.
var width = 960,
height = 500;
var nodes = d3.range(200).map(function() {
return {
radius: Math.random() * 12 + 4
};
}),
root = nodes[0],
color = d3.scale.category10();
root.radius = 0;
root.fixed = true;
var force = d3.layout.force()
.gravity(0.05)
.charge(function(d, i) {
return i ? 0 : -2000;
})
.nodes(nodes)
.size([width, height]);
force.start();
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
var node = svg.selectAll(".node")
.data(nodes.slice(1))
.enter()
.append("g")
.attr("class", "node")
.attr("id",function(d,i){ return d.id = "node"+i; });
node.append("svg:image")
.attr("xlink:href", "http://www.clker.com/cliparts/g/l/R/7/h/u/teamstijl-person-icon-blue.svg")
.attr("width", "30px")
.attr("height", "30px");
force.on("tick", function(e) {
var q = d3.geom.quadtree(nodes),
i = 0,
n = nodes.length;
while (++i < n) q.visit(collide(nodes[i]));
svg.selectAll(".node")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")"
});
});
svg.on("mousemove", function() {
var p1 = d3.mouse(this);
root.px = p1[0];
root.py = p1[1];
force.resume();
});
function collide(node) {
var nodeEl = svg.selectAll("g.node")
.filter(function(d, i) {
return node.id == d.id
}).node();
var nodeSize = nodeEl.getBBox().height+16;//You can remove/reduce this static value 16 to decrease the gap between nodes.
var r = nodeSize / 2 + 16,
nx1 = node.x - r,
nx2 = node.x + r,
ny1 = node.y - r,
ny2 = node.y + r;
return function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== node)) {
var x = node.x - quad.point.x,
y = node.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = nodeSize / 2 + quad.point.radius;
if (l < r) {
l = (l - r) / l * .5;
node.x -= x *= l;
node.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1