Add running fitness history and configurable heart rate zones
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
(() => {
|
||||
const source = document.getElementById('fitness-data');
|
||||
const initial = JSON.parse(source.textContent);
|
||||
let refreshing = false;
|
||||
async function refresh() {
|
||||
if (document.hidden || refreshing) return;
|
||||
refreshing = true;
|
||||
try {
|
||||
const response = await fetch(source.dataset.url, {cache: 'no-store', headers: {Accept: 'application/json'}});
|
||||
if (response.ok && response.headers.get('content-type')?.includes('application/json')) {
|
||||
const next = await response.json();
|
||||
if (JSON.stringify(next.series) !== JSON.stringify(initial.series) ||
|
||||
JSON.stringify(next.runs) !== JSON.stringify(initial.runs) ||
|
||||
JSON.stringify(next.zones) !== JSON.stringify(initial.zones)) window.location.reload();
|
||||
}
|
||||
} catch { /* Keep the current chart available while offline. */ }
|
||||
finally { refreshing = false; }
|
||||
}
|
||||
window.addEventListener('focus', refresh);
|
||||
document.addEventListener('visibilitychange', () => { if (!document.hidden) refresh(); });
|
||||
window.setInterval(refresh, 300000);
|
||||
const canvas = document.getElementById('fitness-chart');
|
||||
if (!canvas) return;
|
||||
const series = initial.series;
|
||||
const keys = ['fitness', 'fatigue', 'form'];
|
||||
const colors = ['#67cbb8', '#f48459', '#b8a1f0'];
|
||||
const chart = new Chart(canvas, {
|
||||
type: 'line',
|
||||
data: {labels: [], datasets: keys.map((key, i) => ({label: key[0].toUpperCase() + key.slice(1), data: [], borderColor: colors[i], pointRadius: 0, borderWidth: 2}))},
|
||||
options: {responsive: true, maintainAspectRatio: false, interaction: {mode: 'index', intersect: false}, plugins: {legend: {labels: {color: '#eeeae4'}}, tooltip: {callbacks: {afterBody(items) {
|
||||
const row = visible[items[0].dataIndex];
|
||||
return [row.missing ? `${row.missing} unscored run(s); known effort only` : `Daily effort: ${row.load.toFixed(1)}`, ...(row.provisional ? ['Provisional estimate'] : [])];
|
||||
}}}}, scales: {x: {ticks: {maxTicksLimit: 8, color: '#9ba4a5'}, grid: {color: '#303638'}}, y: {ticks: {color: '#9ba4a5'}, grid: {color: '#303638'}}}}
|
||||
});
|
||||
let visible = series;
|
||||
const range = document.getElementById('fitness-range');
|
||||
function update() {
|
||||
visible = range.value === 'all' ? series : series.slice(-Number(range.value));
|
||||
chart.data.labels = visible.map(row => row.day);
|
||||
keys.forEach((key, i) => {chart.data.datasets[i].data = visible.map(row => row[key]);});
|
||||
chart.update();
|
||||
}
|
||||
range.addEventListener('change', update);
|
||||
update();
|
||||
})();
|
||||
Reference in New Issue
Block a user