Commit 82994ba7 authored by S Anand's avatar S Anand

ENH: add collision detection option for force networks

parent a865f0ab
......@@ -232,6 +232,7 @@ _G_network.force = function() {
nodes, // Currently active nodes
node_ids, // Dict mapping node id to node
links, // Currently active links
collide, // Collision detection function
brush = d3.svg.brush(),
force = d3.layout.force(),
self = {force: force, brush: brush}
......@@ -262,6 +263,13 @@ _G_network.force = function() {
var draw_label
force.on('tick', function() {
if (collide) {
var q = d3.geom.quadtree(nodes),
i = 0,
n = nodes.length
while (++i < n)
q.visit(collide(nodes[i]))
}
self.lines.attr('x1', function(d) { return d.source.x })
.attr('y1', function(d) { return d.source.y })
.attr('x2', function(d) { return d.target.x })
......@@ -382,9 +390,10 @@ _G_network.force = function() {
return self
}
self.circle = function(v) { if (!arguments.length) return draw_circle; draw_circle = v; return self }
self.label = function(v) { if (!arguments.length) return draw_label; draw_label = v; return self }
self.line = function(v) { if (!arguments.length) return draw_line; draw_line = v; return self }
self.circle = function(v) { if (!arguments.length) return draw_circle; draw_circle = v; return self }
self.label = function(v) { if (!arguments.length) return draw_label; draw_label = v; return self }
self.line = function(v) { if (!arguments.length) return draw_line; draw_line = v; return self }
self.collide = function(v) { if (!arguments.length) return collide; collide = v; return self }
self.draw = function(svg) {
svg = d3.select(svg)
......@@ -483,6 +492,44 @@ _G_network.force = function() {
return self
}
/* Sample usage:
force // Take a G.network.force() object
.collide( // Apply collision
G.network.collide.circle( // using a circular collission detection
function(node) { return node.size }, // with the radius of each node taken from the .size attribute
4 // and a 4px (optional) padding
))
*/
_G_network.collide = {
circle: function(radius_function, padding) {
padding = padding || 0
return function(node) {
var r = radius_function(node) + padding,
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 = radius_function(node) + padding + radius_function(quad.point)
if (l < r) {
l = (l - r) / l * 0.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
}
}
}
}
// TODO: arrows (how to do bi-directional relations?)
// - http://www.jansipke.nl/creating-network-diagrams-with-d3-js/
// - http://jsfiddle.net/tk7Wv/2/
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment