Skip to content

Instantly share code, notes, and snippets.

@josephmisiti
Created November 9, 2012 22:50
Show Gist options
  • Save josephmisiti/4048846 to your computer and use it in GitHub Desktop.
Save josephmisiti/4048846 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<meta charset="utf-8">
<div id='test-location'></div>
<script src="http://d3js.org/d3.v3.js"></script>
<style type="text/css">
.chart {
shape-rendering: crispEdges;
margin-left: 100px;
}
.mini text {
font: 9px sans-serif;
}
.main text {
font: 12px sans-serif;
}
.miniItem0 {
fill: darksalmon;
stroke-width: 6;
}
.miniItem1 {
fill: darkolivegreen;
fill-opacity: .2;
stroke-width: 6;
}
.miniItem2 {
fill: slategray;
fill-opacity: .2;
stroke-width: 6;
}
.brush .extent {
stroke: gray;
fill: dodgerblue;
fill-opacity: .2;
}
</style>
<body>
<script type="text/javascript">
//data
var lanes = ["New Application","Reviewing Application","Invite For Phone Interview","Phone Interview","Invite For In Person Interview","In Person Interview","Final Decision","Offer",],
laneLength = lanes.length,
// items = [{"lane": 0, "id": "New Application", "start": 5, "end": 205},
// {"lane": 0, "id": "Reviewing Application", "start": 265, "end": 420},
// {"lane": 0, "id": "Invite For Phone Interview", "start": 580, "end": 615},
// {"lane": 0, "id": "Phone Interview", "start": 620, "end": 900},
// {"lane": 0, "id": "Invite For In Person Interview", "start": 960, "end": 1265},
// {"lane": 0, "id": "In Person Interview", "start": 1270, "end": 1365},
// {"lane": 0, "id": "Final Decision", "start": 1370, "end": 1640},
// {"lane": 0, "id": "Offer", "start": 1645, "end": 1910},
// {"lane": 1, "id": "New Application", "start": 150, "end": 305},
// {"lane": 1, "id": "Reviewing Application", "start": 265, "end": 540},
// {"lane": 1, "id": "Invite For Phone Interview", "start": 580, "end": 615},
// {"lane": 1, "id": "Phone Interview", "start": 620, "end": 900},
// {"lane": 1, "id": "Invite For In Person Interview", "start": 960, "end": 1265},
// {"lane": 1, "id": "In Person Interview", "start": 1270, "end": 1365},
// {"lane": 1, "id": "Final Decision", "start": 1370, "end": 1640},
// {"lane": 1, "id": "Offer", "start": 1645, "end": 1910},
// {"lane": 2, "id": "New Application", "start": 5, "end": 205},
// {"lane": 2, "id": "Reviewing Application", "start": 265, "end": 420},
// {"lane": 2, "id": "Invite For Phone Interview", "start": 580, "end": 615},
// {"lane": 2, "id": "Phone Interview", "start": 620, "end": 900},
// {"lane": 2, "id": "Invite For In Person Interview", "start": 960, "end": 1265},
// {"lane": 2, "id": "In Person Interview", "start": 1270, "end": 1365},
// {"lane": 2, "id": "Final Decision", "start": 1370, "end": 1640},
// {"lane": 2, "id": "Offer", "start": 1645, "end": 1910},
// ]
items = [{"lane": 0, "id": "New Application", "start": 5, "end": 205},
{"lane": 1, "id": "Reviewing Application", "start": 265, "end": 420},
{"lane": 2, "id": "Invite For Phone Interview", "start": 580, "end": 615},
{"lane": 3, "id": "Phone Interview", "start": 620, "end": 900},
{"lane": 4, "id": "Invite For In Person Interview", "start": 960, "end": 1265},
{"lane": 5, "id": "In Person Interview", "start": 1270, "end": 1365},
{"lane": 6, "id": "Final Decision", "start": 1370, "end": 1640},
{"lane": 7, "id": "Offer", "start": 1645, "end": 1910},
]
timeBegin = 0,
timeEnd = 2000;
</script>
<script type="text/javascript">
function colors(){
return ['#71c857', '#4ca233', '#51c199', '#51c175', '#85db02', '#7d886c', '#8df26f', '#454a44' ];
}
var m = [20, 20, 15, 120], //top right bottom left
w = 960 - m[1] - m[3],
h = 500 - m[0] - m[2],
miniHeight = laneLength * 12 + 50,
mainHeight = h - miniHeight - 50;
//scales
var x = d3.scale.linear()
.domain([timeBegin, timeEnd])
.range([0, w]);
var x1 = d3.scale.linear()
.range([0, w]);
var y1 = d3.scale.linear()
.domain([0, laneLength])
.range([0, mainHeight]);
var y2 = d3.scale.linear()
.domain([0, laneLength])
.range([0, miniHeight]);
var chart = d3.select("body")
.append("svg")
.attr("width", w + m[1] + m[3])
.attr("height", h + m[0] + m[2])
.attr("class", "chart");
chart.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", w)
.attr("height", mainHeight);
var main = chart.append("g")
.attr("transform", "translate(" + 200 + "," + m[0] + ")")
.attr("width", w)
.attr("height", mainHeight)
.attr("class", "main");
var mini = chart.append("g")
.attr("transform", "translate(" + 200 + "," + (mainHeight + m[0]) + ")")
.attr("width", w)
.attr("height", miniHeight)
.attr("class", "mini");
//main lanes and texts
main.append("g").selectAll(".laneLines")
.data(items)
.enter().append("line")
.attr("x1", m[1])
.attr("y1", function(d) {return y1(d.lane);})
.attr("x2", w)
.attr("y2", function(d) {return y1(d.lane);})
.attr("stroke", "lightgray")
main.append("g").selectAll(".laneText")
.data(lanes)
.enter().append("text")
.text(function(d) {return d;})
.attr("x", -m[1])
.attr("y", function(d, i) {return y1(i + .5);})
.attr("dy", ".5ex")
.attr("text-anchor", "end")
.attr("class", "laneText");
//mini lanes and texts
mini.append("g").selectAll(".laneLines")
.data(items)
.enter().append("line")
.attr("x1", m[1])
.attr("y1", function(d) {return y2(d.lane);})
.attr("x2", w)
.attr("y2", function(d) {return y2(d.lane);})
.attr("stroke", "lightgray");
mini.append("g").selectAll(".laneText")
.data(lanes)
.enter().append("text")
.text(function(d) {return d;})
.attr("x", -m[1])
.attr("y", function(d, i) {return y2(i + .5);})
.attr("dy", ".5ex")
.attr("text-anchor", "end")
.attr("class", "laneText");
var itemRects = main.append("g")
.attr("clip-path", "url(#clip)");
//mini item rects
mini.append("g").selectAll("miniItems")
.data(items)
.enter().append("rect")
.attr("x", function(d) {return x(d.start);})
.attr("y", function(d) {return y2(d.lane + .5) - 5;})
.attr("width", function(d) {return x(d.end - d.start);})
.attr("height", 10)
.attr('fill', function(d,i) { var c = colors(); return c[i];})
//mini labels
mini.append("g").selectAll(".miniLabels")
.data(items)
.enter().append("text")
.text(function(d) {return d.id;})
.attr("x", function(d) {return x(d.start);})
.attr("y", function(d) {return y2(d.lane + .5);})
.attr("dy", ".5ex");
//brush
var brush = d3.svg.brush()
.x(x)
.on("brush", display);
mini.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", 1)
.attr("height", miniHeight - 1);
display();
function display() {
var rects, labels,
minExtent = brush.extent()[0],
maxExtent = brush.extent()[1],
visItems = items.filter(function(d) {return d.start < maxExtent && d.end > minExtent;});
mini.select(".brush")
.call(brush.extent([minExtent, maxExtent]));
x1.domain([minExtent, maxExtent]);
//update main item rects
rects = itemRects.selectAll("rect")
.data(visItems, function(d) { return d.id; })
.attr("x", function(d) {return x1(d.start);})
.attr("width", function(d) {return x1(d.end) - x1(d.start);});
rects.enter().append("rect")
.attr('fill', function(d,i) { var c = colors(); return c[i];})
.attr("x", function(d) {return x1(d.start);})
.attr("y", function(d) {return y1(d.lane) + 10;})
.attr("width", function(d) {return x1(d.end) - x1(d.start);})
.attr("height", function(d) {return .8 * y1(1);});
rects.exit().remove();
//update the item labels
labels = itemRects.selectAll("text")
.data(visItems, function (d) { return d.id; })
.attr("x", function(d) {return x1(Math.max(d.start, minExtent) + 2);});
labels.enter().append("text")
.text(function(d) {return d.id;})
.attr("x", function(d) {return x1(Math.max(d.start, minExtent));})
.attr("y", function(d) {return y1(d.lane + .5);})
.attr("text-anchor", "start");
labels.exit().remove();
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment