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/3505bdf5a161c398bab3 to your computer and use it in GitHub Desktop.
Save danharr/3505bdf5a161c398bab3 to your computer and use it in GitHub Desktop.
Project Force Diagrams
<!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