UNPKG

dc

Version:

A multi-dimensional charting library built to work natively with crossfilter and rendered using d3.js

182 lines (167 loc) 6.95 kB
<!DOCTYPE html> <html lang="en"> <head> <title>dc.js - Switching Time Intervals</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"/> <style> dl { margin-left: 2em; } </style> </head> <body> <div class="container"> <script type="text/javascript" src="header.js"></script> <p>This example demonstrates switching between different intervals of aggregation over time.</p> <select id="interval"></select> <span style="font-size: large" id="counter"></span><span id="counter-text" style="display: none"> selected.</span> <br> <div id="test" style="min-height: 500px"></div> <div style="clear: both"> <p>You can supply your own data source with query string parameters: <dl> <dt>data</dt><dd>URL to load</dd> <dt>aggregate</dt><dd>Aggregation method: <code>average</code> or <code>total</code> <dt>date</dt><dd>Date column name</dd> <dt>val</dt><dd>Value column name</dd> </dl> </p> </div> <script type="text/javascript" src="../js/promise-polyfill.js"></script> <script type="text/javascript" src="../js/fetch.umd.js"></script> <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"> var find_query = function() { var _map = window.location.search.substr(1).split('&').map(function(a) { return a.split('='); }).reduce(function(p, v) { if(v.length > 1) p[v[0]] = decodeURIComponent(v[1].replace(/\+/g, " ")); else p[v[0]] = true; return p; }, {}); return function(field) { return _map[field] || null; }; }(); var data = find_query('data') || 'monthly-move.csv', date_col = find_query('date') || 'date', val_col = find_query('val') || 'volume', aggregate = find_query('aggregate') || 'average'; var chart = dc.barChart("#test"), counter = dc.numberDisplay('#counter'); d3.csv(data).then(function(posts) { posts.forEach(function(d) { d[date_col] = new Date(d[date_col]); d[val_col] = +d[val_col]; }); var ndx = crossfilter(posts), dateDim = ndx.dimension(function(d) { return d[date_col]; }), postsGroup; var intervals = { Days: d3.timeDay, Weeks: d3.timeWeek, Months: d3.timeMonth, Years: d3.timeYear }; var defint = find_query('interval') || 'Weeks'; d3.select('#interval').selectAll('option') .data(Object.keys(intervals)) .enter().append('option') .text(function(d) { return d; }) .attr('selected', function(d) { return d === defint ? '' : null; }); function setup() { var start_t = window.performance.now(); if(postsGroup) postsGroup.dispose(); var interval_name = d3.select('#interval').nodes()[0].value; var interval = intervals[interval_name]; chart.xUnits(interval.range); postsGroup = dateDim .group(function(k) { return interval(k); }) .reduce( function(p, v) { ++p.count; p.total += v[val_col]; return p; }, function(p, v) { --p.count; p.total -= v[val_col]; return p; }, function() { return { count: 0, total: 0 }; } ); switch(aggregate) { case 'average': chart.valueAccessor(function(kv) { return kv.value.total / kv.value.count; }); break; case 'total': default: chart.valueAccessor(function(kv) { return kv.value.total; }); } chart.dimension(dateDim).group(postsGroup) .transitionDuration(!find_query('unsafe') && postsGroup.all().length > 2000 ? 0 : 1000) .render(); console.log(['setup for', interval_name, 'took', window.performance.now() - start_t, 'ms'].join(' ')); } chart .width(768) .height(480) .x(d3.scaleTime()) .xUnits(d3.timeWeeks) .margins({left: 50, top: 0, right: 0, bottom: 20}) .elasticY(true) .clipPadding(10); chart.yAxis().tickFormat(d3.format('.3s')); // this demonstrates solving elasticX manually, avoiding the // bug where the rightmost bar/box is not displayed, #792 function calc_domain(chart) { var min = d3.min(chart.group().all(), function(kv) { return kv.key; }), max = d3.max(chart.group().all(), function(kv) { return kv.key; }); max = d3.timeMonth.offset(max, 1); chart.x().domain([min, max]); } chart.on('preRender', calc_domain); chart.on('preRedraw', calc_domain); var countAll = ndx.groupAll(), groupAll = ndx.groupAll().reduceSum(function(d) { return d[val_col]; }); counter .dimension({}) .group(groupAll); switch(aggregate) { case 'average': counter.valueAccessor(function(x) { return x / countAll.value(); }); break; case 'total': default: counter.valueAccessor(function(x) { return x; }); } d3.select('#interval').on('change', function() { setup(); }); counter.on('postRender', function () { d3.select('#counter-text').style('display', 'inline'); }); setup(); dc.renderAll(); }); </script> </div> </body> </html>