A very simple example of d3.layout.timeline that takes a csv like this:
s,e
1,7
1,6
10,15
7,8
4,5
5,6
And places it into a few lanes to be drawn on-screen.
A very simple example of d3.layout.timeline that takes a csv like this:
s,e
1,7
1,6
10,15
7,8
4,5
5,6
And places it into a few lanes to be drawn on-screen.
(function() { | |
d3.layout.timeline = function() { | |
var timelines = []; | |
var dateAccessor = function (d) {return new Date(d)}; | |
var processedTimelines = []; | |
var startAccessor = function (d) {return d.start}; | |
var endAccessor = function (d) {return d.end}; | |
var size = [500,100]; | |
var timelineExtent = [-Infinity, Infinity]; | |
var setExtent = []; | |
var displayScale = d3.scale.linear(); | |
var swimlanes = []; | |
var padding = 0; | |
var fixedExtent = false; | |
var maximumHeight = Infinity; | |
function processTimelines() { | |
timelines.forEach(function (band) { | |
var projectedBand = {}; | |
for (var x in band) { | |
if (band.hasOwnProperty(x)) { | |
projectedBand[x] = band[x]; | |
} | |
} | |
projectedBand.start = dateAccessor(startAccessor(band)); | |
projectedBand.end = dateAccessor(endAccessor(band)); | |
projectedBand.lane = 0; | |
processedTimelines.push(projectedBand); | |
}); | |
} | |
function projectTimelines() { | |
if (fixedExtent === false) { | |
var minStart = d3.min(processedTimelines, function (d) {return d.start}); | |
var maxEnd = d3.max(processedTimelines, function (d) {return d.end}); | |
timelineExtent = [minStart,maxEnd]; | |
} | |
else { | |
timelineExtent = [dateAccessor(setExtent[0]), dateAccessor(setExtent[1])]; | |
} | |
displayScale.domain(timelineExtent).range([0,size[0]]); | |
processedTimelines.forEach(function (band) { | |
band.originalStart = band.start; | |
band.originalEnd = band.end; | |
band.start = displayScale(band.start); | |
band.end = displayScale(band.end); | |
}); | |
} | |
function fitsIn(lane, band) { | |
if (lane.end < band.start || lane.start > band.end) { | |
return true; | |
} | |
var filteredLane = lane.filter(function (d) {return d.start <= band.end && d.end >= band.start}); | |
if (filteredLane.length === 0) { | |
return true; | |
} | |
return false; | |
} | |
function findlane(band) { | |
//make the first array | |
if (swimlanes[0] === undefined) { | |
swimlanes[0] = [band]; | |
return; | |
} | |
var l = swimlanes.length - 1; | |
var x = 0; | |
while (x <= l) { | |
if (fitsIn(swimlanes[x], band)) { | |
swimlanes[x].push(band); | |
return; | |
} | |
x++; | |
} | |
swimlanes[x] = [band]; | |
return; | |
} | |
function timeline(data) { | |
if (!arguments.length) return timeline; | |
timelines = data; | |
processedTimelines = []; | |
swimlanes = []; | |
processTimelines(); | |
projectTimelines(); | |
processedTimelines.forEach(function (band) { | |
findlane(band); | |
}); | |
var height = size[1] / swimlanes.length; | |
height = Math.min(height, maximumHeight); | |
swimlanes.forEach(function (lane, i) { | |
lane.forEach(function (band) { | |
band.y = i * (height); | |
band.dy = height - padding; | |
band.lane = i; | |
}); | |
}); | |
return processedTimelines; | |
} | |
timeline.dateFormat = function (_x) { | |
if (!arguments.length) return dateAccessor; | |
dateAccessor = _x; | |
return timeline; | |
} | |
timeline.bandStart = function (_x) { | |
if (!arguments.length) return startAccessor; | |
startAccessor = _x; | |
return timeline; | |
} | |
timeline.bandEnd = function (_x) { | |
if (!arguments.length) return endAccessor; | |
endAccessor = _x; | |
return timeline; | |
} | |
timeline.size = function (_x) { | |
if (!arguments.length) return size; | |
size = _x; | |
return timeline; | |
} | |
timeline.padding = function (_x) { | |
if (!arguments.length) return padding; | |
padding = _x; | |
return timeline; | |
} | |
timeline.extent = function (_x) { | |
if (!arguments.length) return timelineExtent; | |
fixedExtent = true; | |
setExtent = _x; | |
if (_x.length === 0) { | |
fixedExtent = false; | |
} | |
return timeline; | |
} | |
timeline.maxBandHeight = function (_x) { | |
if (!arguments.length) return maximumHeight; | |
maximumHeight = _x; | |
return timeline; | |
} | |
return timeline; | |
} | |
})(); |
<html xmlns="http://www.w3.org/1999/xhtml"> | |
<head> | |
<title>Timeline with Integers</title> | |
<meta charset="utf-8" /> | |
<style type="text/css"> | |
svg { | |
height: 1100px; | |
width: 1100px; | |
} | |
div.viz { | |
height: 1000px; | |
width: 1000px; | |
} | |
</style> | |
</head> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js" charset="utf-8" type="text/javascript"></script> | |
<script src="d3.layout.timeline.js" charset="utf-8" type="text/javascript"></script> | |
<script> | |
var timeline = d3.layout.timeline() | |
.size([1000,300]) | |
.bandStart(function (d) {return d.s}) | |
.bandEnd(function (d) {return d.e}) | |
.dateFormat(function (d) {return parseInt(d)}) | |
d3.csv("int_bands.csv", function (csv) { | |
timelineBands = timeline(csv); | |
d3.select("svg").selectAll("rect") | |
.data(timelineBands) | |
.enter() | |
.append("rect") | |
.attr("x", function (d) {return d.start}) | |
.attr("y", function (d) {return d.y}) | |
.attr("height", function (d) {return d.dy}) | |
.attr("width", function (d) {return d.end - d.start}) | |
.style("fill", "#687a97") | |
.style("stroke", "black") | |
}) | |
</script> | |
<body> | |
<div id="viz"> | |
<svg style="background:white;" height=1100 width=1100> | |
</svg> | |
</div> | |
<footer> | |
</footer> | |
</body> | |
</html> |
s | e | |
---|---|---|
1 | 7 | |
1 | 6 | |
10 | 15 | |
7 | 8 | |
4 | 5 | |
5 | 6 | |
8 | 9 | |
3 | 10 | |
10 | 15 | |
4 | 8 | |
10 | 12 | |
3 | 8 | |
5 | 12 | |
4 | 12 |