Pollution Levels Dashboard

Pollution Levels Dashboard

Monitor Air, Water, and Soil Pollution Data.

Current Average Levels

Pollutant Levels Over Time

Readings by Pollution Type

Recent Readings Log

Date Location Type Metric Value

Enter Pollution Readings

${avgWater.toFixed(1)} ppb

Soil Quality (Nitrates)

${avgSoil.toFixed(1)} mg/kg

`; }; const renderDataTable = () => { dataTableBody.innerHTML = ''; const sortedReadings = [...state.readings].sort((a, b) => new Date(b.date) - new Date(a.date)); sortedReadings.forEach(r => { const row = ` ${r.date} ${r.location} ${r.type} ${r.metric} ${r.value} ${r.unit} `; dataTableBody.innerHTML += row; }); }; const renderCharts = () => { // Trend Chart const sortedReadings = [...state.readings].sort((a, b) => new Date(a.date) - new Date(b.date)); const airData = sortedReadings.filter(r => r.metric === 'PM2.5').map(r => ({x: r.date, y: r.value})); const waterData = sortedReadings.filter(r => r.metric === 'Lead').map(r => ({x: r.date, y: r.value})); if (trendChart) trendChart.destroy(); trendChart = new Chart(trendCanvas.getContext('2d'), { type: 'line', data: { datasets: [ { label: 'Air (PM2.5)', data: airData, borderColor: '#38bdf8', yAxisID: 'yAir' }, { label: 'Water (Lead)', data: waterData, borderColor: '#60a5fa', yAxisID: 'yWater' } ] }, options: { responsive: true, maintainAspectRatio: false, scales: { x: { type: 'time', time: { unit: 'day' } }, yAir: { type: 'linear', position: 'left', title: {display: true, text: 'µg/m³'} }, yWater: { type: 'linear', position: 'right', title: {display: true, text: 'ppb'}, grid: {drawOnChartArea: false} } } } }); // Type Chart const readingsByType = state.readings.reduce((acc, r) => { acc[r.type] = (acc[r.type] || 0) + 1; return acc; }, {}); const typeLabels = Object.keys(readingsByType); const typeData = typeLabels.map(label => readingsByType[label]); if (typeChart) typeChart.destroy(); typeChart = new Chart(typeCanvas.getContext('2d'), { type: 'pie', data: { labels: typeLabels, datasets: [{ data: typeData, backgroundColor: ['#7dd3fc', '#93c5fd', '#fcd34d'] }] }, options: { responsive: true, maintainAspectRatio: false, plugins: { legend: { position: 'top' } } } }); }; const renderConfigRows = () => { configRowsContainer.innerHTML = ''; const sortedReadings = [...state.readings].sort((a,b) => b.id - a.id); sortedReadings.forEach(r => { configRowsContainer.innerHTML += `
`.replaceAll('class="config-input"', 'class="config-input w-full border-gray-300 rounded-md shadow-sm"'); }); addConfigEventListeners(); }; // --- EVENT HANDLERS --- const handleConfigChange = (e) => { const id = parseInt(e.target.dataset.id); const field = e.target.dataset.field; const value = (e.target.type === 'number') ? parseFloat(e.target.value) || 0 : e.target.value; const reading = state.readings.find(r => r.id === id); if (reading) reading[field] = value; renderAll(); }; const handleAddLog = () => { const newId = state.readings.length > 0 ? Math.max(...state.readings.map(l => l.id)) + 1 : 1; const today = new Date().toISOString().split('T')[0]; state.readings.push({ id: newId, date: today, location: "New Location", type: "Air", metric: "PM2.5", value: 0, unit: "µg/m³" }); renderAll(); }; const handleRemoveLog = (e) => { const id = parseInt(e.target.dataset.id); state.readings = state.readings.filter(r => r.id !== id); renderAll(); }; const addConfigEventListeners = () => { document.querySelectorAll('.config-input').forEach(input => input.addEventListener('change', handleConfigChange)); document.querySelectorAll('.remove-btn').forEach(button => button.addEventListener('click', handleRemoveLog)); }; const handleDownloadPdf = () => { const { jsPDF } = window.jspdf; const pdfContent = document.getElementById('pdf-content'); document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'hidden'); Chart.defaults.animation = false; html2canvas(pdfContent, { scale: 2, useCORS: true, backgroundColor: '#ffffff' }).then(canvas => { document.querySelectorAll('.no-print').forEach(el => el.style.visibility = 'visible'); Chart.defaults.animation = true; const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const imgWidth = pdfWidth - 20; const imgHeight = canvas.height * imgWidth / canvas.width; pdf.addImage(imgData, 'PNG', 10, 10, imgWidth, imgHeight); pdf.save('Pollution-Levels-Dashboard.pdf'); }); }; // --- TABBING LOGIC --- let currentTabIndex = 0; const updateTabButtons = () => { prevTabBtn.disabled = currentTabIndex === 0; nextTabBtn.disabled = currentTabIndex === tabContents.length - 1; }; const switchTab = (index) => { tabButtons.forEach(btn => btn.classList.remove('active')); tabContents.forEach(content => content.classList.remove('active')); tabButtons[index].classList.add('active'); tabContents[index].classList.add('active'); currentTabIndex = index; updateTabButtons(); }; tabButtons.forEach((button, index) => button.addEventListener('click', () => switchTab(index))); prevTabBtn.addEventListener('click', () => { if (currentTabIndex > 0) switchTab(currentTabIndex - 1); }); nextTabBtn.addEventListener('click', () => { if (currentTabIndex < tabContents.length - 1) switchTab(currentTabIndex + 1); }); // --- INITIALIZATION --- if (kpiContainer && addLogBtn && downloadPdfBtn) { addLogBtn.addEventListener('click', handleAddLog); downloadPdfBtn.addEventListener('click', handleDownloadPdf); renderAll(); updateTabButtons(); } else { console.error("Essential dashboard elements could not be found."); } });
Scroll to Top