diff --git a/data_visualization/js/ui.js b/data_visualization/js/ui.js new file mode 100644 index 0000000..652b066 --- /dev/null +++ b/data_visualization/js/ui.js @@ -0,0 +1,136 @@ +/* ui.js — Verantwortlich für DOM-Manipulation und UI-Rendering */ + +/** + * Rendert interaktive Diagramme für Umweltdaten. + * @param {Array<{timestamp: string, temperature: number, wind_speed: number, humidity: number}>} data - API Response von /data + */ +export function renderCharts(data) { + const chartContainer = document.querySelector('#data-charts'); + if (!chartContainer) return; + chartContainer.innerHTML = ''; + + if (!Array.isArray(data) || data.length === 0) { + const msg = document.createElement('p'); + msg.textContent = 'Keine Daten verfügbar'; + chartContainer.appendChild(msg); + return; + } + + // Grundstruktur für Canvas-Diagramme + const canvas = document.createElement('canvas'); + canvas.setAttribute('aria-label', 'Umweltdaten Diagramm'); + canvas.setAttribute('role', 'img'); + chartContainer.appendChild(canvas); + + // Beispielhafte Nutzung von Chart.js oder ähnlicher Logik (ohne externe Ressourcen) + // Zur Vereinfachung: Darstellung als einfache Linien mit Canvas API + const ctx = canvas.getContext('2d'); + const width = chartContainer.clientWidth; + const height = 200; + canvas.width = width; + canvas.height = height; + + ctx.clearRect(0, 0, width, height); + + const temperatures = data.map(d => d.temperature); + const winds = data.map(d => d.wind_speed); + const hums = data.map(d => d.humidity); + + const maxTemp = Math.max(...temperatures, 1); + const maxWind = Math.max(...winds, 1); + const maxHum = Math.max(...hums, 1); + + const step = width / (data.length - 1); + + // Hilfsfunktion zum Zeichnen von Linien + const drawLine = (values, color, maxVal) => { + ctx.beginPath(); + ctx.strokeStyle = color; + ctx.lineWidth = 2; + values.forEach((val, i) => { + const x = i * step; + const y = height - (val / maxVal) * height; + if (i === 0) { + ctx.moveTo(x, y); + } else { + ctx.lineTo(x, y); + } + }); + ctx.stroke(); + }; + + drawLine(temperatures, '#e74c3c', maxTemp); // rot für Temp + drawLine(winds, '#3498db', maxWind); // blau für Wind + drawLine(hums, '#2ecc71', maxHum); // grün für Luftfeuchte + + const legend = document.createElement('div'); + legend.className = 'chart-legend'; + legend.innerHTML = ` + Temperatur | + Wind | + Feuchtigkeit + `; + chartContainer.appendChild(legend); +} + +/** + * Rendert eine Galerie aus Bilddaten. + * @param {Array<{url: string, capture_time: string, analysis_result: string}>} images - API Response von /images + */ +export function renderGallery(images) { + const galleryContainer = document.querySelector('#image-gallery'); + if (!galleryContainer) return; + galleryContainer.innerHTML = ''; + + if (!Array.isArray(images) || images.length === 0) { + const msg = document.createElement('p'); + msg.textContent = 'Keine Bilddaten verfügbar'; + galleryContainer.appendChild(msg); + return; + } + + images.forEach(imgData => { + const wrapper = document.createElement('div'); + wrapper.className = 'gallery-item'; + + const figure = document.createElement('figure'); + + const thumb = document.createElement('div'); + thumb.className = 'image-thumb'; + thumb.tabIndex = 0; + thumb.setAttribute('role', 'button'); + thumb.setAttribute('aria-label', `Bild aufgenommen am ${imgData.capture_time}`); + + // Bilddarstellung über CSS background-image, da keine externen Bilddateien verwendet werden dürfen + thumb.style.background = '#ccc'; // Platzhalter, da keine echten Bilder geladen werden dürfen + + const caption = document.createElement('figcaption'); + caption.textContent = `${imgData.capture_time} – ${imgData.analysis_result}`; + + figure.appendChild(thumb); + figure.appendChild(caption); + wrapper.appendChild(figure); + galleryContainer.appendChild(wrapper); + + // Interaktive Zoomfunktion (nur symbolisch) + thumb.addEventListener('click', () => { + const expanded = document.createElement('div'); + expanded.className = 'overlay'; + expanded.setAttribute('role', 'dialog'); + expanded.setAttribute('aria-modal', 'true'); + + const expandedContent = document.createElement('div'); + expandedContent.className = 'overlay-content'; + expandedContent.style.background = '#999'; // Platzhalter für Zoom-Bild + + const closeBtn = document.createElement('button'); + closeBtn.textContent = 'Schließen'; + closeBtn.className = 'close-button'; + closeBtn.addEventListener('click', () => expanded.remove()); + + expanded.appendChild(expandedContent); + expanded.appendChild(closeBtn); + document.body.appendChild(expanded); + }); + }); +}