donau2space_experiment/data_visualization/js/ui.js

136 lines
4.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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);
});
});
}