JSFiddle - React, Tailwind, and code Playground

by Gordon Woodhull

HTML

<script src="https://unpkg.com/d3@5/dist/d3.js"></script>
<script src="https://unpkg.com/crossfilter2@1.4/crossfilter.js"></script>
<link rel="stylesheet" href="https://unpkg.com/dc@3/dc.css">
<script src="https://unpkg.com/dc@3/dc.js"></script>
<script src="https://rawgit.com/crossfilter/reductio/master/reductio.js"></script>
<script src="https://npmcdn.com/universe@latest/universe.js"></script>
<h3>Input</h3>
<pre id="input"></pre>
<h3>Output</h3>
<pre id="output"></pre>

JavaScript

var data = [{datetime: "2018-05-01 09:10:00", event: 1},
{datetime: "2018-05-01 11:30:00", event: 1},
{datetime: "2018-05-01 14:45:00", event: 1},
{datetime: "2018-05-01 16:15:00", event: 1}
];

data.forEach(function(d) {
    d.datetime = new Date(d.datetime);
})
var facts = crossfilter(data);

var eventsByDay = facts.dimension(function(d) { return d3.timeHour(d.datetime);});
var eventsByDayGroup = eventsByDay.group().reduceCount(); 

function fill_intervals(group, interval) {
  return {
  	all: function() {
      var orig = group.all().map(kv => ({key: new Date(kv.key), value: kv.value}));
      var target = interval.range(orig[0].key, orig[orig.length-1].key);
      var result = [];
      for(var oi = 0, ti = 0; oi < orig.length && ti < target.length;) {
        if(orig[oi].key <= target[ti]) {
          result.push(orig[oi]);
          if(orig[oi++].key.valueOf() === target[ti].valueOf())
            ++ti;
        } else {
          result.push({key: target[ti], value: 0});
          ++ti;
        }
      }
      if(oi<orig.length)
        Array.prototype.push.apply(result, orig.slice(oi));
      if(ti<target.length)
        Array.prototype.push.apply(result, target.slice(ti).map(t => ({key: t, value: 0})));
      return result;
    }
  }
}

d3.select('#input').text(JSON.stringify(eventsByDayGroup.all(), null, 2))
var filled = fill_intervals(eventsByDayGroup, d3.timeHour);
d3.select('#output').text(JSON.stringify(filled.all(), null, 2));