langzeitbelichtung_nachtfot.../data_visualization/js/ui.js

152 lines
4.7 KiB
JavaScript

/* UI Logic for temperature and image rendering */
/**
* Render a temperature line chart in the #temperature-chart container.
* @param {Array<{timestamp: string, value: number}>} temperatures
*/
export function renderChart(temperatures) {
const container = document.querySelector('#temperature-chart');
if (!container) return;
container.innerHTML = '';
const canvas = document.createElement('canvas');
canvas.setAttribute('role', 'img');
canvas.setAttribute('aria-label', 'Temperaturverlauf');
canvas.width = container.clientWidth;
canvas.height = 200;
container.appendChild(canvas);
const ctx = canvas.getContext('2d');
if (!ctx || temperatures.length === 0) return;
const values = temperatures.map(t => t.value);
const minVal = Math.min(...values);
const maxVal = Math.max(...values);
const range = maxVal - minVal || 1;
ctx.strokeStyle = '#2196f3';
ctx.lineWidth = 2;
ctx.beginPath();
temperatures.forEach((t, i) => {
const x = (i / (temperatures.length - 1)) * canvas.width;
const y = canvas.height - ((t.value - minVal) / range) * canvas.height;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
});
ctx.stroke();
}
/**
* Render an interactive image gallery.
* @param {Array<{filename: string, timestamp: string, metadata?: object}>} images
*/
export function renderGallery(images) {
const container = document.querySelector('#image-gallery');
if (!container) return;
container.innerHTML = '';
const galleryGrid = document.createElement('div');
galleryGrid.classList.add('gallery-grid');
images.forEach((imgData, index) => {
const imgEl = document.createElement('div');
imgEl.classList.add('gallery-item');
imgEl.tabIndex = 0;
imgEl.setAttribute('role', 'button');
imgEl.setAttribute('aria-label', `Bild ${index + 1}`);
imgEl.style.backgroundColor = '#e0e0e0';
imgEl.style.display = 'flex';
imgEl.style.alignItems = 'center';
imgEl.style.justifyContent = 'center';
imgEl.style.height = '100px';
imgEl.textContent = `Bild ${index + 1}`;
imgEl.addEventListener('click', () => openImageModal(imgData));
imgEl.addEventListener('keypress', e => {
if (e.key === 'Enter' || e.key === ' ') {
openImageModal(imgData);
}
});
galleryGrid.appendChild(imgEl);
});
container.appendChild(galleryGrid);
}
/**
* Display a modal view for a selected image (textual substitute, no actual image).
* @param {{filename: string, timestamp: string, metadata?: object}} imgData
*/
function openImageModal(imgData) {
let modal = document.querySelector('#image-modal');
if (!modal) {
modal = document.createElement('div');
modal.id = 'image-modal';
modal.setAttribute('role', 'dialog');
modal.setAttribute('aria-modal', 'true');
modal.style.position = 'fixed';
modal.style.top = 0;
modal.style.left = 0;
modal.style.right = 0;
modal.style.bottom = 0;
modal.style.background = 'rgba(0,0,0,0.8)';
modal.style.color = '#fff';
modal.style.display = 'flex';
modal.style.alignItems = 'center';
modal.style.justifyContent = 'center';
const content = document.createElement('div');
content.classList.add('modal-content');
content.style.padding = '1rem';
content.style.background = '#111';
content.style.maxWidth = '90%';
content.style.textAlign = 'center';
const closeBtn = document.createElement('button');
closeBtn.textContent = 'Schließen';
closeBtn.style.marginTop = '1rem';
closeBtn.addEventListener('click', () => {
modal.remove();
});
modal.appendChild(content);
content.appendChild(closeBtn);
document.body.appendChild(modal);
}
const content = modal.querySelector('.modal-content');
if (content) {
content.innerHTML = `<h2>Bild: ${imgData.filename}</h2><p>Aufgenommen: ${imgData.timestamp}</p>`;
const closeBtn = document.createElement('button');
closeBtn.textContent = 'Schließen';
closeBtn.style.marginTop = '1rem';
closeBtn.addEventListener('click', () => modal.remove());
content.appendChild(closeBtn);
}
}
/**
* Update summary statistics for displayed data.
* @param {Array<{timestamp: string, value: number}>} temperatures
* @param {Array<{filename: string, timestamp: string}>} images
*/
export function updateStats(temperatures, images) {
const container = document.querySelector('#summary-stats');
if (!container) return;
container.innerHTML = '';
const avgTemp =
temperatures.length > 0
? (temperatures.reduce((sum, t) => sum + t.value, 0) / temperatures.length).toFixed(2)
: 'N/A';
const imgCount = images.length;
const statsText = `Durchschnittstemperatur: ${avgTemp}°C | Bilder: ${imgCount}`;
container.textContent = statsText;
}