Last active
December 14, 2016 10:33
-
-
Save danharr/e95189aa287536a5de98 to your computer and use it in GitHub Desktop.
Grid Multi Foci 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
<!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