Skip to content

Instantly share code, notes, and snippets.

@danharr
Last active December 14, 2016 10:33
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 danharr/e95189aa287536a5de98 to your computer and use it in GitHub Desktop.
Save danharr/e95189aa287536a5de98 to your computer and use it in GitHub Desktop.
Grid Multi Foci Force Layout
<!DOCTYPE html>
<meta charset="utf-8">
<style>
circle {
stroke: #fff;
}
</style>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script>
var r = 10;
var w = $(window).width();
var h = $(window).height();
var width = w-100,
height = h-100,
padding = 6, // separation between nodes
maxRadius = 20;
var n = 200, // total number of nodes
m = 8; // number of distinct clusters
var color = d3.scale.category10()
.domain(d3.range(m));
var x = d3.scale.ordinal()
.domain(d3.range(m))
.rangePoints([0, width], 1);
var dandata =
[
{"project":"Thomas Lee-Warren","status":"In Progress","cx":820,"cy":50,"radius":14},
{"project":"Thomas Lee-Warren","status":"Initial Engagement","cx":280,"cy":50,"radius":8},
{"project":"Thomas Lee-Warren","status":"In Progress","cx":820,"cy":50,"radius":18},
{"project":"Peter Bassett","status":"Initial Engagement","cx":280,"cy":170,"radius":5},
{"project":"Peter Bassett","status":"Initial Engagement","cx":280,"cy":170,"radius":10},
{"project":"Nigel Hodges","status":"Suspect","cx":100,"cy":290,"radius":19},
{"project":"Peter Bassett","status":"Suspect","cx":100,"cy":170,"radius":15},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":20},
{"project":"Thomas Lee-Warren","status":"In Progress","cx":820,"cy":50,"radius":14},
{"project":"Unknown","status":"Rejected","cx":1180,"cy":650,"radius":20},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":12},
{"project":"Thomas Lee-Warren","status":"In Progress","cx":820,"cy":50,"radius":20},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":17},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":19},
{"project":"Peter Bassett","status":"Initial Engagement","cx":280,"cy":170,"radius":10},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":10},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":5},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":11},
{"project":"Peter Simmonds","status":"Completed","cx":1000,"cy":530,"radius":15},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":14},
{"project":"Peter Bassett","status":"Initial Engagement","cx":280,"cy":170,"radius":12},
{"project":"Thomas Lee-Warren","status":"Initial Engagement","cx":280,"cy":50,"radius":16},
{"project":"Peter Bassett","status":"In Progress","cx":820,"cy":170,"radius":16},
{"project":"Unknown","status":"Rejected","cx":1180,"cy":650,"radius":19},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":20},
{"project":"Peter Bassett","status":"Suspect","cx":100,"cy":170,"radius":9},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":10},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":17},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":18},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":8},
{"project":"Peter Bassett","status":"Rejected","cx":1180,"cy":170,"radius":6},
{"project":"Peter Bassett","status":"In Progress","cx":820,"cy":170,"radius":17},
{"project":"Peter Bassett","status":"In Progress","cx":820,"cy":170,"radius":10},
{"project":"Peter Bassett","status":"In Progress","cx":820,"cy":170,"radius":5},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":20},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":20},
{"project":"Andy McMurtrie","status":"Qualified ","cx":460,"cy":410,"radius":9},
{"project":"Andy McMurtrie","status":"In Progress","cx":820,"cy":410,"radius":14},
{"project":"Andy McMurtrie","status":"In Progress","cx":820,"cy":410,"radius":14},
{"project":"Andy McMurtrie","status":"Suspect","cx":100,"cy":410,"radius":12},
{"project":"Andy McMurtrie","status":"Funding Sought","cx":640,"cy":410,"radius":12},
{"project":"Thomas Lee-Warren","status":"Qualified ","cx":460,"cy":50,"radius":14},
{"project":"Andy McMurtrie","status":"In Progress","cx":820,"cy":410,"radius":17},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":12},
{"project":"Andy McMurtrie","status":"Funding Sought","cx":640,"cy":410,"radius":10},
{"project":"Nigel Hodges","status":"In Progress","cx":820,"cy":290,"radius":10},
{"project":"Nigel Hodges","status":"Initial Engagement","cx":280,"cy":290,"radius":20},
{"project":"Andy McMurtrie","status":"Initial Engagement","cx":280,"cy":410,"radius":12}
]
var xScale = d3.scale.ordinal().domain(["Suspect",
"Initial Engagement",
"Qualified ",
"Funding Sought",
"In Progress",
"Completed",
"Rejected"
])
.rangeBands([50,1400]);
var yScale = d3.scale.ordinal().domain([
"Thomas Lee-Warren",
"Peter Bassett",
"Nigel Hodges",
"Andy McMurtrie",
"Peter Simmonds",
"Unknown"
])
.rangeBands([50,680]);
dandata.forEach(function(d) {
d.cx = xScale(d.status);
d.cy = yScale(d.project);
});
var force = d3.layout.force()
.nodes(dandata)
.size([width, height])
.gravity(0)
.charge(0)
.on("tick", tick)
.start();
var svg = d3.select("body").append("svg")
.attr("width", width+80)
.attr("height", height+80);
var circle = svg.selectAll("circle")
.data(dandata)
.enter().append("circle")
.attr("r", function(d) { return d.radius; })
.style("fill", function(d) { return color(d.project); })
.style("stroke","black")
.call(force.drag);
function tick(e) {
circle
.each(gravity(.2 * e.alpha))
.each(collide(.5))
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
// Move nodes toward cluster focus.
function gravity(alpha) {
return function(d) {
d.y += (d.cy - d.y) * alpha;
d.x += (d.cx - d.x) * alpha;
};
}
// Resolve collisions between nodes.
function collide(alpha) {
var quadtree = d3.geom.quadtree(dandata);
return function(d) {
var r = d.radius + maxRadius + padding,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}
circle.append("title").text(function(d) {return d.color ;});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment