block by emeeks d24171dac80dd535521b

Simple d3.layout.timeline

Full 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.

index.html

<html xmlns="//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>

d3.layout.timeline.js

(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;
}
})();

int_bands.csv

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