fix: Datenlücken in Charts korrekt darstellen, Version 1.5.1
- withGaps()-Hilfsfunktion: fügt null-Punkte bei Datenlücken ein - Betrifft: Temperatur, Luftdruck, Feuchte, Wind, Böen - restore-db.sh: mapfile durch while-read ersetzt (zsh-kompatibel)
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "wetterstation-frontend",
|
"name": "wetterstation-frontend",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.5.0",
|
"version": "1.5.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useMemo, useState } from 'react'
|
import { useMemo, useState, useCallback } from 'react'
|
||||||
import Highcharts from 'highcharts'
|
import Highcharts from 'highcharts'
|
||||||
import { HighchartsReact } from 'highcharts-react-official'
|
import { HighchartsReact } from 'highcharts-react-official'
|
||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
@@ -24,6 +24,24 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
// State für Anleitung
|
// State für Anleitung
|
||||||
const [showAnleitung, setShowAnleitung] = useState(false)
|
const [showAnleitung, setShowAnleitung] = useState(false)
|
||||||
|
|
||||||
|
// Schwellwert für Datenlücken (abhängig vom Zeitraum)
|
||||||
|
const gapThresholdMs = useMemo(() => {
|
||||||
|
if (timeRange === '24h') return 2 * 60 * 60 * 1000 // 2 Stunden
|
||||||
|
return 1.5 * 24 * 3600 * 1000 // 1,5 Tage
|
||||||
|
}, [timeRange])
|
||||||
|
|
||||||
|
// Fügt null-Einträge in Lücken ein, damit Highcharts die Linie unterbricht
|
||||||
|
const withGaps = useCallback((pairs) => {
|
||||||
|
const result = []
|
||||||
|
for (let i = 0; i < pairs.length; i++) {
|
||||||
|
result.push(pairs[i])
|
||||||
|
if (i < pairs.length - 1 && pairs[i + 1][0] - pairs[i][0] > gapThresholdMs) {
|
||||||
|
result.push([(pairs[i][0] + pairs[i + 1][0]) / 2, null])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}, [gapThresholdMs])
|
||||||
|
|
||||||
// State für benutzerdefinierten Zeitbereich
|
// State für benutzerdefinierten Zeitbereich
|
||||||
const [showCustomRangeModal, setShowCustomRangeModal] = useState(false)
|
const [showCustomRangeModal, setShowCustomRangeModal] = useState(false)
|
||||||
const [customStartDate, setCustomStartDate] = useState('')
|
const [customStartDate, setCustomStartDate] = useState('')
|
||||||
@@ -405,7 +423,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Maximaltemperatur',
|
name: 'Maximaltemperatur',
|
||||||
data: sortedData.filter(item => item.max_temperature != null).map(item => [new Date(item.datetime).getTime(), item.max_temperature]),
|
data: withGaps(sortedData.filter(item => item.max_temperature != null).map(item => [new Date(item.datetime).getTime(), item.max_temperature])),
|
||||||
color: 'rgb(255, 99, 132)',
|
color: 'rgb(255, 99, 132)',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
lineWidth: 2,
|
lineWidth: 2,
|
||||||
@@ -419,7 +437,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Minimaltemperatur',
|
name: 'Minimaltemperatur',
|
||||||
data: sortedData.filter(item => item.min_temperature != null).map(item => [new Date(item.datetime).getTime(), item.min_temperature]),
|
data: withGaps(sortedData.filter(item => item.min_temperature != null).map(item => [new Date(item.datetime).getTime(), item.min_temperature])),
|
||||||
color: 'rgb(54, 162, 235)',
|
color: 'rgb(54, 162, 235)',
|
||||||
type: 'line',
|
type: 'line',
|
||||||
lineWidth: 2,
|
lineWidth: 2,
|
||||||
@@ -461,7 +479,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Temperatur',
|
name: 'Temperatur',
|
||||||
data: sortedData.filter(item => item.temperature != null).map(item => [new Date(item.datetime).getTime(), item.temperature]),
|
data: withGaps(sortedData.filter(item => item.temperature != null).map(item => [new Date(item.datetime).getTime(), item.temperature])),
|
||||||
color: 'rgb(255, 99, 132)',
|
color: 'rgb(255, 99, 132)',
|
||||||
fillColor: {
|
fillColor: {
|
||||||
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
|
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
|
||||||
@@ -481,7 +499,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}, [sortedData, temperatureSuffix, timeRange])
|
}, [sortedData, temperatureSuffix, timeRange, withGaps])
|
||||||
|
|
||||||
// Luftfeuchtigkeit Chart
|
// Luftfeuchtigkeit Chart
|
||||||
const humidityOptions = useMemo(() => {
|
const humidityOptions = useMemo(() => {
|
||||||
@@ -497,7 +515,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Feuchte',
|
name: 'Feuchte',
|
||||||
data: sortedData.filter(item => item.humidity != null).map(item => [new Date(item.datetime).getTime(), item.humidity]),
|
data: withGaps(sortedData.filter(item => item.humidity != null).map(item => [new Date(item.datetime).getTime(), item.humidity])),
|
||||||
color: 'rgb(54, 162, 235)',
|
color: 'rgb(54, 162, 235)',
|
||||||
fillColor: {
|
fillColor: {
|
||||||
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
|
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
|
||||||
@@ -516,7 +534,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}, [sortedData, timeRange])
|
}, [sortedData, timeRange, withGaps])
|
||||||
|
|
||||||
// Luftdruck Chart
|
// Luftdruck Chart
|
||||||
const pressureOptions = useMemo(() => {
|
const pressureOptions = useMemo(() => {
|
||||||
@@ -545,7 +563,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: 'Luftdruck',
|
name: 'Luftdruck',
|
||||||
data: sortedData.filter(item => item.pressure != null).map(item => [new Date(item.datetime).getTime(), item.pressure]),
|
data: withGaps(sortedData.filter(item => item.pressure != null).map(item => [new Date(item.datetime).getTime(), item.pressure])),
|
||||||
color: 'rgb(75, 192, 192)',
|
color: 'rgb(75, 192, 192)',
|
||||||
fillColor: {
|
fillColor: {
|
||||||
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
|
linearGradient: { x1: 0, y1: 0, x2: 0, y2: 1 },
|
||||||
@@ -564,7 +582,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}, [sortedData, timeRange])
|
}, [sortedData, timeRange, withGaps])
|
||||||
|
|
||||||
// Regen Chart (angepasst an Zeitraum)
|
// Regen Chart (angepasst an Zeitraum)
|
||||||
const rainOptions = useMemo(() => {
|
const rainOptions = useMemo(() => {
|
||||||
@@ -645,7 +663,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
},
|
},
|
||||||
series
|
series
|
||||||
}
|
}
|
||||||
}, [sortedData, rainData, timeRange])
|
}, [sortedData, rainData, timeRange, withGaps])
|
||||||
|
|
||||||
// Windgeschwindigkeit Chart
|
// Windgeschwindigkeit Chart
|
||||||
const windSpeedOptions = useMemo(() => {
|
const windSpeedOptions = useMemo(() => {
|
||||||
@@ -655,9 +673,9 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
const hideGusts = (timeRange === '365d') || (isCustomRange && customDays >= 365)
|
const hideGusts = (timeRange === '365d') || (isCustomRange && customDays >= 365)
|
||||||
const windSpeedSeries = {
|
const windSpeedSeries = {
|
||||||
name: 'Windgeschwindigkeit',
|
name: 'Windgeschwindigkeit',
|
||||||
data: sortedData
|
data: withGaps(sortedData
|
||||||
.filter(item => item.wind_speed != null)
|
.filter(item => item.wind_speed != null)
|
||||||
.map(item => [new Date(item.datetime).getTime(), item.wind_speed]),
|
.map(item => [new Date(item.datetime).getTime(), item.wind_speed])),
|
||||||
color: 'rgb(153, 102, 255)',
|
color: 'rgb(153, 102, 255)',
|
||||||
fillColor: 'rgba(153, 102, 255, 0.1)',
|
fillColor: 'rgba(153, 102, 255, 0.1)',
|
||||||
type: 'area',
|
type: 'area',
|
||||||
@@ -674,9 +692,9 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
? [windSpeedSeries]
|
? [windSpeedSeries]
|
||||||
: [windSpeedSeries, {
|
: [windSpeedSeries, {
|
||||||
name: 'Böe' + windGustSuffix,
|
name: 'Böe' + windGustSuffix,
|
||||||
data: sortedData
|
data: withGaps(sortedData
|
||||||
.filter(item => item.wind_gust != null)
|
.filter(item => item.wind_gust != null)
|
||||||
.map(item => [new Date(item.datetime).getTime(), item.wind_gust]),
|
.map(item => [new Date(item.datetime).getTime(), item.wind_gust])),
|
||||||
color: 'rgb(255, 100, 0)',
|
color: 'rgb(255, 100, 0)',
|
||||||
fillColor: 'rgba(255, 100, 0, 0.15)',
|
fillColor: 'rgba(255, 100, 0, 0.15)',
|
||||||
type: 'area',
|
type: 'area',
|
||||||
@@ -716,7 +734,7 @@ const WeatherDashboard = ({ data, currentData = [], rainData = [], timeRange = '
|
|||||||
},
|
},
|
||||||
series
|
series
|
||||||
}
|
}
|
||||||
}, [sortedData, timeRange, windGustSuffix])
|
}, [sortedData, timeRange, windGustSuffix, withGaps])
|
||||||
|
|
||||||
// Windrichtung Chart
|
// Windrichtung Chart
|
||||||
const windDirOptions = useMemo(() => ({
|
const windDirOptions = useMemo(() => ({
|
||||||
|
|||||||
+4
-1
@@ -36,7 +36,10 @@ else
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mapfile -t DUMPS < <(find "$BACKUP_DIR" -name "*.dump" | sort -r)
|
DUMPS=()
|
||||||
|
while IFS= read -r line; do
|
||||||
|
DUMPS+=("$line")
|
||||||
|
done < <(find "$BACKUP_DIR" -name "*.dump" | sort -r)
|
||||||
|
|
||||||
if [[ ${#DUMPS[@]} -eq 0 ]]; then
|
if [[ ${#DUMPS[@]} -eq 0 ]]; then
|
||||||
echo "FEHLER: Keine Backup-Dateien in $BACKUP_DIR gefunden."
|
echo "FEHLER: Keine Backup-Dateien in $BACKUP_DIR gefunden."
|
||||||
|
|||||||
Reference in New Issue
Block a user