Skip to content

Instantly share code, notes, and snippets.

@rninne
Last active October 4, 2017 22:36
Show Gist options
  • Save rninne/b978525b5784476a98282ebfa2f03330 to your computer and use it in GitHub Desktop.
Save rninne/b978525b5784476a98282ebfa2f03330 to your computer and use it in GitHub Desktop.
Radius Based Multi-Foci Cluster Layout
<!DOCTYPE html>
<meta charset="utf-8">
<html>
<head>
<title></title>
<script src="https://d3js.org/d3.v3.min.js"></script>
</head>
<body style="background-color: black">
<div id="clusters" style="margin: auto; text-align: center;"></div>
<script src="vis.js"></script>
</body>
</html>
var width = 960,
height = 500;
var color = d3.scale.category10();
var positions = [];
var types = [];
var types = d3.range(1).map(function(i) {
return {
total_radius: 0,
position: {
x: 0,
y: height / 2,
},
color: color(i),
}
});
var nodes = [];
var force = d3.layout.force()
.gravity(0)
.charge(0)
.nodes(nodes)
.size([width, height])
.on("tick", ticked);
var svg = d3.select("#clusters").append("svg")
.attr("width", width)
.attr("height", height)
//.on("mousemove", addRandomNode);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", function(d) { return d.radius - 2; })
.style("fill", function(d) { return d.type.color; });
force.start();
function addRandomNode() {
var p1 = [Math.random() * width | 0, Math.random() * height | 0];
var r = Math.random() * types.length | 0;
var type = types[r];
var node = {
radius: Math.random() * 12 + 4,
type: type,
id: guid(),
color: type.color,
x: p1[0],
y: p1[1],
px: p1[0],
py: p1[1]
};
nodes.push(node);
svg.append("circle")
.data([node])
.attr("id", function(d) { return 'id' + d.id; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", function(d) { return d.radius - 2; })
.style("fill", function(d) { return d.type.color; })
force.resume();
}
function ticked(e) {
var q = d3.geom.quadtree(nodes),
k = e.alpha * 0.1,
n = nodes.length,
o,
c;
for (var i=0; i < types.length; i++)
types[i].total_radius = 0;
for (var i=0; i < n; i++) {
o = nodes[i];
o.type.total_radius += o.radius;
}
types.sort(function(a, b){
if ((a.total_radius - b.total_radius) == 0)
return - 1;
return a.total_radius - b.total_radius;
});
positions = [];
types.forEach(function(type) {
if (type.total_radius > 0)
positions.push(type);
})
for (var i=0; i < positions.length; i++) {
positions[i].position = {
x: (i + 1) * (width / (positions.length + 1)),
y: height / 2,
}
}
for (var i=0; i < n; i++) {
o = nodes[i];
o.x += (o.type.position.x - o.x) * k;
o.y += (o.type.position.y - o.y) * k;
q.visit(collide(o));
}
svg.selectAll("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
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 * .5;
node.px += x * l;
node.py += y * l;
}
}
return x1 > nx2
|| x2 < nx1
|| y1 > ny2
|| y2 < ny1;
};
}
// for(var i=0; i<150; i++)
// addRandomNode();
var ticks = 0;
var interval = setInterval(function(){
if (ticks > 150)
clearInterval(interval);
ticks += 1;
addRandomNode();
addRandomNode();
addRandomNode();
removeRandomNode();
if (types.length < 10 && ticks % 7 == 0)
addNewType();
}, 700)
function addNewType() {
types.push({
total_radius: 0,
position: {
x: 0,
y: height / 2,
},
color: color(types.length),
});
}
function removeRandomNode() {
var r = Math.random() * nodes.length | 0;
var node = nodes[r];
d3.select('#id' + node.id).remove();
nodes.splice(r, 1);
}
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment