Skip to content

Instantly share code, notes, and snippets.

@EfratVil
Last active January 26, 2017 18:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EfratVil/27eb71f3523f0d5d97e10bf77957fa1c to your computer and use it in GitHub Desktop.
Save EfratVil/27eb71f3523f0d5d97e10bf77957fa1c to your computer and use it in GitHub Desktop.
clusters force
<!DOCTYPE html>
<meta charset="utf-8">
<svg width="960" height="700"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
padding = 1.5;
var n = 300, // nodes
m = 3; // clusters
var colorRange1 = ['#9BB0DB', '#708DC8', '#486CB4'],
colorRange2 = ['#D7A1C9', '#B06FAE', '#AC53A0'],
colorRange3 = ['#F6A4BF', '#EF77A0', '#EB4F83'];
var color1 = d3.scaleLinear().range(colorRange1).domain([-1, 0, 1]),
color2 = d3.scaleLinear().range(colorRange2).domain([-1, 0, 1]),
color3 = d3.scaleLinear().range(colorRange3).domain([-1, 0, 1]);
var radialGradient1 = svg.append("defs")
.append("radialGradient")
.attr("id", "radial-gradient1");
radialGradient1.append("stop")
.attr("offset", "0%")
.attr("stop-color", color1(-1));
radialGradient1.append("stop")
.attr("offset", "50%")
.attr("stop-color", color1(0));
radialGradient1.append("stop")
.attr("offset", "100%")
.attr("stop-color", color1(1));
var radialGradient2 = svg.append("defs")
.append("radialGradient")
.attr("id", "radial-gradient2");
radialGradient2.append("stop")
.attr("offset", "0%")
.attr("stop-color", color2(-1));
radialGradient2.append("stop")
.attr("offset", "50%")
.attr("stop-color", color2(0));
radialGradient2.append("stop")
.attr("offset", "100%")
.attr("stop-color", color2(1));
var radialGradient3 = svg.append("defs")
.append("radialGradient")
.attr("id", "radial-gradient3");
radialGradient3.append("stop")
.attr("offset", "0%")
.attr("stop-color", color3(-1));
radialGradient3.append("stop")
.attr("offset", "50%")
.attr("stop-color", color3(0));
radialGradient3.append("stop")
.attr("offset", "100%")
.attr("stop-color", color3(1));
var clusters = new Array(m);
var nodes = d3.range(n).map(function () {
var i = Math.floor(Math.random() * m+1),
r = Math.random() * 15 + 5,
d = {
cluster: i,
radius: Math.random() * 15 + 5,
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()
.force('center', d3.forceCenter(width / 2, height / 2))
.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 node = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", function (d) { return d.radius; })
.style("fill", function (d) {
if (d.cluster== 1) { return "url(#radial-gradient1)"; }
else {if (d.cluster == 2) { return "url(#radial-gradient2)"; }
else { return "url(#radial-gradient3)"; }
}
});
function layoutTick() {
node
.attr("cx", function (d) { return d.x; })
.attr("cy", function (d) { return d.y; })
}
// 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