xxxxxxxxxx
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>Kanban Treemap</title>
<script src="https://d3js.org/d3.v2.js"></script>
<script src=" https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<link href='https://fonts.googleapis.com/css?family=Tienne' rel='stylesheet' type='text/css'>
<style>
body { text-align: center; margin: auto; }
p.source { font-style: italic; }
a { color: blue; }
svg {
display: block;
margin: auto;
}
rect {
fill: none;
stroke: #fff;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
sup, sub {
line-height: 0;
}
q:before,
blockquote:before {
content: "“";
}
q:after,
blockquote:after {
content: "―";
}
blockquote:before {
position: absolute;
left: 2em;
}
blockquote:after {
position: absolute;
}
.bucket {
width: 300px;
height: 500px;
float:left;
}
#bucket1, #bucket2, #bucket3 {
width: 240px;
height: 500px;
margin: 30px;
background: #bbb;
}
text {
pointer-events: none;
}
.grandparent text {
font-weight: bold;
}
rect {
fill: none;
stroke: #fff;
}
rect.parent,
.grandparent rect {
stroke-width: 2px;
}
.grandparent rect {
fill: #fff;
}
.children rect.parent,
.grandparent rect {
cursor: pointer;
}
rect.parent {
pointer-events: all;
}
.children:hover rect.child,
.grandparent:hover rect {
fill: #aaa;
}
</style>
<script>
$(document).ready(function() {
$(":button").click(function() {
alert("Handler for .click() called.");
});
});
</script>
<h1>Phoebe's Kanban Treemap</h1>
<div class="bucket"><h3>Not Started</h3><div id="bucket1"></div></div>
<div class="bucket"><h3>In Progress</h3><div id="bucket2"></div></div>
<div class="bucket"><h3>Complete</h3><div id="bucket3"></div></div>
<div id="filter">
Filter for <span id="who_filter"></span>
Check to Highlight <span id="who_high"></span>
</div>
<script type="text/javascript">
var w = 240,
h = 500,
color = d3.scale.category20c(),
root,
node,
master,
data,
bucket1_data,
bucket2_data,
bucket3_data,
totals,
total_time;
var treemap1 = d3.layout.treemap()
.children(function(d) { return d.values; })
.value(function(d) { return d.time; });
var treemap2 = d3.layout.treemap()
.children(function(d) { return d.values; })
.value(function(d) { return d.time; });
var treemap3 = d3.layout.treemap()
.children(function(d) { return d.values; })
.value(function(d) { return d.time; });
var svg_b1 = d3.select("#bucket1")
.attr("width", w + "px")
.attr("height", h + "px")
.append("svg:svg")
.append("svg:g");
var svg_b2 = d3.select("#bucket2")
.attr("width", w + "px")
.attr("height", h + "px")
.append("svg:svg")
.append("svg:g");
var svg_b3 = d3.select("#bucket3")
.attr("width", w + "px")
.attr("height", h + "px")
.append("svg:svg")
.append("svg:g");
//load csv and copy to global variable
d3.csv("./data_project.csv",function(csv) {
master=data=csv;
init(master);
});
d3.select("#filter").on("change", redraw);
function init(){
var nested_data = d3.nest()
.key(function(d) { return d.who}).sortKeys(d3.ascending)
.rollup(function(leaves) { return leaves.length; })
.entries(master);
// select list for filtering
var list = d3.select("#who_filter").append("select")
.attr("class", "filter")
.attr("id", "who_select");
list.selectAll("option")
.data(nested_data)
.enter()
.append("option")
.attr("value", function(d) {return d.key;})
.text(function(d) {
return d.key; });
// Buttons to highlight
var checks = d3.select("#who_high")
.data(nested_data)
.enter().append("button")
.attr("value", function(d) {return d.key;})
.text(function(d) {
return d.key; });
datanest();
datadraw();
}
function redraw(master){
filter();
//fonfilter();
//fonfilter2(); etc etc etc
//nestswitcher..... use switch to choose appropriate nest.
//visswitcher..... use switch to choose appropriate vis. maybe here https://stackoverflow.com/questions/6643015/switch-and-select-in-javascript
datanest();
datadraw();
}
function filter () {
var who = $("#who_select").val();
data = master.filter(function(d) { return d.who == who;});
return data;
}
function datanest () {
node = root = {values: d3.nest()
.key(function(d) { return d.status; })
.entries(data)};
bucket1_data = root.values[0];
bucket2_data = root.values[1];
bucket3_data = root.values[2];
// calculate total size per bucket and overall
totals = d3.nest()
.key(function(d) { return d.status; })
.rollup(function(leaves) {
return d3.sum(leaves, function(d) {return d.time;} );})
.map(data);
total_time = totals["Complete"] + totals["In Progress"] + totals["Not Started"];
}
function datadraw() {
// calculate percentage of total for each bucket
var pct_b1 = Math.round(h * totals["Not Started"] / total_time),
pct_b2 = Math.round(h * totals["In Progress"] / total_time),
pct_b3 = Math.round(h * totals["Complete"] / total_time);
// resize treemps to they reflect the correct proportion of the overall time
treemap1.size([w, pct_b1]);
treemap2.size([w, pct_b2]);
treemap3.size([w, pct_b3]);
// filter gets the leaves
celldraw(svg_b1.selectAll(".cell")
.data(treemap1.nodes(bucket1_data).filter(function(d) { return !d.values; }) ));
celldraw(svg_b2.selectAll(".cell")
.data(treemap2.nodes(bucket2_data).filter(function(d) { return !d.values; }) ));
celldraw(svg_b3.selectAll(".cell")
.data(treemap3.nodes(bucket3_data).filter(function(d) { return !d.values; }) ));
svg_b1.attr("transform", "translate(0,"+(h-pct_b1)+")");
svg_b2.attr("transform", "translate(0,"+(h-pct_b2)+")");
svg_b3.attr("transform", "translate(0,"+(h-pct_b3)+")");
}
function celldraw(cell) {
// enter new elements
var cellEnter = cell.enter().append("g")
.attr("class", "cell")
// .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
cellEnter.append("rect")
cellEnter.append("text")
// update remaining elements
cell.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
cell.select("rect")
.attr("width", function(d) { return d.dx - 1; })
.attr("height", function(d) { return d.dy - 1; })
.attr("class", function(d) { return "cell "+ d.who; })
.style("fill", function(d) { return color(d.parent.key); })
cell.select("text")
.attr("x", function(d) { return d.dx / 2; })
.attr("y", function(d) { return d.dy / 2; })
.attr("dy", ".35em")
.attr("text-anchor", "middle")
.text(function(d) { return d.id; })
.style("opacity", function(d) { d.w = this.getComputedTextLength(); return d.dx > d.w ? 1 : 0; })
// remove old elements
cell.exit().remove()
}
</script>
</body>
</html>
Modified http://d3js.org/d3.v2.js to a secure url
https://d3js.org/d3.v2.js
https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js