diff --git a/public/scripts/trends.js b/public/scripts/trends.js index 48bd44a..bd5df88 100644 --- a/public/scripts/trends.js +++ b/public/scripts/trends.js @@ -1,36 +1,34 @@ + // Timeframes const tfConfig = [ - { unit:'hours', count:24, label:'Last 24 Hours' }, - { unit:'days', count:7, label:'Last 7 Days' }, - { unit:'weeks', count:4, label:'Last 4 Weeks' }, - { unit:'months', count:12, label:'Last 12 Months' }, - { unit:'years', count:1, label:'All Time' } + { unit: 'hours', count: 24, label: 'Last 24 Hours' }, + { unit: 'days', count: 7, label: 'Last 7 Days' }, + { unit: 'weeks', count: 4, label: 'Last 4 Weeks' }, + { unit: 'months', count: 12, label: 'Last 12 Months' }, + { unit: 'years', count: 1, label: 'All Time' } ]; let readings = []; let chart; -// Subtract helper +// Helper: subtract time function subtract(date, count, unit) { const d = new Date(date); - switch(unit) { - case 'hours': d.setHours(d.getHours() - count); break; - case 'days': d.setDate(d.getDate() - count); break; - case 'weeks': d.setDate(d.getDate() - 7*count); break; - case 'months': d.setMonth(d.getMonth() - count); break; - case 'years': d.setFullYear(d.getFullYear() - count); break; + switch (unit) { + case 'hours': d.setHours(d.getHours() - count); break; + case 'days': d.setDate(d.getDate() - count); break; + case 'weeks': d.setDate(d.getDate() - 7 * count); break; + case 'months': d.setMonth(d.getMonth() - count); break; + case 'years': d.setFullYear(d.getFullYear() - count);break; } return d; } +// On load document.addEventListener('DOMContentLoaded', () => { - // 1) Grab the server‐injected readings + // Grab server-injected data const data = window.__INITIAL_READINGS__ || []; - if (!data.length) { - console.warn('No initial readings found.'); - } - // 2) Map into local array with Date objs & formatted strings readings = data.map(r => { const dt = new Date(r.epoch_ms); return { @@ -45,9 +43,9 @@ document.addEventListener('DOMContentLoaded', () => { month: 'numeric', day: 'numeric', year: '2-digit', + hour12: false, hour: '2-digit', - minute: '2-digit', - hour12: false + minute: '2-digit' }).replace(',', ' @') }; }); @@ -58,7 +56,7 @@ document.addEventListener('DOMContentLoaded', () => { }); function setupUI() { - // Slider + label + // Slider const slider = document.getElementById('timeframe-slider'); const label = document.getElementById('timeframe-label'); slider.addEventListener('input', () => { @@ -67,24 +65,33 @@ function setupUI() { }); label.textContent = tfConfig[slider.value].label; - // Metric checkboxes + // Metric toggles document.getElementsByName('metric').forEach(cb => { cb.addEventListener('change', updateView); }); - // Table sorting + // Sortable headers document.querySelectorAll('#trends-table thead th.sortable').forEach(th => { th.addEventListener('click', () => { - const idx = th.cellIndex; + // Determine sort order const asc = !th.classList.contains('asc'); + // Clear other indicators + document.querySelectorAll('#trends-table thead th') + .forEach(h => h.classList.remove('asc','desc')); + th.classList.add(asc ? 'asc' : 'desc'); + + const idx = th.cellIndex; const tbody = document.getElementById('trends-table-body'); - Array.from(tbody.rows) - .sort((a,b) => asc - ? a.cells[idx].textContent.localeCompare(b.cells[idx].textContent, undefined, {numeric:true}) - : b.cells[idx].textContent.localeCompare(a.cells[idx].textContent, undefined, {numeric:true}) - ) - .forEach(r => tbody.appendChild(r)); - th.classList.toggle('asc', asc); + const rows = Array.from(tbody.rows); + + rows.sort((a, b) => { + const av = a.cells[idx].textContent; + const bv = b.cells[idx].textContent; + return asc + ? av.localeCompare(bv, undefined, { numeric: true }) + : bv.localeCompare(av, undefined, { numeric: true }); + }); + rows.forEach(r => tbody.appendChild(r)); }); }); } @@ -96,11 +103,11 @@ function initChart() { data: { labels: [], datasets: [] }, options: { scales: { - x: { title: { display:true, text:'Time (EST)' } }, - y: { title: { display:true, text:'Value' } } + x: { title: { display: true, text: 'Time (EST)' } }, + y: { title: { display: true, text: 'Value' } } }, - interaction: { mode:'index', intersect:false }, - plugins: { legend:{ position:'top' } }, + interaction: { mode: 'index', intersect: false }, + plugins: { legend: { position: 'top' } }, maintainAspectRatio: false } }); @@ -109,21 +116,21 @@ function initChart() { function updateView() { if (!chart) return; - // Determine "now" from the latest reading, not the browser clock + // Determine 'now' based on latest reading const maxEpoch = Math.max(...readings.map(r => r.dateObj.getTime())); const nowDate = new Date(maxEpoch); // Compute cutoff const idx = +document.getElementById('timeframe-slider').value; const { unit, count } = tfConfig[idx]; - const cutoff = (idx === 4) - ? new Date(0) // "All Time" + const cutoff = idx === 4 + ? new Date(0) : subtract(nowDate, count, unit); - // Filter + // Filter data const filtered = readings.filter(r => r.dateObj >= cutoff); - // Which metrics? + // Selected metrics const selected = Array.from(document.getElementsByName('metric')) .filter(cb => cb.checked) .map(cb => cb.value); @@ -170,4 +177,3 @@ function updateView() { tbody.appendChild(tr); }); } -