Built with blockbuilder.org
Created
April 12, 2017 18:17
-
-
Save gazaston/6ecf283fb8a58ac96daddf89b94c09c5 to your computer and use it in GitHub Desktop.
clusters
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
license: mit |
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
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<body> | |
<script src="//d3js.org/d3.v4.min.js"></script> | |
<script> | |
var width = 960, | |
height = 500, | |
padding = 1.5, // separation between same-color nodes | |
clusterPadding = 6, // separation between different-color nodes | |
maxRadius = 80; | |
var n = 5, // total number of nodes | |
m = 1; // number of distinct clusters | |
var color = d3.scaleSequential(d3.interpolateRainbow) | |
.domain(d3.range(m)); | |
// The largest node for each cluster. | |
var clusters = new Array(m); | |
var nodes = d3.range(n).map(function() { | |
var i = Math.floor(Math.random() * m), | |
r = Math.sqrt((i + 1) / m * -Math.log(Math.random())) * maxRadius, | |
d = { | |
cluster: i, | |
radius: r, | |
x: Math.cos(i / m * 2 * Math.PI) * 200 + width / 2 + Math.random(), | |
y: Math.sin(i / m * 2 * Math.PI) * 200 + height / 2 + Math.random() | |
}; | |
if (!clusters[i] || (r > clusters[i].radius)) clusters[i] = d; | |
return d; | |
}); | |
var force = d3.forceSimulation() | |
// keep entire simulation balanced around screen center | |
.force('center', d3.forceCenter(width/2, height/2)) | |
// cluster by section | |
.force('cluster', cluster() | |
.strength(0.2)) | |
// apply collision with padding | |
.force('collide', d3.forceCollide(d => d.radius + padding) | |
.strength(0.7)) | |
.on('tick', layoutTick) | |
.nodes(nodes); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width) | |
.attr("height", height); | |
var node = svg.selectAll("circle") | |
.data(nodes) | |
.enter().append("circle") | |
.style("fill", function(d) { return color(d.cluster/1); }); | |
function layoutTick(e) { | |
node | |
.attr("cx", function(d) { return d.x; }) | |
.attr("cy", function(d) { return d.y; }) | |
.attr("r", function(d) { return d.radius; }); | |
} | |
// Move d to be adjacent to the cluster node. | |
// from: https://bl.ocks.org/mbostock/7881887 | |
function cluster () { | |
var nodes, | |
strength = 0.1; | |
function force (alpha) { | |
// scale + curve alpha value | |
alpha *= strength * alpha; | |
nodes.forEach(function(d) { | |
var cluster = clusters[d.cluster]; | |
if (cluster === d) return; | |
let x = d.x - cluster.x, | |
y = d.y - cluster.y, | |
l = Math.sqrt(x * x + y * y), | |
r = d.radius + cluster.radius; | |
if (l != r) { | |
l = (l - r) / l * alpha; | |
d.x -= x *= l; | |
d.y -= y *= l; | |
cluster.x += x; | |
cluster.y += y; | |
} | |
}); | |
} | |
force.initialize = function (_) { | |
nodes = _; | |
} | |
force.strength = _ => { | |
strength = _ == null ? strength : _; | |
return force; | |
}; | |
return force; | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment