Вы на правильном пути с ensure_group_bins
, но вместо того, чтобы заранее знать требуемый набор корзин, в этом случае нам нужно их вычислить.
К счастью, d3 предоставляет interval.range , который возвращает массив дат для каждой границы интервала между двумя датами.
Затем нам нужно объединить-отсортировать этот набор с ячейками из исходной группы. Возможно, я немного переработал это, но вот функция для этого:
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;
}
}
}
По сути, мы выполняем итерации как для исходных, так и для целевых корзин и выбираем, что меньше. Если они одинаковы, то мы увеличиваем оба счетчика; в противном случае мы просто увеличиваем нижний.
Наконец, когда один из массивов исчерпан, мы добавляем все остальные результаты из другого массива.
Вот пример скрипты, основанной на вашем коде.
Он написан на D3v4, но вам нужно только изменить d3.timeHour
в двух местах на d3.time.hour
, чтобы использовать его с D3v3.
Я добавлю эту функцию в FAQ!