我正在尝试使用crossfilter.js和d3.js生成画笔和图表以过滤我的数据。日期格式为“ 2019-04-08T09:07:22.512Z”。我尝试了各种方法来解析日期并生成图表,但无法这样做。我在控制台“ t.apply不是函数”中收到以下错误。看着错误,我认为render和renderAll函数有问题。
d3版本5.7.0
var cf = crossfilter(json);
var all = cf.groupAll();
var byAlertType = cf.dimension(function(p) {return p['alertType'];});
var byDate = cf.dimension(function (p) { return p['created'].substring(0,10);});
var byHour = cf.dimension(function (p) { return p['created'].substring(11,13);});
var byTimezone = cf.dimension(function (p) { return p['created'].substring(30,39);});
var groupByAlertType = byAlertType.group();
var groupByDate = byDate.group();
var groupByHour = byHour.group();
var groupByTimezone = byTimezone.group();
//data selected, counts by day date hour
groupByAlertType.top(Infinity).forEach(function(p,i){
console.log(p.key + ":" + p.value);
});
groupByDate.top(Infinity).forEach(function(p,i){
console.log(p.key + ":" + p.value);
});
groupByTimezone.top(Infinity).forEach(function(p,i){
console.log(p.key + ":" + p.value);
});
groupByHour.top(Infinity).forEach(function(p,i){
console.log(p.key + ":" + p.value);
});
var charts = [
barChart()
.dimension(byHour)
.group(groupByHour)
.x(d3.scaleLinear()
.domain([0,24])
.rangeRound([0, 10*24])),
barChart()
.dimension(byDate)
.group(groupByDate)
.round(d3.timeDay.round)
.x(d3.scaleTime()
.domain([new Date(2019,4,1),new Date(2019,5,1)])
.rangeRound([0,10*30])),
barChart()
.dimension(byAlertType)
.group(groupByAlertType)
.x(d3.scaleLinear()
.domain([0,24])
.rangeRound([0, 10*24])),
barChart()
.dimension(byTimezone)
.group(groupByTimezone)
.x(d3.scaleLinear()
.domain([0,24])
.rangeRound([0, 10*24])),
];
//charts as they appear in DOM
const viz = d3.selectAll('.chart')
.data([charts])
// render initial list
const list = d3.selectAll('.list')
.data([alertList]);
d3.selectAll('#total')
.text((cf.size()));
renderAll();
function render(method){
d3.select(this).call(method);
}
function renderAll() {
viz.each(render);
list.each(render);
d3.select('#active').text(all.value());
}
window.filter = filters => {
filters.forEach((d, i) => { charts[i].filter(d); });
renderAll();
};
window.reset = i => {
charts[i].filter(null);
renderAll();
};
function alertList(div) {
}
function barChart() {
if (!barChart.id) barChart.id = 0;
let margin = { top: 10, right: 13, bottom: 20, left: 10 };
let x;
let y = d3.scaleLinear().range([100, 0]);
const id = barChart.id++;
const axis = d3.axisBottom();
const brush = d3.brushX();
let brushDirty;
let dimension;
let group;
let round;
let gBrush;
function chart(div) {
const width = x.range()[1];
const height = y.range()[0];
brush.extent([[0, 0], [width, height]]);
y.domain([0, group.top(1)[0].value]);
div.each(function () {
const div = d3.select(this);
let g = div.select('g');
// Create the skeletal chart.
if (g.empty()) {
div.select('.title').append('a')
.attr('href', `javascript:reset(${id})`)
.attr('class', 'reset')
.text('reset')
.style('display', 'none');
g = div.append('svg')
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
g.append('clipPath')
.attr('id', `clip-${id}`)
.append('rect')
.attr('width', width)
.attr('height', height);
g.selectAll('.bar')
.data(['background', 'foreground'])
.enter().append('path')
.attr('class', d => `${d} bar`)
.datum(group.all());
g.selectAll('.foreground.bar')
.attr('clip-path', `url(#clip-${id})`);
g.append('g')
.attr('class', 'axis')
.attr('transform', `translate(0,${height})`)
.call(axis);
// Initialize the brush component with pretty resize handles.
gBrush = g.append('g')
.attr('class', 'brush')
.call(brush);
gBrush.selectAll('.handle--custom')
.data([{ type: 'w' }, { type: 'e' }])
.enter().append('path')
.attr('class', 'brush-handle')
.attr('cursor', 'ew-resize')
.attr('d', resizePath)
.style('display', 'none');
}
// Only redraw the brush if set externally.
if (brushDirty !== false) {
const filterVal = brushDirty;
brushDirty = false;
div.select('.title a').style('display', d3.brushSelection(div) ? null : 'none');
if (!filterVal) {
g.call(brush);
g.selectAll(`#clip-${id} rect`)
.attr('x', 0)
.attr('width', width);
g.selectAll('.brush-handle').style('display', 'none');
renderAll();
} else {
const range = filterVal.map(x);
brush.move(gBrush, range);
}
}
g.selectAll('.bar').attr('d', barPath);
});
function barPath(groups) {
const path = [];
let i = -1;
const n = groups.length;
let d;
while (++i < n) {
d = groups[i];
path.push('M', x(d.key), ',', height, 'V', y(d.value), 'h9V', height);
}
return path.join('');
}
function resizePath(d) {
const e = +(d.type === 'e');
const x = e ? 1 : -1;
const y = height / 3;
return `M${0.5 * x},
${y}A6,6 0 0 ${e} ${6.5 * x},
${y + 6}V${2 * y - 6}A6,6 0 0 ${e} ${0.5 * x},${2 * y}ZM${2.5 * x},${y + 8}V${2 * y - 8}M${4.5 * x},${y + 8}V${2 * y - 8}`;
}
}
brush.on('start.chart', function () {
const div = d3.select(this.parentNode.parentNode.parentNode);
div.select('.title a').style('display', null);
});
brush.on('brush.chart', function () {
const g = d3.select(this.parentNode);
const brushRange = d3.event.selection || d3.brushSelection(this); // attempt to read brush range
const xRange = x && x.range(); // attempt to read range from x scale
let activeRange = brushRange || xRange; // default to x range if no brush range available
const hasRange = activeRange &&
activeRange.length === 2 &&
!isNaN(activeRange[0]) &&
!isNaN(activeRange[1]);
if (!hasRange) return; // quit early if we don't have a valid range
// calculate current brush extents using x scale
let extents = activeRange.map(x.invert);
// if rounding fn supplied, then snap to rounded extents
// and move brush rect to reflect rounded range bounds if it was set by user interaction
if (round) {
extents = extents.map(round);
activeRange = extents.map(x);
if (
d3.event.sourceEvent &&
d3.event.sourceEvent.type === 'mousemove'
) {
d3.select(this).call(brush.move, activeRange);
}
}
// move brush handles to start and end of range
g.selectAll('.brush-handle')
.style('display', null)
.attr('transform', (d, i) => `translate(${activeRange[i]}, 0)`);
// resize sliding window to reflect updated range
g.select(`#clip-${id} rect`)
.attr('x', activeRange[0])
.attr('width', activeRange[1] - activeRange[0]);
// filter the active dimension to the range extents
dimension.filterRange(extents);
// re-render the other charts accordingly
renderAll();
});
brush.on('end.chart', function () {
// reset corresponding filter if the brush selection was cleared
// (e.g. user "clicked off" the active range)
if (!d3.brushSelection(this)) {
reset(id);
}
});
chart.margin = function (_) {
if (!arguments.length) return margin;
margin = _;
return chart;
};
chart.x = function (_) {
if (!arguments.length) return x;
x = _;
axis.scale(x);
return chart;
};
chart.y = function (_) {
if (!arguments.length) return y;
y = _;
return chart;
};
chart.dimension = function (_) {
if (!arguments.length) return dimension;
dimension = _;
return chart;
};
chart.filter = _ => {
if (!_) dimension.filterAll();
brushDirty = _;
return chart;
};
chart.group = function (_) {
if (!arguments.length) return group;
group = _;
return chart;
};
chart.round = function (_) {
if (!arguments.length) return round;
round = _;
return chart;
};
chart.gBrush = () => gBrush;
return chart;
}
};
};