diff --git a/public/scripts/trends.js b/public/scripts/trends.js index 17830a5..660ee46 100644 --- a/public/scripts/trends.js +++ b/public/scripts/trends.js @@ -1,63 +1,57 @@ -// public/scripts/trends.js - -// --- Timeframe options --- +// Timeframe configurations 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' } ]; -// --- State --- let readings = []; let chart; -// --- Helpers --- +// Subtract a given amount from a Date 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; } -// --- Load & initialize --- -document.addEventListener('DOMContentLoaded', async () => { - console.log('📡 Loading readings from /api/readings…'); - try { - const data = await fetch('/api/readings').then(r => r.json()); - console.log('✅ Received readings:', data); - 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', - hour:'2-digit', minute:'2-digit', hour12:false - }).replace(',',' @') - })); - console.log('✔ Parsed readings:', readings); +document.addEventListener('DOMContentLoaded', () => { + // 1) Grab embedded data + 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(',', ' @') + })); - setupUI(); - initChart(); - updateView(); - } catch (err) { - console.error('❌ Failed to load readings:', err); - } + setupUI(); + initChart(); + updateView(); }); -// --- UI wiring --- function setupUI() { - // Slider + // Timeframe slider const slider = document.getElementById('timeframe-slider'); const label = document.getElementById('timeframe-label'); slider.addEventListener('input', () => { @@ -66,7 +60,7 @@ function setupUI() { }); label.textContent = tfConfig[slider.value].label; - // Metrics toggles + // Metric toggles document.getElementsByName('metric').forEach(cb => { cb.addEventListener('change', updateView); }); @@ -78,87 +72,79 @@ function setupUI() { const asc = !th.classList.contains('asc'); 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}) - ) + .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 }); + }) .forEach(r => tbody.appendChild(r)); th.classList.toggle('asc', asc); }); }); } -// --- Chart.js init --- function initChart() { - if (typeof Chart === 'undefined') { - console.error('❌ Chart.js not loaded!'); - return; - } - console.log('📊 Initializing Chart.js'); const ctx = document.getElementById('trend-chart').getContext('2d'); chart = new Chart(ctx, { type: 'line', 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' } }, - maintainAspectRatio:false + interaction: { mode: 'index', intersect: false }, + plugins: { legend: { position: 'top' } }, + maintainAspectRatio: false } }); } -// --- Render chart & table --- function updateView() { if (!chart) return; - console.log('🔄 updateView called'); - // Timeframe cutoff + // Determine cutoff const idx = +document.getElementById('timeframe-slider').value; const { unit, count } = tfConfig[idx]; - const cutoff = subtract(new Date(), count, unit); - console.log(` Showing data since ${cutoff.toISOString()}`); + const cutoff = subtract(Date.now(), count, unit); // Filter readings const filtered = readings.filter(r => r.dateObj >= cutoff); - console.log(` ${filtered.length}/${readings.length} points after filtering`); - // Metrics selected + // Determine selected metrics const selected = Array.from(document.getElementsByName('metric')) - .filter(cb => cb.checked).map(cb => cb.value); - console.log(' Metrics selected:', selected); + .filter(cb => cb.checked) + .map(cb => cb.value); - // Update chart + // Build chart chart.data.labels = filtered.map(r => r.formattedTs); chart.data.datasets = []; if (selected.includes('temperature')) { chart.data.datasets.push({ - label:'Temperature (°F)', + label: 'Temperature (°F)', data: filtered.map(r => r.temperature), tension: 0.3 }); } if (selected.includes('humidity')) { chart.data.datasets.push({ - label:'Humidity (%)', + label: 'Humidity (%)', data: filtered.map(r => r.humidity), tension: 0.3 }); } if (selected.includes('heatIndex')) { chart.data.datasets.push({ - label:'Heat Index (°F)', + label: 'Heat Index (°F)', data: filtered.map(r => r.heatIndex), tension: 0.3 }); } - console.log(' Chart update:', chart.data); chart.update(); - // Update table + // Populate table const tbody = document.getElementById('trends-table-body'); tbody.innerHTML = ''; filtered.forEach(r => { @@ -173,5 +159,4 @@ function updateView() { `; tbody.appendChild(tr); }); - console.log(' Table populated with', filtered.length, 'rows'); }