Circle-bound nodes in d3.layout.force(), using a variation of Mike Bostock's rectangular Bounded Force Layout. Here we calculate the maximum and minimum x for a given y in the circle, and vice versa.
| <html> | |
| <head> | |
| <title>Circular bounds</title> | |
| <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
| <link rel="stylesheet" type="text/css" href="style.css"> | |
| </head> | |
| <body> | |
| <div id="chart"></div> | |
| <script> | |
| var margin = 30, | |
| w = 500 - margin * 2, | |
| h = w, | |
| radius = w / 2, | |
| strokeWidth = 4, | |
| hyp2 = Math.pow(radius, 2), | |
| nodeBaseRad = 5; | |
| var svg = d3.select('#chart').append('svg') | |
| .attr('width', w + margin * 2) | |
| .attr('height', h + margin * 2) | |
| .append('g') | |
| .attr('transform', 'translate(' + margin + ',' + margin + ')'); | |
| var pool = svg.append('circle') | |
| .style('stroke-width', strokeWidth * 2) | |
| .attr({ | |
| class: 'pool', | |
| r: radius, | |
| cy: 0, | |
| cx: 0, | |
| transform: 'translate(' + w / 2 + ',' + h / 2 + ')' | |
| }); | |
| function randomNodes(n) { | |
| var data = [], | |
| range = d3.range(n); | |
| for (var i = range.length - 1; i >= 0; i--) { | |
| data.push({ | |
| rad: Math.floor(Math.random() * 12) | |
| }); | |
| } | |
| return data; | |
| } | |
| var nodeData = randomNodes(80); | |
| var force = d3.layout.force() | |
| .charge(-50) | |
| .gravity(0.05) | |
| .nodes(nodeData) | |
| .size([w, h]); | |
| var nodes = svg.selectAll('.nodes') | |
| .data(nodeData) | |
| .enter().append('circle') | |
| .attr({ | |
| class: 'nodes', | |
| r: function (d) { return d.rad + nodeBaseRad; }, | |
| fill: "#fff8d1" | |
| }) | |
| function pythag(r, b, coord) { | |
| r += nodeBaseRad; | |
| // force use of b coord that exists in circle to avoid sqrt(x<0) | |
| b = Math.min(w - r - strokeWidth, Math.max(r + strokeWidth, b)); | |
| var b2 = Math.pow((b - radius), 2), | |
| a = Math.sqrt(hyp2 - b2); | |
| // radius - sqrt(hyp^2 - b^2) < coord < sqrt(hyp^2 - b^2) + radius | |
| coord = Math.max(radius - a + r + strokeWidth, | |
| Math.min(a + radius - r - strokeWidth, coord)); | |
| return coord; | |
| } | |
| function tick() { | |
| nodes.attr('cx', function (d) { return d.x = pythag(d.rad, d.y, d.x); }) | |
| .attr('cy', function (d) { return d.y = pythag(d.rad, d.x, d.y); }); | |
| } | |
| nodes.call(force.drag); | |
| force.on('tick', tick) | |
| .start(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment