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 | |