Last active
December 14, 2016 10:33
-
-
Save danharr/3505bdf5a161c398bab3 to your computer and use it in GitHub Desktop.
Project Force Diagrams
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; | |
} | |
/* unvisited link */ | |
a:link { | |
color: #FF0000; | |
} | |
/* visited link */ | |
a:visited { | |
color: #00FF00; | |
} | |
body{ | |
background-color:#333;} | |
.headers { | |
font-family: ChevinLight,Verdana; | |
font-size: 22px; | |
fill:white; | |
} | |
.owners{ | |
font-family: "Julius Sans One",ChevinLight,Verdana; | |
font-size: 62px; | |
fill:#56564B; | |
} | |
.totals { | |
font-family: "Julius Sans One",ChevinBold,Verdana; | |
font-size: 22px; | |
fill:white; | |
} | |
div.tooltip { | |
position: absolute; | |
text-align: left; | |
padding: 10px; | |
font-size: 20px ; | |
font-family:"Julius Sans One",ChevinLight,Verdana; | |
background: rgba(0, 0, 0, 0.5); | |
color:white; | |
border: px; | |
border-radius: 8px; | |
} | |
.headers{ | |
display: inline-block; | |
margin-left: 20px; | |
width: 140px; | |
height: 60px; | |
white-space: nowrap; | |
border: 1px solid #686881; | |
text-align:center; | |
font-family:ChevinBold , calibri; | |
vertical-align:middle; | |
white-space: pre-wrap; /* CSS3 */ | |
white-space: -moz-pre-wrap; /* Firefox */ | |
white-space: -pre-wrap; /* Opera <7 */ | |
white-space: -o-pre-wrap; /* Opera 7 */ | |
word-wrap: break-word; /* IE */ | |
} | |
#top { | |
width:1400px; | |
} | |
</style> | |
<body> | |
<!--[if IE 6]> | |
<div id="nytg-error"> | |
<p>This interactive graphic requires a browser with SVG support, such as <a href="http://www.google.com/chrome">Chrome</a>, <a href="http://www.mozilla.org/en-US/firefox/">Firefox</a>, <a href="http://www.apple.com/safari/download/">Safari</a> or the latest <a href="http://windows.microsoft.com/en-US/internet-explorer/products/ie/home">Internet Explorer 9</a>. </p> | |
<img src="gal/ie.png" width="670" alt="Error"> | |
<div id="nytg-chartFrame" style="display:none;"> | |
<![endif]--> | |
<!--[if IE 7]> | |
<div id="nytg-error"> | |
<p>This interactive graphic requires a browser with SVG support, such as <a href="http://www.google.com/chrome">Chrome</a>, <a href="http://www.mozilla.org/en-US/firefox/">Firefox</a>, <a href="http://www.apple.com/safari/download/">Safari</a> or the latest <a href="http://windows.microsoft.com/en-US/internet-explorer/products/ie/home">Internet Explorer 9</a>. </p> | |
<img src="gal/ie.png" width="670" alt="Error"> | |
<div id="nytg-chartFrame" style="display:none;"> | |
<![endif]--> | |
<!--[if IE 8]> | |
<div id="nytg-error"> | |
<p>This interactive graphic requires a browser with SVG support, such as <a href="http://www.google.com/chrome">Chrome</a>, <a href="http://www.mozilla.org/en-US/firefox/">Firefox</a>, <a href="http://www.apple.com/safari/download/">Safari</a> or the latest <a href="http://windows.microsoft.com/en-US/internet-explorer/products/ie/home">Internet Explorer 9</a>. </p> | |
<img src="gal/ie.png" width="670" alt="Error"> | |
<div id="nytg-chartFrame" style="display:none;"> | |
<![endif]--> | |
<div id="top"></div> | |
<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 stages = | |
["Suspect", | |
"Initial Engagement", | |
"Qualified", | |
"Funding Sought", | |
"Business Incubator", | |
"Delivery", | |
"Completed", | |
"Rejected" | |
]; | |
var stages_agg = | |
[ | |
["Suspect",4], | |
["Initial Engagement",24], | |
["Qualified",2], | |
["Funding Sought",2], | |
["Business Incubator",3], | |
["Delivery",10], | |
["Completed",1], | |
["Rejected",3] | |
]; | |
var owners = | |
[ | |
"Tom Smith", | |
"Pete Smith", | |
"Nigel Smith", | |
"Andy Smith", | |
"Peter Smith", | |
"Unknown" | |
]; | |
var type = | |
[ | |
"Data Products", | |
"Data Provisioning", | |
"Platform", | |
"Data Advisory" | |
]; | |
var margin = {top:50,right:50,bottom:50,left:50}; | |
var r = 10; | |
var w = 1400; | |
var h = 800; | |
var width = w, | |
height = h, | |
padding = 20, // separation between nodes | |
maxRadius = 20; | |
var n = 200, // total number of nodes | |
m = 7; // number of columns | |
l = 4; //number of lanes | |
var color = d3.scale.category10() | |
.domain(d3.range(m)); | |
var color2 = d3.scale.ordinal() | |
.domain(d3.range(l)).range(["black","white"]); | |
//headers | |
var headers = d3.select('#top').selectAll(".headers").data(stages).enter().append("div").attr("class","headers"); | |
headers.html(function(d) {return d;}).style("background-color",function(d) {return color(d);}); | |
var dandata = | |
[ | |
{"project":"Tom Smith","type":"Data Products","status":"Delivery","pName":"Project1","cx":875,"cy":50,"radius":6}, | |
{"project":"Tom Smith","type":"Data Products","status":"Initial Engagement","pName":"D2C","cx":255,"cy":50,"radius":20}, | |
{"project":"Tom Smith","type":"Data Products","status":"Delivery","pName":"POL Channel","cx":875,"cy":50,"radius":9}, | |
{"project":"Pete Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":170,"radius":10}, | |
{"project":"Pete Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project2","cx":255,"cy":170,"radius":11}, | |
{"project":"Nigel Smith","type":"Data Products","status":"Suspect","pName":"Project3","cx":100,"cy":290,"radius":10}, | |
{"project":"Pete Smith","type":"Data Provisioning","status":"Suspect","pName":"Project4","cx":100,"cy":170,"radius":15}, | |
{"project":"Andy Smith","type":"Data Products","status":"Business Incubator","pName":"Project5","cx":720,"cy":410,"radius":12}, | |
{"project":"Tom Smith","type":"Data Provisioning","status":"Delivery","pName":"Project6","cx":875,"cy":50,"radius":20}, | |
{"project":"Unknown","type":"Platform","status":"Rejected","pName":"Project7","cx":1185,"cy":650,"radius":5}, | |
{"project":"Nigel Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project8","cx":255,"cy":290,"radius":7}, | |
{"project":"Tom Smith","type":"Data Provisioning","status":"Delivery","pName":"Project9","cx":875,"cy":50,"radius":9}, | |
{"project":"Nigel Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":10}, | |
{"project":"Nigel Smith","type":"Data Advisory","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":19}, | |
{"project":"Pete Smith","type":"Platform","status":"Initial Engagement","pName":"Project1","cx":255,"cy":170,"radius":15}, | |
{"project":"Nigel Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":5}, | |
{"project":"Nigel Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":11}, | |
{"project":"Nigel Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":5}, | |
{"project":"Peter Smith","type":"Data Products","status":"Completed","pName":"Project1","cx":1030,"cy":530,"radius":20}, | |
{"project":"Andy Smith","type":"Data Advisory","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":14}, | |
{"project":"Pete Smith","type":"Platform","status":"Initial Engagement","pName":"Project1","cx":255,"cy":170,"radius":9}, | |
{"project":"Tom Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":50,"radius":19}, | |
{"project":"Pete Smith","type":"Data Products","status":"Delivery","pName":"Project1","cx":875,"cy":170,"radius":10}, | |
{"project":"Unknown","type":"Platform","status":"Rejected","pName":"Project1","cx":1185,"cy":650,"radius":12}, | |
{"project":"Nigel Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":11}, | |
{"project":"Pete Smith","type":"Data Provisioning","status":"Suspect","pName":"Project1","cx":100,"cy":170,"radius":16}, | |
{"project":"Nigel Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":14}, | |
{"project":"Nigel Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":11}, | |
{"project":"Nigel Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":20}, | |
{"project":"Andy Smith","type":"Platform","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":6}, | |
{"project":"Pete Smith","type":"Platform","status":"Rejected","pName":"Project1","cx":1185,"cy":170,"radius":14}, | |
{"project":"Pete Smith","type":"Platform","status":"Delivery","pName":"Project1","cx":875,"cy":170,"radius":17}, | |
{"project":"Pete Smith","type":"Platform","status":"Delivery","pName":"Project1","cx":875,"cy":170,"radius":12}, | |
{"project":"Pete Smith","type":"Platform","status":"Delivery","pName":"Project1","cx":875,"cy":170,"radius":10}, | |
{"project":"Andy Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":20}, | |
{"project":"Andy Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":10}, | |
{"project":"Andy Smith","type":"Data Advisory","status":"Qualified","pName":"Project1","cx":410,"cy":410,"radius":5}, | |
{"project":"Andy Smith","type":"Data Products","status":"Delivery","pName":"Project1","cx":875,"cy":410,"radius":6}, | |
{"project":"Andy Smith","type":"Data Advisory","status":"Business Incubator","pName":"Project1e","cx":720,"cy":410,"radius":15}, | |
{"project":"Andy Smith","type":"Data Products","status":"Suspect","pName":"Project1","cx":100,"cy":410,"radius":9}, | |
{"project":"Andy Smith","type":"Data Products","status":"Funding Sought","pName":"Project1","cx":565,"cy":410,"radius":18}, | |
{"project":"Tom Smith","type":"Data Products","status":"Qualified","pName":"Project1","cx":410,"cy":50,"radius":18}, | |
{"project":"Andy Smith","type":"Data Advisory","status":"Business Incubator","pName":"Project1","cx":720,"cy":410,"radius":5}, | |
{"project":"Andy Smith","type":"Data Provisioning","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":6}, | |
{"project":"Andy Smith","type":"Data Products","status":"Funding Sought","pName":"Project1","cx":565,"cy":410,"radius":12}, | |
{"project":"Nigel Smith","type":"Data Products","status":"Delivery","pName":"Project1","cx":875,"cy":290,"radius":7}, | |
{"project":"Nigel Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":290,"radius":14}, | |
{"project":"Andy Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":8}, | |
{"project":"Andy Smith","type":"Data Products","status":"Initial Engagement","pName":"Project1","cx":255,"cy":410,"radius":12} | |
] | |
var xScale = d3.scale.ordinal().domain(stages) | |
.rangeBands([margin.left,width-margin.right]); | |
var yScale = d3.scale.ordinal().domain(type) | |
.rangeBands([70,height]); | |
var r = d3.scale.linear().domain([5,20]) | |
.range([6,35]); | |
dandata.forEach(function(d) { | |
d.cx = xScale(d.status); | |
d.cy = yScale(d.type); | |
d.roll = +1; | |
d.radius = r(d.radius); | |
}); | |
var force = d3.layout.force() | |
.nodes(dandata) | |
.size([width, height]) | |
.gravity(0) | |
.charge(-50) | |
.on("tick", tick) | |
.start(); | |
var svg = d3.select("body").append("svg") | |
.attr("width", width-margin.right-margin.left) | |
.attr("height", height-margin.top-margin.bottom+500); | |
//borders | |
var borders = svg.selectAll(".border").data(stages).enter().append("line").attr("x1",function(d,i) {return xScale(d)-30;}).attr("y1",30) | |
.attr("x2",function(d,i) {return xScale(d)-30;}).attr("y2",height+500).attr("class","border").attr("stroke", "#EDEDE3").attr("stroke-width", 2); | |
var totals = svg.selectAll(".totals").data(stages_agg).enter().append("text").text(function(d,i) {return d[1]}).attr("class","totals"); | |
totals.attr("x",function(d,i) {return xScale(d[0]);}).attr("y",30).style("fill", function(d) { return color(d[0]); }); | |
var lanes = svg.selectAll(".owners").data(type).enter().append("text").text(function(d,i) {return d}).attr("class","owners"); | |
lanes.attr("y",function(d,i) {return yScale(d) +100;}); | |
//Create tooltip element | |
var tooltip = d3.select("body") | |
.append("div") | |
.attr("class", "tooltip") | |
.style("position", "absolute") | |
.style("z-index", "10") | |
.style("opacity", 0); | |
var circle = svg.selectAll("circle") | |
.data(dandata) | |
.enter().append("circle") | |
.attr("r", function(d) { return d.radius*1.2; }) | |
.style("fill", function(d) { return color(d.status); }) | |
.style("opacity",0.95) | |
.style("stroke",function(d) { return color2(d.type); }) | |
.attr("project",function(d) {return d.project;}) | |
.attr("projectName",function(d) {return d.pName;}) | |
.attr("type",function(d) {return d.type;}) | |
.attr("status",function(d) {return d.status;}) | |
.style("stroke-width",5) | |
.attr("transform","translate(50,100)") | |
.on("mouseover",mouseover) | |
.on("mouseout",mouseout) | |
.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; | |
}); | |
}; | |
} | |
function mouseover() | |
{ | |
tooltip.html( //Populate tooltip text | |
"Owner: " + d3.select(this).attr("project") + "<br/>" + | |
"Project: " + d3.select(this).attr("projectName") + "<br/>" + | |
"Status: <a href='https://www.google.co.uk/#q=" + d3.select(this).attr("project") + "'>" + d3.select(this).attr("status") + "</a>" + "<br/>" + | |
"Category: " + d3.select(this).attr("type") | |
) | |
.transition() | |
.duration(750) | |
.style("opacity", 1) | |
.style("top", (event.pageY-10)+"px").style("left",(event.pageX+10)+"px"); | |
} | |
function mouseout() | |
{ | |
tooltip.transition() | |
.delay(2000) | |
.style("opacity", 0) //Make tooltip invisible | |
} | |
var total = d3.nest() | |
.key(function(d) { | |
return d.status; | |
}) | |
.rollup(function(d,i){ | |
return d3.sum(d, function(g) { | |
return +g.roll; | |
}); | |
}) | |
.entries(dandata); | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment