smart date formatting on chart x-axis

This commit is contained in:
Danny van Kooten 2018-05-24 13:35:43 +02:00
parent d4bd700513
commit a00e72f81d
2 changed files with 1208 additions and 1176 deletions

View File

@ -12,7 +12,35 @@ function padZero(s) {
return s < 10 ? "0" + s : s; return s < 10 ? "0" + s : s;
} }
function padData(startUnix, endUnix, data) { const timeFormats = [
[() => '', function(d, n) {
return true;
}],
[d3.timeFormat("%Y"), function (d, i, n) {
return d.getUTCMonth() === 0 && d.getUTCDate() === 1;;
}],
[d3.timeFormat("%b"), function (d, i, n) {
return ( d.getUTCMonth() > 0 && d.getUTCDate() === 1 );
}],
[d3.timeFormat("%d"), function (d, i, n) {
return ( d.getUTCDate() > 1 ) && n < 32;
}],
[d3.timeFormat("%b %d"), function (d, i, n) {
return i === 0 && d.getUTCDate() > 1;
}]
]
var timeFormatPicker = function (formats, len) {
return function (date, pos) {
var i = formats.length - 1, f = formats[i];
while (!f[1](date, pos, len)) {
f = formats[--i];
}
return f[0](date);
};
};
function prepareData(startUnix, endUnix, data) {
let startDate = new Date(startUnix * 1000); let startDate = new Date(startUnix * 1000);
let endDate = new Date(endUnix * 1000); let endDate = new Date(endUnix * 1000);
let datamap = []; let datamap = [];
@ -25,16 +53,18 @@ function padData(startUnix, endUnix, data) {
}); });
// make sure we have values for each date // make sure we have values for each date
while(startDate < endDate) { let currentDate = startDate;
let date = startDate.getFullYear() + "-" + padZero(startDate.getMonth() + 1) + "-" + padZero(startDate.getDate()); while(currentDate < endDate) {
let data = datamap[date] ? datamap[date] : { let key = currentDate.getFullYear() + "-" + padZero(currentDate.getMonth() + 1) + "-" + padZero(currentDate.getDate());
"Date": date, let data = datamap[key] ? datamap[key] : {
"Pageviews": 0, "Pageviews": 0,
"Visitors": 0, "Visitors": 0,
}; };
// replace Date property with actual date object
data.Date = new Date(currentDate);
newData.push(data); newData.push(data);
startDate.setDate(startDate.getDate() + 1); currentDate.setDate(currentDate.getDate() + 1);
} }
return newData; return newData;
@ -69,7 +99,7 @@ class Chart extends Component {
return; return;
} }
let padding = { top: 24, right: 12, bottom: 64, left: 40 }; let padding = { top: 12, right: 12, bottom: 24, left: 40 };
let height = Math.max( this.base.clientHeight, 240 ); let height = Math.max( this.base.clientHeight, 240 );
let width = this.base.clientWidth; let width = this.base.clientWidth;
let innerWidth = width - padding.left - padding.right; let innerWidth = width - padding.left - padding.right;
@ -91,31 +121,33 @@ class Chart extends Component {
const max = d3.max(data, (d) => d.Pageviews); const max = d3.max(data, (d) => d.Pageviews);
// axes // axes
let x = d3.scaleBand().range([0, innerWidth]).padding(0.1).domain(data.map((d) => d.Date)), let x = d3.scaleBand().range([0, innerWidth]).padding(0.1).domain(data.map((d) => d.Date))
y = d3.scaleLinear().range([innerHeight, 0]).domain([0, (max*1.1)]), let y = d3.scaleLinear().range([innerHeight, 0]).domain([0, (max*1.1)])
yAxis = d3.axisLeft().scale(y).ticks(3).tickSize(-innerWidth), let yAxis = d3.axisLeft().scale(y).ticks(3).tickSize(-innerWidth)
xAxis = d3.axisBottom().scale(x); let xAxis = d3.axisBottom().scale(x).tickFormat(timeFormatPicker(timeFormats, data.length))
graph.append("g") let yTicks = graph.append("g")
.attr("class", "y axis") .attr("class", "y axis")
.call(yAxis); .call(yAxis);
let nxTicks = Math.max(1, Math.round(data.length / 60));
let nxLabels = Math.max(1, Math.round(data.length / 15));
let xTicks = graph.append("g") let xTicks = graph.append("g")
.attr("class", "x axis") .attr("class", "x axis")
.attr('transform', 'translate(0,' + innerHeight + ')') .attr('transform', 'translate(0,' + innerHeight + ')')
.call(xAxis) .call(xAxis)
xTicks.selectAll('g text').style('display', (d, i) => {
return i % nxLabels != 0 ? 'none' : 'block'
}).attr("transform", "rotate(-60)").style("text-anchor", "end"); // hide all "day" ticks if we're watching more than 100 days of data
xTicks.selectAll('g').style('display', (d, i) => { xTicks.selectAll('g').style('display', (d, i) => {
return i % nxTicks != 0 ? 'none' : 'block'; if(data.length > 100 && d.getUTCDate() > 1 ) {
}); return 'none';
}
return '';
})
// tooltip // tooltip
const tip = d3.tip().attr('class', 'd3-tip').html((d) => (` const tip = d3.tip().attr('class', 'd3-tip').html((d) => (`
<div class="tip-heading">${d.Date}</div> <div class="tip-heading">${d.Date.toLocaleDateString()}</div>
<div class="tip-content"> <div class="tip-content">
<div class="tip-pageviews"> <div class="tip-pageviews">
<div class="tip-number">${d.Pageviews}</div> <div class="tip-number">${d.Pageviews}</div>
@ -169,7 +201,7 @@ class Chart extends Component {
this.setState({ this.setState({
loading: false, loading: false,
data: padData(after, before, d), data: prepareData(after, before, d),
}); });
this.redrawChart(); this.redrawChart();

2304
package-lock.json generated

File diff suppressed because it is too large Load Diff