graph tweaks
This commit is contained in:
parent
8bff273d8b
commit
38a8191744
21
generate.js
21
generate.js
@ -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);
|
||||||
|
@ -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 ?
|
||||||
|
Loading…
Reference in New Issue
Block a user