Skip to content

Instantly share code, notes, and snippets.

@pellekrogholt
Last active December 24, 2015 07:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pellekrogholt/6762073 to your computer and use it in GitHub Desktop.
Save pellekrogholt/6762073 to your computer and use it in GitHub Desktop.
could find the gist for http://mbostock.github.io/d3/talk/20111018/collision.html so here is a replication
# w = 1280, h = 800
collide = (node) ->
r = node.radius + 16
nx1 = node.x - r
nx2 = node.x + r
ny1 = node.y - r
ny2 = node.y + r
(quad, x1, y1, x2, y2) ->
if quad.point and (quad.point isnt node)
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 * 0.5
node.x -= x *= l
node.y -= y *= l
quad.point.x += x
quad.point.y += y
x1 > nx2 or x2 < nx1 or y1 > ny2 or y2 < ny1
w = 600
h = 600
nodes = d3.range(200).map(->radius: Math.random() * 12 + 4)
color = d3.scale.category10()
force = d3.layout.force().gravity(0.05).charge((d, i) ->
(if i then 0 else -2000)
).nodes(nodes).size([w, h])
root = nodes[0]
root.radius = 0
root.fixed = true
force.start()
svg = d3.select("#body").append("svg:svg").attr("width", w).attr("height", h)
svg.selectAll("circle").data(nodes.slice(1)).enter().append("svg:circle").attr("r", (d) ->
d.radius - 2
).style "fill", (d, i) ->
color i % 3
force.on "tick", (e) ->
q = d3.geom.quadtree(nodes)
i = 0
n = nodes.length
q.visit collide(nodes[i]) while ++i < n
svg.selectAll("circle").attr("cx", (d) ->
d.x
).attr "cy", (d) ->
d.y
svg.on "mousemove", ->
p1 = d3.mouse(this)
root.px = p1[0]
root.py = p1[1]
force.resume()
<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
<!-- note: for a production use then download the minified version -->
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<link rel="stylesheet" href="style.css"/>
<style type="text/css">
circle {
stroke: #000;
stroke-opacity: .5;
}
</style>
</head>
<body>
<div id="body">
<div id="footer">
Collision Detection
<div class="hint">move the mouse to repel nodes</div>
</div>
</div>
<script type="text/javascript" src="collision.js"></script>
</body>
</html>
// Generated by CoffeeScript 1.6.3
(function() {
var collide, color, force, h, nodes, root, svg, w;
collide = function(node) {
var nx1, nx2, ny1, ny2, r;
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) {
var l, x, y;
if (quad.point && (quad.point !== node)) {
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 * 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;
};
};
w = 600;
h = 600;
nodes = d3.range(200).map(function() {
return {
radius: Math.random() * 12 + 4
};
});
color = d3.scale.category10();
force = d3.layout.force().gravity(0.05).charge(function(d, i) {
if (i) {
return 0;
} else {
return -2000;
}
}).nodes(nodes).size([w, h]);
root = nodes[0];
root.radius = 0;
root.fixed = true;
force.start();
svg = d3.select("#body").append("svg:svg").attr("width", w).attr("height", h);
svg.selectAll("circle").data(nodes.slice(1)).enter().append("svg:circle").attr("r", function(d) {
return d.radius - 2;
}).style("fill", function(d, i) {
return color(i % 3);
});
force.on("tick", function(e) {
var i, n, q;
q = d3.geom.quadtree(nodes);
i = 0;
n = nodes.length;
while (++i < n) {
q.visit(collide(nodes[i]));
}
return svg.selectAll("circle").attr("cx", function(d) {
return d.x;
}).attr("cy", function(d) {
return d.y;
});
});
svg.on("mousemove", function() {
var p1;
p1 = d3.mouse(this);
root.px = p1[0];
root.py = p1[1];
return force.resume();
});
}).call(this);
body {
background: url(texture-noise.png);
overflow: hidden;
margin: 0;
font-size: 14px;
font-family: "Helvetica Neue", Helvetica;
}
#chart, #header, #footer {
position: absolute;
top: 0;
}
#header, #footer {
z-index: 1;
display: block;
font-size: 36px;
font-weight: 300;
text-shadow: 0 1px 0 #fff;
}
#header.inverted, #footer.inverted {
color: #fff;
text-shadow: 0 1px 4px #000;
}
#header {
top: 80px;
left: 140px;
width: 1000px;
}
#footer {
top: 680px;
right: 140px;
text-align: right;
}
rect {
fill: none;
pointer-events: all;
}
pre {
font-size: 18px;
}
line {
stroke: #000;
stroke-width: 1.5px;
}
.string, .regexp {
color: #f39;
}
.keyword {
color: #00c;
}
.comment {
color: #777;
font-style: oblique;
}
.number {
color: #369;
}
.class, .special {
color: #1181B8;
}
a:link, a:visited {
color: #000;
text-decoration: none;
}
a:hover {
color: #666;
}
.hint {
position: absolute;
right: 0;
width: 1280px;
font-size: 12px;
color: #999;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment