diff --git a/tmpl/master.pug b/tmpl/master.pug index d82aef2..19364ae 100644 --- a/tmpl/master.pug +++ b/tmpl/master.pug @@ -18,13 +18,25 @@ html } script. + const charts = { + logarithmic: false, + heroChart: null, + trends: [], + }; + function makeSparkline(id, data) { const canvas = document.getElementById(id); + const maxValue = data[data.length - 1]; const chart = new Chart(canvas.getContext('2d'), { type: 'line', data: { labels: [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14], - datasets: [{ data: data }], + datasets: [{ + data: data, + borderColor: 'rgb(53,120,193)', + borderWidth: 1, + backgroundColor: 'rgba(148,193,250,0.51)', + }], }, options: { responsive: false, @@ -32,10 +44,6 @@ html display: false, }, elements: { - line: { - borderColor: '#000000', - borderWidth: 1, - }, point: { radius: 0, }, @@ -61,11 +69,61 @@ html } } }); + + charts.trends.push({ + chart, + maxValue, + }); + } + + function setAxisType(type) { + if (charts.heroChart) { + const axis = charts.heroChart.options.scales.yAxes[0]; + if (type === 'logarithmic') { + axis.type = 'logarithmic'; + const maxLogPower = Math.ceil(Math.log10(charts.heroMaxValue)); + axis.ticks.max = Math.pow(10, maxLogPower); + axis.ticks.callback = value => Number(value.toString()); + } else { + axis.type = 'linear'; + delete axis.ticks.max; + axis.ticks.callback = value => value; + } + + charts.heroChart.update(); + + const selector = '.set-axis-' + type; + const otherSelector = type === 'linear' ? + '.set-axis-logarithmic' : + '.set-axis-linear'; + + document.querySelector(selector).disabled = true; + document.querySelector(otherSelector).disabled = false; + } + + charts.trends.forEach((data) => { + const axis = data.chart.options.scales.yAxes[0]; + if (axis.type === 'linear') { + axis.type = 'logarithmic'; + const maxLogPower = Math.ceil(Math.log10(data.maxValue)); + axis.ticks.max = Math.pow(10, maxLogPower); + axis.ticks.callback = value => Number(value.toString()); + } else { + axis.type = 'linear'; + delete axis.ticks.max; + axis.ticks.callback = value => value; + } + + data.chart.update(); + }); } function makeHeroChart(id, title, labels, totalDeaths, newDeaths) { const canvas = document.getElementById(id); - const chart = new Chart(canvas.getContext('2d'), { + + charts.heroMaxValue = totalDeaths[totalDeaths.length - 1]; + + charts.heroChart = new Chart(canvas.getContext('2d'), { type: 'line', data: { labels: labels, @@ -108,7 +166,20 @@ html ticks: { precision: 0, beginAtZero: true, - } + }, + afterBuildTicks: (axis, ticks) => { + if (axis.type === 'logarithmic') { + return ticks.filter((value) => { + if (value > 0 && value < 10) { + return false; + } + const logValue = Math.log10(value); + return Math.round(logValue) === logValue; + }); + } + + return ticks; + }, }, ], xAxes: [ @@ -121,7 +192,6 @@ html }); } body - mixin formatNumber(num) = Number(num).toLocaleString() @@ -135,7 +205,20 @@ html mixin heroChart(title) div.card.mb-4 - div.card-body + div.card-body.position-relative + div.position-absolute(style="top: 10px; right: 10px") + div.btn-group + button.btn.btn-secondary.btn-sm.set-axis-linear( + type="button" + onclick="setAxisType('linear')" + autocomplete="off" + disabled + ) Linear + button.btn.btn-secondary.btn-sm.set-axis-logarithmic( + type="button" + onclick="setAxisType('logarithmic')" + autocomplete="off" + ) Logarithmic canvas.mx-auto(id="main-chart" width="800" height="450") script. makeHeroChart( @@ -210,6 +293,7 @@ html #{JSON.stringify(item.timeSeriesDaily.slice(-14).map(x => x.value))}, ); + div.container.mt-2 h1.text-center Covid-19 Death Data div.d-flex.justify-content-around.font-italic.small @@ -224,7 +308,7 @@ html hr - div.main-content.mt-4 + div.main-content.mt-4.position-relative block main script.