block by renecnielsen 9753502

Swimlane

Full Screen

index.html

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
		<title>Swimlane Chart</title>
		<script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
		<link rel="stylesheet" href="style.css" type="text/css">
		<link href='//fonts.googleapis.com/css?family=Open+Sans:300' rel='stylesheet' type='text/css'>
	</head>
	<body>
		<script type="text/javascript">
		//data
		var lanes = ["Phase I","Phase II","Phase III","Phase IV","Phase V","Phase VI"],
			laneLength = lanes.length,
			items = [{"lane": 0, "id": "Item 1", "start": 5, "end": 205},
					{"lane": 0, "id": "Item 2", "start": 265, "end": 420},
					{"lane": 0, "id": "Item 3", "start": 580, "end": 615},
					{"lane": 0, "id": "Item 4", "start": 620, "end": 900},
					{"lane": 0, "id": "Item 5", "start": 960, "end": 1265},
					{"lane": 0, "id": "Item 6", "start": 1270, "end": 1365},
					{"lane": 0, "id": "Item 7", "start": 1370, "end": 1640},
					{"lane": 0, "id": "Item 8", "start": 1645, "end": 1910},
					{"lane": 1, "id": "Item 9", "start": 300, "end": 530},
					{"lane": 1, "id": "Item 10", "start": 550, "end": 700},
					{"lane": 1, "id": "Item 11", "start": 710, "end": 790},
					{"lane": 1, "id": "Item 12", "start": 800, "end": 1180},
					{"lane": 1, "id": "Item 13", "start": 1190, "end": 1330},
					{"lane": 1, "id": "Item 14", "start": 1340, "end": 1560},
					{"lane": 1, "id": "Item 15", "start": 1610, "end": 1860},
					{"lane": 1, "id": "Item 16", "start": 1870, "end": 1900},
					{"lane": 1, "id": "Item 17", "start": 1910, "end": 1920},
					{"lane": 1, "id": "Item 18", "start": 1925, "end": 1985},
					{"lane": 1, "id": "Item 19", "start": 1990, "end": 1995},
					{"lane": 2, "id": "Item 20", "start": 10, "end": 670},
					{"lane": 2, "id": "Item 21", "start": 690, "end": 900},
					{"lane": 2, "id": "Item 22", "start": 920, "end": 1380},
					{"lane": 2, "id": "Item 23", "start": 1390, "end": 1890},
					{"lane": 2, "id": "Item 24", "start": 1900, "end": 1945},
					{"lane": 3, "id": "Item 25", "start": 5, "end": 205},
					{"lane": 3, "id": "Item 26", "start": 265, "end": 420},
					{"lane": 3, "id": "Item 27", "start": 580, "end": 615},
					{"lane": 3, "id": "Item 28", "start": 620, "end": 900},
					{"lane": 3, "id": "Item 29", "start": 960, "end": 1265},
					{"lane": 3, "id": "Item 30", "start": 1270, "end": 1365},
					{"lane": 3, "id": "Item 31", "start": 1370, "end": 1640},
					{"lane": 3, "id": "Item 32", "start": 1645, "end": 1910},
					{"lane": 4, "id": "Item 33", "start": 300, "end": 530},
					{"lane": 4, "id": "Item 34", "start": 550, "end": 700},
					{"lane": 4, "id": "Item 35", "start": 710, "end": 790},
					{"lane": 4, "id": "Item 36", "start": 800, "end": 1180},
					{"lane": 4, "id": "Item 37", "start": 1190, "end": 1330},
					{"lane": 4, "id": "Item 38", "start": 1340, "end": 1560},
					{"lane": 4, "id": "Item 39", "start": 1610, "end": 1860},
					{"lane": 4, "id": "Item 40", "start": 1870, "end": 1900},
					{"lane": 4, "id": "Item 41", "start": 1910, "end": 1920},
					{"lane": 4, "id": "Item 42", "start": 1925, "end": 1985},
					{"lane": 4, "id": "Item 43", "start": 1990, "end": 1995},
					{"lane": 5, "id": "Item 44", "start": 10, "end": 670},
					{"lane": 5, "id": "Item 45", "start": 690, "end": 900},
					{"lane": 5, "id": "Item 46", "start": 920, "end": 1380},
					{"lane": 5, "id": "Item 47", "start": 1390, "end": 1890},
					{"lane": 5, "id": "Item 48", "start": 1900, "end": 1945}]
			timeBegin = 0,
			timeEnd = 2000;
		</script>
		<script type="text/javascript">
		var m = [20, 15, 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(" + m[3] + "," + m[0] + ")")
					.attr("width", w)
					.attr("height", mainHeight)
					.attr("class", "main");

		var mini = chart.append("g")
					.attr("transform", "translate(" + m[3] + "," + (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", "#96999b") //Uncomment to insert lines between lanes
			;

		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", "#96999b")  //Uncomment to insert lines between lanes
			;

		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("class", function(d) {return "miniItem" + d.lane;})
			.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);

		//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("class", function(d) {return "miniItem" + d.lane;})
				.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>
</html>

style.css

.chart {
  shape-rendering: crispEdges;
}

.mini text {
  font: 9px 'Open Sans';
}

.main text {
  font: 12px 'Open Sans';
}

.miniItem0 {
  fill: #00aeef;
  fill-opacity: .7;
  stroke-width: 6;
}

.miniItem1 {
  fill: #e1f4fd;
  stroke-width: 6;
}

.miniItem2 {
  fill: #96999b;
  fill-opacity: .7;
  stroke-width: 6;
}

.miniItem3 {
  fill: #00447c;
  fill-opacity: .6;
  stroke-width: 6;
}

.miniItem4 {
  fill: #cf5c42;
  fill-opacity: .7;
  stroke-width: 6;
}

.miniItem5 {
  fill: #e1d8ad;
  stroke-width: 6;
}

.brush .extent {
  stroke: #e1f4fd;
  fill: #e1f4fd;
  fill-opacity: .65;
}