dc
Version:
A multi-dimensional charting library built to work natively with crossfilter and rendered using d3.js
140 lines (126 loc) • 5.05 kB
HTML
<html lang="en">
<head>
<title>dc.js - Time Intervals Example</title>
<meta charset="UTF-8">
<link rel="stylesheet" type="text/css" href="../css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="../css/dc.css"/>
</head>
<body>
<div class="container">
<script type="text/javascript" src="header.js"></script>
<p>This demonstrates using an <a href="https://en.wikipedia.org/wiki/Interval_tree">interval
tree</a> to plot items which span from a begin date to an end date. The brush will intersect with
any items whose intervals overlap with it.</p>
<div id="month">
<div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
<a href="javascript:monthChart.filterAll().redrawGroup();">reset</a>
</div>
</div>
<div id="cost">
<div class="reset" style="visibility: hidden;">selected: <span class="filter"></span>
<a href="javascript:costChart.filterAll().redrawGroup();">reset</a>
</div>
</div>
<script type="text/javascript" src="../js/d3.js"></script>
<script type="text/javascript" src="../js/crossfilter.js"></script>
<script type="text/javascript" src="../js/dc.js"></script>
<script type="text/javascript" src="lysenko-interval-tree.js"></script>
<script type="text/javascript">
function intervalTreeGroup(tree, firstDate, lastDate) {
return {
all: function() {
var begin = d3.time.month(firstDate), end = d3.time.month(lastDate);
var i = new Date(begin);
var ret = [], count;
do {
next = new Date(i);
next.setMonth(next.getMonth()+1);
count = 0;
tree.queryInterval(i.getTime(), next.getTime(), function() {
++count;
});
ret.push({key: i, value: count});
i = next;
}
while(i.getTime() <= end.getTime());
return ret;
}
};
}
var timeFormat = d3.time.format('%x');
var monthChart = dc.barChart("#month");
var costChart = dc.barChart("#cost");
// data from http://stackoverflow.com/questions/22603788/crossfilter-how-to-extract-time-information-from-start-date-and-end-date-column
d3.csv("intervals.csv", function(error, projects) {
projects.forEach(function(x) {
x['Start Date'] = timeFormat.parse(x['Start Date']);
x['End Date'] = timeFormat.parse(x['End Date']);
// the library uses object identity so we have to cache the interval arrays
x.interval = [x['Start Date'].getTime(), x['End Date'].getTime()];
x.Cost = +x.Cost;
});
// the interval tree library doesn't seem to provide start/end info
var firstDate = d3.min(projects, function(x) { return x['Start Date']; }),
lastDate = d3.max(projects, function(x) { return x['End Date']; });
var ndx = crossfilter(projects),
intervalDimension = ndx.dimension(function(d) {return d.interval;}),
projectsPerMonthTree = ndx.groupAll().reduce(
function(v, d) {
v.insert(d.interval);
return v;
},
function(v, d) {
v.remove(d.interval);
return v;
},
function() {
return lysenkoIntervalTree(null);
}
),
projectsPerMonthGroup = intervalTreeGroup(projectsPerMonthTree.value(), firstDate, lastDate),
projectCostDimension = ndx.dimension(function(d) { return d.Cost; }),
projectCostGroup = projectCostDimension.group();
monthChart
.width(400)
.height(300)
.x(d3.time.scale())
.y(d3.scale.linear().domain([0,25]))
.xUnits(d3.time.months)
.gap(5)
.elasticX(true)
.brushOn(true)
.yAxisLabel("Number of Projects")
.xAxisLabel("Month")
.dimension(intervalDimension)
.group(projectsPerMonthGroup)
.controlsUseVisibility(true);
monthChart.filterHandler(function(dim, filters) {
if(filters && filters.length) {
if(filters.length !== 1)
throw new Error('not expecting more than one range filter');
var range = filters[0];
dim.filterFunction(function(i) {
return !(i[1] < range[0].getTime() || i[0] > range[1].getTime());
})
}
else dim.filterAll();
return filters;
});
costChart
.width(400)
.height(300)
.x(d3.scale.linear().domain([0,24]))
.y(d3.scale.linear().domain([0,25]))
.brushOn(true)
.yAxisLabel("Number of Projects")
.xAxisLabel("Cost")
.dimension(projectCostDimension)
.group(projectCostGroup)
.controlsUseVisibility(true);
dc.renderAll();
});
</script>
</div>
</body>
</html>