forked from danharr's block: Grid Multi Foci Force Layout
Last active
October 1, 2018 14:18
-
-
Save FrissAnalytics/d08fd514971b86d2af0d8db715a86682 to your computer and use it in GitHub Desktop.
Grid Multi Foci Force Layout
This file contains hidden or 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 hidden or 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="http://d3js.org/d3.v3.min.js"></script> | |
<script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.min.js"></script> | |
<script> | |
// set parameters | |
var r = 10, | |
w = $(window).width(), | |
h = $(window).height(), | |
width = w-100, | |
height = h-100, | |
padding = 6, // separation between nodes | |
maxRadius = 20, | |
n = 200, // total number of nodes | |
m = 8; // number of distinct clusters | |
// color scale | |
var color = d3.scale.category10() | |
.domain(d3.range(m)); | |
// ordinal x scale | |
var x = d3.scale.ordinal() | |
.domain(d3.range(m)) | |
.rangePoints([0, width], 1); | |
// main data | |
var data = [ | |
{"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} | |
] | |
// status driven categorical x-axis | |
var xDomain = ["Suspect","Initial Engagement","Qualified ","Funding Sought","In Progress","Completed","Rejected"]; | |
var xScale = d3.scale.ordinal() | |
.domain(xDomain) | |
.rangeBands([50,800]); | |
// project driven categorical y-axis | |
var yDomain = ["Thomas Lee-Warren","Peter Bassett","Nigel Hodges","Andy McMurtrie","Peter Simmonds","Unknown"]; | |
var yScale = d3.scale.ordinal() | |
.domain(yDomain) | |
.rangeBands([50,800]); | |
// update data | |
data.forEach(function(d) { | |
d.cx = xScale(d.status); | |
d.cy = yScale(d.project); | |
}); | |
// setup force layout | |
var force = d3.layout.force() | |
.nodes(data) | |
.size([width, height]) | |
.gravity(0) | |
.charge(0) | |
.on("tick", tick) | |
.start(); | |
// container svg | |
var svg = d3.select("body").append("svg") | |
.attr("width", width+80) | |
.attr("height", height+80); | |
// draw initial circles | |
var circle = svg.selectAll("circle") | |
.data(data) | |
.enter().append("circle") | |
// radius | |
.attr("r", function(d) { return d.radius; }) | |
// fill color | |
.style("fill", function(d) { return color(d.project); }) | |
// stroke color | |
.style("stroke","gray") | |
// stoke width | |
.style("stroke-width","1px") | |
// enable drag option | |
.call(force.drag); | |
// tick function | |
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(data); | |
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