Add data_visualization/js/ui.js
This commit is contained in:
parent
160c6db0dc
commit
acac0c44da
1 changed files with 136 additions and 0 deletions
136
data_visualization/js/ui.js
Normal file
136
data_visualization/js/ui.js
Normal file
|
|
@ -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 = `
|
||||
<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);
|
||||
});
|
||||
});
|
||||
}
|
||||
Loading…
Reference in a new issue