diff --git a/data_visualization/js/app.js b/data_visualization/js/app.js new file mode 100644 index 0000000..d1ae74e --- /dev/null +++ b/data_visualization/js/app.js @@ -0,0 +1,173 @@ +import { fetchSensorData } from './api.js'; + +/** + * @typedef {Object} SensorData + * @property {string} timestamp + * @property {string} location_id + * @property {number} temperature + * @property {number} humidity + * @property {number} light + */ + +let allData = []; +let chartInstances = {}; + +/** + * Initialisiert UI-Elemente, ruft Daten ab und rendert Diagramme. + * Wird beim Laden des Fensters aufgerufen. + */ +export async function initApp() { + try { + const data = await fetchSensorData(); + if (!Array.isArray(data)) { + console.error('Ungültige Datenstruktur von /data'); + return; + } + allData = data; + initializeFilters(); + renderCharts(data); + } catch (error) { + console.error('Fehler beim Initialisieren der Anwendung:', error); + } +} + +/** + * Initialisiert Datumsauswahl- und Filter-Events. + */ +function initializeFilters() { + const startInput = document.getElementById('filter-start'); + const endInput = document.getElementById('filter-end'); + + [startInput, endInput].forEach((input) => { + if (input) { + input.addEventListener('change', () => { + const startDate = new Date(startInput?.value); + const endDate = new Date(endInput?.value); + const filtered = filterDataByDate(allData, startDate, endDate); + updateCharts(filtered); + }); + } + }); +} + +/** + * Filtert Daten basierend auf Start- und Enddatum. + * @param {SensorData[]} data + * @param {Date} start + * @param {Date} end + * @returns {SensorData[]} + */ +function filterDataByDate(data, start, end) { + if (!(start instanceof Date) || !(end instanceof Date)) return data; + return data.filter(({ timestamp }) => { + const t = new Date(timestamp); + return t >= start && t <= end; + }); +} + +/** + * Rendert initiale Diagramme. + * @param {SensorData[]} data + */ +function renderCharts(data) { + const ctxTemp = document.getElementById('chart-temperature'); + const ctxHum = document.getElementById('chart-humidity'); + const ctxLight = document.getElementById('chart-light'); + + const timestamps = data.map(d => new Date(d.timestamp).toLocaleTimeString()); + + chartInstances.temperature = new Chart(ctxTemp, { + type: 'line', + data: { + labels: timestamps, + datasets: [{ + label: 'Temperatur (°C)', + data: data.map(d => d.temperature), + borderColor: '#FF5733', + backgroundColor: 'rgba(255, 87, 51, 0.1)', + tension: 0.3, + }] + }, + options: baseChartOptions('Temperaturverlauf') + }); + + chartInstances.humidity = new Chart(ctxHum, { + type: 'line', + data: { + labels: timestamps, + datasets: [{ + label: 'Feuchtigkeit (%)', + data: data.map(d => d.humidity), + borderColor: '#33A1FF', + backgroundColor: 'rgba(51, 161, 255, 0.1)', + tension: 0.3, + }] + }, + options: baseChartOptions('Feuchtigkeitsverlauf') + }); + + chartInstances.light = new Chart(ctxLight, { + type: 'line', + data: { + labels: timestamps, + datasets: [{ + label: 'Lichtintensität (lx)', + data: data.map(d => d.light), + borderColor: '#FFC300', + backgroundColor: 'rgba(255, 195, 0, 0.1)', + tension: 0.3, + }] + }, + options: baseChartOptions('Lichtintensität') + }); +} + +/** + * Options-Vorlage für Diagramme. + * @param {string} title + * @returns {object} + */ +function baseChartOptions(title) { + return { + responsive: true, + maintainAspectRatio: false, + interaction: { mode: 'index', intersect: false }, + plugins: { + title: { display: true, text: title }, + tooltip: { enabled: true }, + legend: { display: true } + }, + scales: { + x: { display: true, title: { display: true, text: 'Zeit' } }, + y: { display: true } + } + }; +} + +/** + * Aktualisiert Diagramme auf Basis neuer Filter oder Daten. + * @param {SensorData[]} filteredData + */ +export function updateCharts(filteredData) { + const timestamps = filteredData.map(d => new Date(d.timestamp).toLocaleTimeString()); + + if (chartInstances.temperature) { + chartInstances.temperature.data.labels = timestamps; + chartInstances.temperature.data.datasets[0].data = filteredData.map(d => d.temperature); + chartInstances.temperature.update(); + } + + if (chartInstances.humidity) { + chartInstances.humidity.data.labels = timestamps; + chartInstances.humidity.data.datasets[0].data = filteredData.map(d => d.humidity); + chartInstances.humidity.update(); + } + + if (chartInstances.light) { + chartInstances.light.data.labels = timestamps; + chartInstances.light.data.datasets[0].data = filteredData.map(d => d.light); + chartInstances.light.update(); + } +} + +window.addEventListener('load', initApp); \ No newline at end of file