173 lines
4.8 KiB
Plaintext
173 lines
4.8 KiB
Plaintext
|
extends ./master.pug
|
||
|
|
||
|
mixin sortableLinks(col, label)
|
||
|
span.sortables.float-left.mr-2.d-inline-flex.flex-column(style="font-size: 50%")
|
||
|
a(href="#sort:" + col + ":asc") ▲
|
||
|
a(href="#sort:" + col + ":desc") ▼
|
||
|
block
|
||
|
|
||
|
block main
|
||
|
h2 Country Rollup
|
||
|
div#table.table-responsive: table.table.table-sm.table-hover
|
||
|
thead: tr
|
||
|
th #
|
||
|
th: +sortableLinks("name") Country
|
||
|
th: +sortableLinks("total") Deaths
|
||
|
th: +sortableLinks("yesterday") …since yesterday
|
||
|
th: +sortableLinks("week") …since last week
|
||
|
th: +sortableLinks("month") …month-to-date
|
||
|
th Last 14 days
|
||
|
-
|
||
|
data.sort((a, b) => {
|
||
|
const yesterdayA = a.timeSeriesDaily[a.timeSeriesDaily.length - 1].delta;
|
||
|
const yesterdayB = b.timeSeriesDaily[b.timeSeriesDaily.length - 1].delta;
|
||
|
if (yesterdayA === yesterdayB) {
|
||
|
return a.name.localeCompare(b.name);
|
||
|
}
|
||
|
|
||
|
return yesterdayA < yesterdayB ? 1 : -1;
|
||
|
});
|
||
|
|
||
|
tbody: each item, i in data
|
||
|
- const yesterday = item.timeSeriesDaily[item.timeSeriesDaily.length - 1].delta || 0;
|
||
|
- const lastWeek = item.timeSeriesDaily[item.timeSeriesDaily.length - 1].value - item.timeSeriesDaily[item.timeSeriesDaily.length - 7].value;
|
||
|
- const lastMonth = item.timeSeriesMonthly[item.timeSeriesMonthly.length - 1].delta || 0;
|
||
|
tr(id="row-" + item.safeName data-name=item.name data-total=item.total data-yesterday=yesterday data-week=lastWeek data-month=lastMonth)
|
||
|
td.sort-order= i + 1
|
||
|
td: a(href="./countries/" + item.safeName + ".html")= item.name
|
||
|
td.text-right: +formatNumber(item.total)
|
||
|
td.text-right: +formatNumber(yesterday)
|
||
|
td.text-right: +formatNumber(lastWeek)
|
||
|
td.text-right: +formatNumber(lastMonth)
|
||
|
td
|
||
|
canvas(id="sparkline-" + i width="200" height="50")
|
||
|
script.
|
||
|
(function() {
|
||
|
const canvas = document.getElementById('sparkline-#{i}');
|
||
|
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: #{JSON.stringify(item.timeSeriesDaily.slice(-14).map(x => x.value))},
|
||
|
}
|
||
|
],
|
||
|
},
|
||
|
options: {
|
||
|
responsive: false,
|
||
|
legend: {
|
||
|
display: false,
|
||
|
},
|
||
|
elements: {
|
||
|
line: {
|
||
|
borderColor: '#000000',
|
||
|
borderWidth: 1,
|
||
|
},
|
||
|
point: {
|
||
|
radius: 0,
|
||
|
},
|
||
|
},
|
||
|
tooltips: {
|
||
|
enabled: false,
|
||
|
},
|
||
|
scales: {
|
||
|
yAxes: [
|
||
|
{
|
||
|
display: false,
|
||
|
ticks: {
|
||
|
precision: 0,
|
||
|
beginAtZero: true,
|
||
|
}
|
||
|
},
|
||
|
],
|
||
|
xAxes: [
|
||
|
{
|
||
|
display: false,
|
||
|
},
|
||
|
],
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
}());
|
||
|
|
||
|
script.
|
||
|
(function() {
|
||
|
const tbody = document.getElementById('table').querySelector('tbody');
|
||
|
const allRows = [].slice.call(tbody.querySelectorAll('tbody tr'));
|
||
|
|
||
|
const resortTable = () => {
|
||
|
let nextChild = null;
|
||
|
for (let i = allRows.length - 1; i >= 0; i--) {
|
||
|
const row = allRows[i];
|
||
|
if (!row) {
|
||
|
continue;
|
||
|
}
|
||
|
if (row === nextChild) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
tbody.insertBefore(row, nextChild);
|
||
|
row.querySelector('.sort-order').textContent = (i + 1).toString();
|
||
|
nextChild = row;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const handleSort = (value, dir) => {
|
||
|
const newSortDir = dir === 'desc' ? 'desc' : 'asc';
|
||
|
const sortByNumberThenName = (attr) => {
|
||
|
allRows.sort((a, b) => {
|
||
|
const aValue = Number(a.getAttribute('data-' + attr));
|
||
|
const bValue = Number(b.getAttribute('data-' + attr));
|
||
|
if (aValue === bValue) {
|
||
|
const aName = a.getAttribute('data-name');
|
||
|
const bName = b.getAttribute('data-name');
|
||
|
return aName.localeCompare(bName);
|
||
|
}
|
||
|
|
||
|
return aValue < bValue ?
|
||
|
(newSortDir === 'asc' ? -1 : 1) :
|
||
|
(newSortDir === 'asc' ? 1 : -1);
|
||
|
});
|
||
|
resortTable();
|
||
|
};
|
||
|
switch (value) {
|
||
|
case 'name':
|
||
|
allRows.sort((a, b) => {
|
||
|
const aName = a.getAttribute('data-name');
|
||
|
const bName = b.getAttribute('data-name');
|
||
|
if (newSortDir === 'asc') {
|
||
|
return aName.localeCompare(bName);
|
||
|
}
|
||
|
|
||
|
return bName.localeCompare(aName);
|
||
|
});
|
||
|
resortTable();
|
||
|
break;
|
||
|
case 'total':
|
||
|
sortByNumberThenName('total');
|
||
|
break;
|
||
|
case 'yesterday':
|
||
|
sortByNumberThenName('yesterday');
|
||
|
break;
|
||
|
case 'week':
|
||
|
sortByNumberThenName('week');
|
||
|
break;
|
||
|
case 'month':
|
||
|
sortByNumberThenName('month');
|
||
|
break;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const handleHash = (hash) => {
|
||
|
const sortValue = hash.replace(/^#sort:/, '').split(':');
|
||
|
handleSort(sortValue[0], sortValue[1]);
|
||
|
};
|
||
|
|
||
|
window.addEventListener('hashchange', () => {
|
||
|
handleHash(window.location.hash);
|
||
|
});
|
||
|
|
||
|
handleHash(window.location.hash || '#sort:yesterday:desc');
|
||
|
}());
|