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.
Last active
August 11, 2021 04:38
-
-
Save nsonnad/5993342 to your computer and use it in GitHub Desktop.
Circle-bound D3 force layout
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#chart { | |
width: 600px; | |
margin: 0 auto; | |
} | |
.pool { | |
fill: #3db1ff; | |
stroke: #4f4f4f; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment