Update public/scripts/trends.js

This commit is contained in:
JoshBaneyCS 2025-04-23 02:08:19 +00:00
parent ab5f5d2dfc
commit 8348d1a3fa

View File

@ -3,9 +3,11 @@ function average(arr) {
return arr.reduce((a, b) => a + b, 0) / arr.length; return arr.reduce((a, b) => a + b, 0) / arr.length;
} }
// period definitions // interval mappings
const periodKeys = ['hourly','daily','weekly','monthly','yearly']; const periodKeys = ['hourly','daily','weekly','monthly','yearly'];
const periodLabels = ['Hourly','Daily','Weekly','Monthly','Yearly']; const periodLabels = ['Hourly','Daily','Weekly','Monthly','Yearly'];
// bucket definitions
const periodConfig = { const periodConfig = {
hourly: { keyFn: r => r.timestamp.slice(0,13), labelFn: k => k.replace('T',' ') }, hourly: { keyFn: r => r.timestamp.slice(0,13), labelFn: k => k.replace('T',' ') },
daily: { keyFn: r => r.timestamp.slice(0,10), labelFn: k => k }, daily: { keyFn: r => r.timestamp.slice(0,10), labelFn: k => k },
@ -19,22 +21,62 @@ const periodConfig = {
}; };
// global Chart.js instance // global Chart.js instance
let trendChart; let trendChart, dataTable;
// fetch all readings // fetch readings from server
async function fetchReadings() { async function fetchReadings() {
const res = await fetch('/api/readings'); const res = await fetch('/api/readings');
return res.ok ? res.json() : []; return res.ok ? res.json() : [];
} }
// build or update chart // determine direction based on dock door #
function getDirection(dock) {
return ( (dock>=124 && dock<=138) || (dock>=202 && dock<=209) )
? 'Inbound'
: 'Outbound';
}
// render DataTable
function renderTable(allReadings) {
const tbody = $('#trendTable tbody').empty();
allReadings.forEach(r => {
const ts = new Date(r.timestamp).toLocaleString('en-US', { timeZone:'America/New_York' });
const dir = getDirection(r.dockDoor);
tbody.append(`
<tr>
<td>${ts}</td>
<td>${r.temperature.toFixed(1)}</td>
<td>${r.humidity.toFixed(1)}</td>
<td>${r.heatIndex.toFixed(1)}</td>
<td>${r.dockDoor}</td>
<td>${dir}</td>
</tr>
`);
});
// initialize or redraw DataTable
if ($.fn.DataTable.isDataTable('#trendTable')) {
dataTable.clear().rows.add($('#trendTable tbody tr')).draw();
} else {
dataTable = $('#trendTable').DataTable({
paging: true,
pageLength: 25,
ordering: true,
order: [[0,'desc']],
autoWidth: false,
scrollX: true
});
}
}
// draw or update chart
async function drawTrend() { async function drawTrend() {
const all = await fetchReadings(); const all = await fetchReadings();
const slider = document.getElementById('periodSlider'); const slider = document.getElementById('periodSlider');
const periodKey = periodKeys[slider.value]; const periodKey = periodKeys[slider.value];
const cfg = periodConfig[periodKey]; const cfg = periodConfig[periodKey];
// group and compute stats // group & stats
const groups = {}; const groups = {};
all.forEach(r => { all.forEach(r => {
const key = cfg.keyFn(r); const key = cfg.keyFn(r);
@ -74,10 +116,13 @@ async function drawTrend() {
} else { } else {
trendChart = new Chart(ctx, { trendChart = new Chart(ctx, {
type: 'line', type: 'line',
data: { labels: labels.map(cfg.labelFn), datasets }, data: {
labels: labels.map(cfg.labelFn),
datasets
},
options: { options: {
responsive: true, responsive: true,
maintainAspectRatio: false, // <<— ensure the canvas fills its container maintainAspectRatio: false,
plugins: { plugins: {
legend: { display: true }, legend: { display: true },
tooltip: { mode:'index', intersect:false }, tooltip: { mode:'index', intersect:false },
@ -93,17 +138,24 @@ async function drawTrend() {
} }
}); });
} }
// always update table below
renderTable(all);
} }
// wire up controls
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
// initial draw
drawTrend(); drawTrend();
// slider // slider
document.getElementById('periodSlider') document.getElementById('periodSlider')
.addEventListener('input', e => { .addEventListener('input', e => {
document.getElementById('periodLabel').textContent = periodLabels[e.target.value]; document.getElementById('periodLabel').textContent = periodLabels[e.target.value];
drawTrend(); drawTrend();
}); });
// toggles // toggles
document.querySelectorAll('#metricToggles input') document.querySelectorAll('#metricToggles input')
.forEach(chk => chk.addEventListener('change', drawTrend)); .forEach(chk => chk.addEventListener('change', drawTrend));
}); });