From cc1c77930bdfab366c7c59d4902cef1f6d7b0875 Mon Sep 17 00:00:00 2001 From: JoshBaneyCS Date: Wed, 30 Apr 2025 05:56:08 +0000 Subject: [PATCH] Update public/scripts/trends.js --- public/scripts/trends.js | 123 +++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/public/scripts/trends.js b/public/scripts/trends.js index 660ee46..48bd44a 100644 --- a/public/scripts/trends.js +++ b/public/scripts/trends.js @@ -1,49 +1,56 @@ -// Timeframe configurations +// 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 a given amount from a Date +// Subtract helper 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; } document.addEventListener('DOMContentLoaded', () => { - // 1) Grab embedded data + // 1) Grab the server‐injected readings const data = window.__INITIAL_READINGS__ || []; - - readings = data.map(r => ({ - stationDockDoor: r.stationDockDoor, - location: r.location, - temperature: r.temperature, - humidity: r.humidity, - heatIndex: r.heatIndex, - dateObj: new Date(r.epoch_ms), - formattedTs: new Date(r.epoch_ms).toLocaleString('en-US', { - timeZone: 'America/New_York', - month: 'numeric', - day: 'numeric', - year: '2-digit', - hour12: false, - hour: '2-digit', - minute: '2-digit' - }).replace(',', ' @') - })); + 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 { + stationDockDoor: r.stationDockDoor, + location: r.location, + temperature: r.temperature, + humidity: r.humidity, + heatIndex: r.heatIndex, + dateObj: dt, + formattedTs: dt.toLocaleString('en-US', { + timeZone: 'America/New_York', + month: 'numeric', + day: 'numeric', + year: '2-digit', + hour: '2-digit', + minute: '2-digit', + hour12: false + }).replace(',', ' @') + }; + }); setupUI(); initChart(); @@ -51,7 +58,7 @@ document.addEventListener('DOMContentLoaded', () => { }); function setupUI() { - // Timeframe slider + // Slider + label const slider = document.getElementById('timeframe-slider'); const label = document.getElementById('timeframe-label'); slider.addEventListener('input', () => { @@ -60,7 +67,7 @@ function setupUI() { }); label.textContent = tfConfig[slider.value].label; - // Metric toggles + // Metric checkboxes document.getElementsByName('metric').forEach(cb => { cb.addEventListener('change', updateView); }); @@ -72,13 +79,10 @@ function setupUI() { const asc = !th.classList.contains('asc'); const tbody = document.getElementById('trends-table-body'); Array.from(tbody.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 }); - }) + .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); }); @@ -92,11 +96,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 } }); @@ -105,40 +109,46 @@ function initChart() { function updateView() { if (!chart) return; - // Determine cutoff - const idx = +document.getElementById('timeframe-slider').value; - const { unit, count } = tfConfig[idx]; - const cutoff = subtract(Date.now(), count, unit); + // Determine "now" from the latest reading, not the browser clock + const maxEpoch = Math.max(...readings.map(r => r.dateObj.getTime())); + const nowDate = new Date(maxEpoch); - // Filter readings + // Compute cutoff + const idx = +document.getElementById('timeframe-slider').value; + const { unit, count } = tfConfig[idx]; + const cutoff = (idx === 4) + ? new Date(0) // "All Time" + : subtract(nowDate, count, unit); + + // Filter const filtered = readings.filter(r => r.dateObj >= cutoff); - // Determine selected metrics + // Which metrics? const selected = Array.from(document.getElementsByName('metric')) .filter(cb => cb.checked) .map(cb => cb.value); - // Build chart - chart.data.labels = filtered.map(r => r.formattedTs); + // Update chart + chart.data.labels = filtered.map(r => r.formattedTs); chart.data.datasets = []; if (selected.includes('temperature')) { chart.data.datasets.push({ label: 'Temperature (°F)', - data: filtered.map(r => r.temperature), + data: filtered.map(r => r.temperature), tension: 0.3 }); } if (selected.includes('humidity')) { chart.data.datasets.push({ label: 'Humidity (%)', - data: filtered.map(r => r.humidity), + data: filtered.map(r => r.humidity), tension: 0.3 }); } if (selected.includes('heatIndex')) { chart.data.datasets.push({ label: 'Heat Index (°F)', - data: filtered.map(r => r.heatIndex), + data: filtered.map(r => r.heatIndex), tension: 0.3 }); } @@ -160,3 +170,4 @@ function updateView() { tbody.appendChild(tr); }); } +