import { useMemo } from 'react' import Highcharts from 'highcharts' import HighchartsReact from 'highcharts-react-official' import { format } from 'date-fns' import { de } from 'date-fns/locale' import './WeatherDashboard.css' // Build-Informationen (werden beim Build eingef\u00fcgt) const buildDate = __BUILD_DATE__ const version = __VERSION__ // Deutsche Lokalisierung für Highcharts Highcharts.setOptions({ lang: { months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'], shortMonths: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'], weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'], resetZoom: 'Zoom zurücksetzen' }, time: { useUTC: false } }) const WeatherDashboard = ({ data }) => { // Daten vorbereiten und nach Zeit sortieren (älteste zuerst) const sortedData = useMemo(() => { return [...data].sort((a, b) => new Date(a.datetime) - new Date(b.datetime)) }, [data]) // Gemeinsame Chart-Optionen const getCommonOptions = () => ({ chart: { height: '50%', animation: false, backgroundColor: 'transparent' }, accessibility: { enabled: false }, credits: { enabled: false }, title: { text: null }, legend: { enabled: false }, tooltip: { shared: true, crosshairs: true, xDateFormat: '%d.%m.%Y %H:%M' }, plotOptions: { series: { marker: { enabled: false, states: { hover: { enabled: true, radius: 5 } } } } }, xAxis: { type: 'datetime', tickInterval: 4 * 3600 * 1000, // 4 Stunden in Millisekunden labels: { format: '{value:%H:%M}', align: 'center' }, gridLineWidth: 1, gridLineColor: 'rgba(0, 0, 0, 0.1)' }, yAxis: { gridLineColor: 'rgba(0, 0, 0, 0.05)' } }) // Temperatur Chart const temperatureOptions = useMemo(() => { const temps = sortedData.map(item => item.temperature) const min = Math.min(...temps) const max = Math.max(...temps) const range = max - min let yMin = min let yMax = max if (range < 10) { const center = (max + min) / 2 yMin = center - 5 yMax = center + 5 } return { ...getCommonOptions(), yAxis: { ...getCommonOptions().yAxis, title: { text: 'Temperatur (°C)' }, min: yMin, max: yMax }, series: [{ name: 'Temperatur', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.temperature]), color: 'rgb(255, 99, 132)', fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [ [0, 'rgba(255, 99, 132, 0.3)'], [1, 'rgba(255, 99, 132, 0.1)'] ] }, type: 'areaspline', threshold: null, tooltip: { valueSuffix: ' °C' } }] } }, [sortedData]) // Luftfeuchtigkeit Chart const humidityOptions = useMemo(() => ({ ...getCommonOptions(), yAxis: { ...getCommonOptions().yAxis, title: { text: 'Feuchte (%)' }, min: 40, max: 100 }, series: [{ name: 'Feuchte', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.humidity]), color: 'rgb(54, 162, 235)', fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [ [0, 'rgba(54, 162, 235, 0.3)'], [1, 'rgba(54, 162, 235, 0.1)'] ] }, type: 'area', tooltip: { valueSuffix: ' %' } }] }), [sortedData]) // Luftdruck Chart const pressureOptions = useMemo(() => { const pressures = sortedData.map(item => item.pressure) const min = Math.min(...pressures) const max = Math.max(...pressures) const range = max - min let yMin = min let yMax = max if (range < 40) { const center = (max + min) / 2 yMin = center - 20 yMax = center + 20 } return { ...getCommonOptions(), yAxis: { ...getCommonOptions().yAxis, title: { text: 'Luftdruck (hPa)' }, min: yMin, max: yMax }, series: [{ name: 'Luftdruck', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.pressure]), color: 'rgb(75, 192, 192)', fillColor: { linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 }, stops: [ [0, 'rgba(75, 192, 192, 0.3)'], [1, 'rgba(75, 192, 192, 0.1)'] ] }, type: 'area', tooltip: { valueSuffix: ' hPa' } }] } }, [sortedData]) // Regen Chart const rainOptions = useMemo(() => ({ ...getCommonOptions(), yAxis: { ...getCommonOptions().yAxis, title: { text: 'Regen (mm) / Rate (mm/h)' } }, series: [{ name: 'Regen', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.rain]), color: 'rgb(54, 162, 235)', fillColor: 'rgba(54, 162, 235, 0.3)', type: 'area', tooltip: { valueSuffix: ' mm' } }, { name: 'Regenrate', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.rain_rate]), color: 'rgb(59, 130, 246)', dashStyle: 'Dash', type: 'line', tooltip: { valueSuffix: ' mm/h' } }] }), [sortedData]) // Windgeschwindigkeit Chart const windSpeedOptions = useMemo(() => ({ ...getCommonOptions(), plotOptions: { series: { marker: { enabled: false }, lineWidth: 2 }, line: { step: 'left' // Keine Glättung } }, yAxis: { ...getCommonOptions().yAxis, title: { text: 'Windspeed (km/h)', style: { whiteSpace: 'nowrap' } } }, series: [{ name: 'Windgeschwindigkeit', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.wind_speed]), color: 'rgb(153, 102, 255)', fillColor: 'rgba(153, 102, 255, 0.1)', type: 'area', tooltip: { valueSuffix: ' km/h' } }, { name: 'Windböen', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.wind_gust]), color: 'rgb(255, 159, 64)', fillColor: 'rgba(255, 159, 64, 0.1)', type: 'area', tooltip: { valueSuffix: ' km/h' } }] }), [sortedData]) // Windrichtung Chart const windDirOptions = useMemo(() => ({ ...getCommonOptions(), plotOptions: { scatter: { marker: { enabled: true, radius: 2, states: { hover: { enabled: true, radius: 3 } } } } }, yAxis: { ...getCommonOptions().yAxis, title: { text: 'Windrichtung' }, min: 0, max: 360, tickInterval: 45, labels: { formatter: function() { const directions = { 0: 'N', 45: 'NO', 90: 'O', 135: 'SO', 180: 'S', 225: 'SW', 270: 'W', 315: 'NW', 360: 'N' } return directions[this.value] || '' } } }, series: [{ name: 'Windrichtung', data: sortedData.map(item => [new Date(item.datetime).getTime(), item.wind_dir]), color: 'rgb(54, 162, 235)', type: 'scatter', tooltip: { valueSuffix: ' °' } }] }), [sortedData]) // Aktuellste Werte für Übersicht const current = sortedData[sortedData.length - 1] || {} // Berechne Min/Max für den aktuellen Tag const todayStats = useMemo(() => { const now = new Date() const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()) const todayData = sortedData.filter(item => { const itemDate = new Date(item.datetime) return itemDate >= todayStart }) if (todayData.length === 0) { return { minTemp: null, maxTemp: null, minTempTime: null, maxTempTime: null, minHumidity: null, maxHumidity: null, minHumidityTime: null, maxHumidityTime: null, minPressure: null, maxPressure: null, minPressureTime: null, maxPressureTime: null } } // Temperatur const minTempItem = todayData.reduce((min, item) => item.temperature != null && (min === null || item.temperature < min.temperature) ? item : min, null) const maxTempItem = todayData.reduce((max, item) => item.temperature != null && (max === null || item.temperature > max.temperature) ? item : max, null) // Luftfeuchtigkeit const minHumidityItem = todayData.reduce((min, item) => item.humidity != null && (min === null || item.humidity < min.humidity) ? item : min, null) const maxHumidityItem = todayData.reduce((max, item) => item.humidity != null && (max === null || item.humidity > max.humidity) ? item : max, null) // Luftdruck const minPressureItem = todayData.reduce((min, item) => item.pressure != null && (min === null || item.pressure < min.pressure) ? item : min, null) const maxPressureItem = todayData.reduce((max, item) => item.pressure != null && (max === null || item.pressure > max.pressure) ? item : max, null) // Windgeschwindigkeit const maxWindGustItem = todayData.reduce((max, item) => item.wind_gust != null && (max === null || item.wind_gust > max.wind_gust) ? item : max, null) return { minTemp: minTempItem?.temperature ?? null, maxTemp: maxTempItem?.temperature ?? null, minTempTime: minTempItem ? format(new Date(minTempItem.datetime), 'HH:mm', { locale: de }) : null, maxTempTime: maxTempItem ? format(new Date(maxTempItem.datetime), 'HH:mm', { locale: de }) : null, minHumidity: minHumidityItem?.humidity ?? null, maxHumidity: maxHumidityItem?.humidity ?? null, minHumidityTime: minHumidityItem ? format(new Date(minHumidityItem.datetime), 'HH:mm', { locale: de }) : null, maxHumidityTime: maxHumidityItem ? format(new Date(maxHumidityItem.datetime), 'HH:mm', { locale: de }) : null, minPressure: minPressureItem?.pressure ?? null, maxPressure: maxPressureItem?.pressure ?? null, minPressureTime: minPressureItem ? format(new Date(minPressureItem.datetime), 'HH:mm', { locale: de }) : null, maxPressureTime: maxPressureItem ? format(new Date(maxPressureItem.datetime), 'HH:mm', { locale: de }) : null, maxWindGust: maxWindGustItem?.wind_gust ?? null, maxWindGustTime: maxWindGustItem ? format(new Date(maxWindGustItem.datetime), 'HH:mm', { locale: de }) : null } }, [sortedData]) return (