diff --git a/data_visualization/js/app.js b/data_visualization/js/app.js new file mode 100644 index 0000000..93ee0a3 --- /dev/null +++ b/data_visualization/js/app.js @@ -0,0 +1,122 @@ +'use strict'; + +/** + * Haupt-Einstiegspunkt der Anwendung zur Echtzeit-Visualisierung der WLAN-Daten. + * Initialisiert DOM, Heatmap und Event-Listener. + */ + +/** + * Globale Referenzen auf DOM-Elemente und State-Objekte. + * @type {{ heatmapContainer: HTMLElement|null, refreshButton: HTMLElement|null, statsContainer: HTMLElement|null, heatmapInstance: any|null }} + */ +const appState = { + heatmapContainer: null, + refreshButton: null, + statsContainer: null, + heatmapInstance: null +}; + +/** + * Initialisiert UI und Listener. + */ +export async function initApp() { + appState.heatmapContainer = document.getElementById('heatmap'); + appState.refreshButton = document.getElementById('refresh-btn'); + appState.statsContainer = document.getElementById('stats'); + + if (!appState.heatmapContainer) { + console.error('Heatmap-Container nicht gefunden.'); + return; + } + + // Dummy Heatmap-Struktur initialisieren (z. B. Leaflet oder einfache Canvas-basierte Heatmap) + appState.heatmapInstance = createHeatmap(appState.heatmapContainer); + + // Events + if (appState.refreshButton) { + appState.refreshButton.addEventListener('click', refreshData); + } + + // Periodische Datenaktualisierung starten + setInterval(refreshData, 15000); + + // Initial einmal rendern + await refreshData(); +} + +/** + * Lädt neue Daten und aktualisiert die Heatmap. + */ +export async function refreshData() { + try { + // Beispiel: lokale Datenquelle; später durch echte API ersetzt + const response = await fetch('data/heatmap_data.json'); + if (!response.ok) throw new Error('Fehler beim Laden der Heatmap-Daten'); + + /** @type {{ points: Array<{lat: number, lng: number, rssi: number}>, stats: {min: number, max: number, avg: number} }} */ + const data = await response.json(); + + if (appState.heatmapInstance && data?.points) { + updateHeatmap(appState.heatmapInstance, data.points); + renderStats(data.stats); + } + } catch (error) { + console.error('refreshData Fehler:', error); + } +} + +/** + * Erstellt eine einfache Heatmap-Instanz. + * @param {HTMLElement} container + * @returns {object} + */ +function createHeatmap(container) { + // Platzhalter für echtes Heatmap-Rendering-Objekt + const layer = document.createElement('div'); + layer.className = 'heatmap__layer'; + container.appendChild(layer); + + return { + container: layer, + data: [], + render(points) { + // Primitive Darstellung: Größe oder Farbe anhand RSSI simulieren + layer.innerHTML = ''; + points.forEach(p => { + const point = document.createElement('div'); + point.className = 'heatmap__point'; + const intensity = Math.max(0, Math.min(1, (100 + p.rssi) / 100)); + point.style.opacity = intensity.toFixed(2); + point.style.left = `${(p.lng % 1) * 100}%`; + point.style.top = `${(p.lat % 1) * 100}%`; + layer.appendChild(point); + }); + } + }; +} + +/** + * Aktualisiert die Heatmap-Daten und rendert neu. + * @param {object} heatmapInstance + * @param {Array<{lat: number, lng: number, rssi: number}>} points + */ +function updateHeatmap(heatmapInstance, points) { + heatmapInstance.data = points; + heatmapInstance.render(points); +} + +/** + * Rendert einfache Statistik-Anzeige. + * @param {{min: number, max: number, avg: number}} stats + */ +function renderStats(stats) { + if (!appState.statsContainer) return; + appState.statsContainer.innerHTML = ` +
Min: ${stats.min?.toFixed(1) ?? '–'} dBm
+Max: ${stats.max?.toFixed(1) ?? '–'} dBm
+Ø: ${stats.avg?.toFixed(1) ?? '–'} dBm
+ `; +} + +// Einstiegspunkt beim Laden +window.addEventListener('load', initApp); \ No newline at end of file