A recreation of an earlier Protovis example.
forked from mbostock's block: N-Body Problem
license: gpl-3.0 |
A recreation of an earlier Protovis example.
forked from mbostock's block: N-Body Problem
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
body { | |
background: #333; | |
} | |
</style> | |
<canvas width="960" height="500"></canvas> | |
<script src="//d3js.org/d3.v3.min.js"></script> | |
<script> | |
var canvas = document.querySelector("canvas"), | |
context = canvas.getContext("2d"), | |
width = canvas.width, | |
height = canvas.height; | |
var n = 200, | |
tau = 2 * Math.PI, | |
nodes = d3.range(n).map(function() { return {radius: Math.random() * 8 + 2}; }); | |
var force = d3.layout.force() | |
.charge(0.5) | |
.gravity(0) | |
.friction(1) | |
.nodes(nodes) | |
.size([width, height]) | |
.start(); | |
context.fillStyle = "#fff"; | |
force.on("tick", function(e) { | |
context.clearRect(0, 0, width, height); | |
var q = d3.geom.quadtree(nodes), node, i; | |
for (i = 1; i < n; ++i) q.visit(collide(nodes[i])); | |
for (i = 1; i < n; ++i) { | |
node = nodes[i]; | |
context.beginPath(); | |
context.arc(node.x, node.y, node.radius, 0, tau); | |
context.fill(); | |
} | |
force.resume(); | |
}); | |
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 * 2); | |
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> |
�PNG | |