136 lines
4.6 KiB
JavaScript
136 lines
4.6 KiB
JavaScript
/* 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 = `
|
||
<span style="color:#e74c3c">Temperatur</span> |
|
||
<span style="color:#3498db">Wind</span> |
|
||
<span style="color:#2ecc71">Feuchtigkeit</span>
|
||
`;
|
||
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);
|
||
});
|
||
});
|
||
}
|