graph tweaks

This commit is contained in:
tmont 2020-04-30 23:28:21 -07:00
parent 8bff273d8b
commit 38a8191744
2 changed files with 67 additions and 20 deletions

View File

@ -157,25 +157,28 @@ const processGlobalDeaths = async () => {
const getRollingAverage = (item) => { const getRollingAverage = (item) => {
return item.timeSeriesDaily.map((item, i, arr) => { return item.timeSeriesDaily.map((item, i, arr) => {
const prevValues = arr.slice(Math.max(0, i - 6), i); const prevValues = arr.slice(Math.max(0, i - 6), i);
const valueAverage = (item.value + prevValues.reduce((sum, next) => sum + next.value, 0)) / (1 + prevValues.length); let valueAverage = (item.value + prevValues.reduce((sum, next) => sum + next.value, 0)) / (1 + prevValues.length);
const deltaAverage = (item.delta + prevValues.reduce((sum, next) => sum + next.delta, 0)) / (1 + prevValues.length); let deltaAverage = (item.delta + prevValues.reduce((sum, next) => sum + next.delta, 0)) / (1 + prevValues.length);
if (valueAverage < 1) {
valueAverage = Math.round(valueAverage);
}
if (deltaAverage < 1) {
deltaAverage = Math.round(deltaAverage);
}
return { return {
key: item.key, key: item.key,
value: Math.round(valueAverage), value: Math.round(valueAverage * 10) / 10,
delta: Math.round(deltaAverage), delta: Math.round(deltaAverage * 10) / 10,
}; };
}); });
}; };
const getDoublingTime = (item) => { const getDoublingTime = (item) => {
return item.timeSeriesDaily.map((item, i, arr) => { return item.timeSeriesDaily.map((item, i, arr) => {
const prevItems = arr.slice(Math.max(i - 7, 0), i);
const sum = prevItems.reduce((sum, next) => sum + next.value, 0);
let value; let value;
if (sum < 10) { if (item.value < 10) {
value = 0; value = 0;
} else { } else {
const growthRate = calcGrowthRate(arr, i, 7); const growthRate = calcGrowthRate(arr, i, 7);

View File

@ -32,6 +32,31 @@ html
} }
}); });
// https://stackoverflow.com/a/45172506
Chart.defaults.lineVerticalTooltip = Chart.defaults.line;
Chart.controllers.lineVerticalTooltip = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
const activePoint = this.chart.tooltip._active[0];
const ctx = this.chart.ctx;
const x = activePoint.tooltipPosition().x;
const topY = this.chart.legend.bottom;
const bottomY = this.chart.chartArea.bottom;
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 1;
ctx.strokeStyle = 'rgba(96, 96, 96, 0.75)';
ctx.stroke();
ctx.restore();
}
}
});
const charts = { const charts = {
logarithmic: false, logarithmic: false,
heroChart: null, heroChart: null,
@ -40,7 +65,7 @@ html
function makeSparkline(id, data) { function makeSparkline(id, data) {
const canvas = document.getElementById(id); const canvas = document.getElementById(id);
const maxValue = data[data.length - 1]; const maxValue = data.reduce((max, value) => Math.max(max, value), 0);
const chart = new Chart(canvas.getContext('2d'), { const chart = new Chart(canvas.getContext('2d'), {
type: 'line', type: 'line',
data: { data: {
@ -73,7 +98,8 @@ html
ticks: { ticks: {
precision: 0, precision: 0,
beginAtZero: true, beginAtZero: true,
max: Math.pow(10, Math.ceil(Math.log10(maxValue))), min: 0,
max: maxValue > 0 ? Math.pow(10, Math.ceil(Math.log10(maxValue))) : 0,
callback: value => Number(value.toString()), callback: value => Number(value.toString()),
} }
}, },
@ -139,14 +165,29 @@ html
const canvas = document.getElementById(id); const canvas = document.getElementById(id);
charts.heroMaxValue = totalDeaths[totalDeaths.length - 1]; charts.heroMaxValue = totalDeaths[totalDeaths.length - 1];
const firstNonZeroDeathIndex = totalDeaths.findIndex(value => value > 0);
const start = Math.max(0, firstNonZeroDeathIndex - 2);
const end = totalDeaths.length;
const totalData = totalDeaths.slice(start, end);
const newData = newDeaths.slice(start, end);
const rollingData = rollingAverage.slice(start, end);
const doublingData = doubling.slice(start, end);
const months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ];
const realLabels = labels
.slice(start, end)
.map((date) => date.replace(/\d{4}-(\d\d?)-(\d\d?)/, (_, m, d) => `${months[Number(m) - 1]} ${Number(d)}`));
charts.heroChart = new Chart(canvas.getContext('2d'), { charts.heroChart = new Chart(canvas.getContext('2d'), {
type: 'line', type: 'lineVerticalTooltip',
data: { data: {
labels: labels, labels: realLabels,
datasets: [ datasets: [
{ {
label: 'Cumulative', label: 'Cumulative',
data: totalDeaths, data: totalData,
fill: '1', fill: '1',
borderColor: 'rgb(196, 64, 64)', borderColor: 'rgb(196, 64, 64)',
borderWidth: 1, borderWidth: 1,
@ -154,7 +195,7 @@ html
}, },
{ {
label: 'New (rolling)', label: 'New (rolling)',
data: rollingAverage, data: rollingData,
fill: 'origin', fill: 'origin',
borderColor: 'rgb(20,24,59)', borderColor: 'rgb(20,24,59)',
borderWidth: 1, borderWidth: 1,
@ -162,14 +203,14 @@ html
}, },
{ {
label: 'New', label: 'New',
data: newDeaths, data: newData,
fill: false, fill: false,
borderColor: 'rgb(96, 96, 96, 0.25)', borderColor: 'rgb(96, 96, 96, 0.25)',
borderWidth: 1, borderWidth: 1,
}, },
{ {
label: 'Days to 2x', label: 'Days to 2x',
data: doubling, data: doublingData,
fill: false, fill: false,
borderColor: 'rgb(187,40,193, 0.5)', borderColor: 'rgb(187,40,193, 0.5)',
borderWidth: 2, borderWidth: 2,
@ -339,7 +380,7 @@ html
script. script.
makeSparkline( makeSparkline(
"sparkline-#{i}", "sparkline-#{i}",
#{JSON.stringify(item.timeSeriesDaily.slice(-14).map(x => x.value))}, #{JSON.stringify(item.timeSeriesDaily.slice(-14).map(x => x.delta))},
); );
@ -371,7 +412,6 @@ html
const resortTable = (col) => { const resortTable = (col) => {
let nextChild = null; let nextChild = null;
const highlightedIndex = headers.findIndex(cell => cell.getAttribute('data-col') === col); const highlightedIndex = headers.findIndex(cell => cell.getAttribute('data-col') === col);
console.log(col, highlightedIndex);
headers.forEach((cell, i) => { headers.forEach((cell, i) => {
if (i !== highlightedIndex) { if (i !== highlightedIndex) {
cell.classList.remove('sorted'); cell.classList.remove('sorted');
@ -383,8 +423,11 @@ html
for (let i = allRows.length - 1; i >= 0; i--) { for (let i = allRows.length - 1; i >= 0; i--) {
const row = allRows[i]; const row = allRows[i];
if (!row) { if (!row) {
console.log(i + ' no row!');
continue; continue;
} }
const name = row.getAttribute('data-name');
console.log(row.id, name, !name && row);
const cells = [].slice.call(row.querySelectorAll('td')); const cells = [].slice.call(row.querySelectorAll('td'));
cells.forEach((cell, i) => { cells.forEach((cell, i) => {
if (i !== highlightedIndex) { if (i !== highlightedIndex) {
@ -401,6 +444,7 @@ html
row.querySelector('.sort-order').textContent = (i + 1).toString(); row.querySelector('.sort-order').textContent = (i + 1).toString();
nextChild = row; nextChild = row;
} }
console.log('---');
}; };
const handleSort = (value, dir) => { const handleSort = (value, dir) => {
@ -412,7 +456,7 @@ html
if (aValue === bValue) { if (aValue === bValue) {
const aName = a.getAttribute('data-name'); const aName = a.getAttribute('data-name');
const bName = b.getAttribute('data-name'); const bName = b.getAttribute('data-name');
return aName && bName ? aName.localeCompare(bName) : 0; return aName && bName ? aName.localeCompare(bName) : -1;
} }
return aValue < bValue ? return aValue < bValue ?