"use strict"; /** * UI Logic for Data Visualization * Handles rendering charts, updating stats, and applying filters. */ import { fetchData } from './api.js'; /** * @typedef {Object} SensorData * @property {string} timestamp - ISO time string * @property {number} intensity - Measured light intensity * @property {number} wavelength - Light wavelength in nm * @property {string} sensor_id - Identifier of the sensor */ /** * Renders chart visualization inside the DOM element with id 'chart-container'. * @param {SensorData[]} dataArray */ export function renderChart(dataArray) { const container = document.getElementById('chart-container'); if (!container) return; container.innerHTML = ''; // Create canvas for chart const canvas = document.createElement('canvas'); canvas.setAttribute('role', 'img'); canvas.setAttribute('aria-label', 'Diagramm der Intensitätswerte über Zeit'); container.appendChild(canvas); const ctx = canvas.getContext('2d'); const timestamps = dataArray.map(d => new Date(d.timestamp).toLocaleTimeString()); const intensities = dataArray.map(d => d.intensity); // Chart.js-like pseudo implementation (no external lib) ctx.beginPath(); const maxIntensity = Math.max(...intensities, 1); const minIntensity = Math.min(...intensities, 0); const width = canvas.width = container.offsetWidth; const height = canvas.height = Math.min(400, container.offsetHeight || 300); ctx.strokeStyle = '#007acc'; ctx.lineWidth = 2; intensities.forEach((value, i) => { const x = (i / (intensities.length - 1)) * width; const y = height - ((value - minIntensity) / (maxIntensity - minIntensity)) * height; if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y); }); ctx.stroke(); updateSummary(dataArray); } /** * Updates statistics panel with calculated summary data. * @param {SensorData[]} dataArray */ export function updateSummary(dataArray) { const avg = dataArray.length ? dataArray.reduce((acc, d) => acc + d.intensity, 0) / dataArray.length : 0; const max = dataArray.length ? Math.max(...dataArray.map(d => d.intensity)) : 0; const min = dataArray.length ? Math.min(...dataArray.map(d => d.intensity)) : 0; const summaryEl = document.getElementById('summary-panel'); if (!summaryEl) return; summaryEl.innerHTML = `
Durchschnitt: ${avg.toFixed(2)}
Max: ${max.toFixed(2)}
Min: ${min.toFixed(2)}
`; } /** * Reads filter form values and triggers data reload. */ export async function applyFilters() { const sensorSelect = document.getElementById('filter-sensor'); const timeStart = document.getElementById('filter-start'); const timeEnd = document.getElementById('filter-end'); const params = {}; if (sensorSelect?.value) params.sensor = sensorSelect.value; if (timeStart?.value) params.start = timeStart.value; if (timeEnd?.value) params.end = timeEnd.value; const data = await fetchData(params).catch(() => []); renderChart(data); } /** * Binds UI event handlers. */ export function bindUIEvents() { const form = document.getElementById('filter-form'); if (form) { form.addEventListener('submit', e => { e.preventDefault(); applyFilters(); }); } } // Auto-bind when DOM is ready document.addEventListener('DOMContentLoaded', () => { bindUIEvents(); });