Highcharts sieht viel besser aus
This commit is contained in:
@@ -9,11 +9,10 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chart.js": "^4.4.1",
|
|
||||||
"chartjs-adapter-date-fns": "^3.0.0",
|
|
||||||
"date-fns": "^3.3.1",
|
"date-fns": "^3.3.1",
|
||||||
|
"highcharts": "^11.4.0",
|
||||||
|
"highcharts-react-official": "^3.2.1",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-chartjs-2": "^5.2.0",
|
|
||||||
"react-dom": "^18.3.1"
|
"react-dom": "^18.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -1,33 +1,22 @@
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import {
|
import Highcharts from 'highcharts'
|
||||||
Chart as ChartJS,
|
import HighchartsReact from 'highcharts-react-official'
|
||||||
CategoryScale,
|
|
||||||
LinearScale,
|
|
||||||
TimeScale,
|
|
||||||
PointElement,
|
|
||||||
LineElement,
|
|
||||||
Title,
|
|
||||||
Tooltip,
|
|
||||||
Legend,
|
|
||||||
Filler
|
|
||||||
} from 'chart.js'
|
|
||||||
import 'chartjs-adapter-date-fns'
|
|
||||||
import { Line } from 'react-chartjs-2'
|
|
||||||
import { format } from 'date-fns'
|
import { format } from 'date-fns'
|
||||||
import { de } from 'date-fns/locale'
|
import { de } from 'date-fns/locale'
|
||||||
import './WeatherDashboard.css'
|
import './WeatherDashboard.css'
|
||||||
|
|
||||||
ChartJS.register(
|
// Deutsche Lokalisierung für Highcharts
|
||||||
CategoryScale,
|
Highcharts.setOptions({
|
||||||
LinearScale,
|
lang: {
|
||||||
TimeScale,
|
months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
|
||||||
PointElement,
|
shortMonths: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],
|
||||||
LineElement,
|
weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
|
||||||
Title,
|
resetZoom: 'Zoom zurücksetzen'
|
||||||
Tooltip,
|
},
|
||||||
Legend,
|
time: {
|
||||||
Filler
|
useUTC: false
|
||||||
)
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const WeatherDashboard = ({ data }) => {
|
const WeatherDashboard = ({ data }) => {
|
||||||
// Daten vorbereiten und nach Zeit sortieren (älteste zuerst)
|
// Daten vorbereiten und nach Zeit sortieren (älteste zuerst)
|
||||||
@@ -35,292 +24,289 @@ const WeatherDashboard = ({ data }) => {
|
|||||||
return [...data].sort((a, b) => new Date(a.datetime) - new Date(b.datetime))
|
return [...data].sort((a, b) => new Date(a.datetime) - new Date(b.datetime))
|
||||||
}, [data])
|
}, [data])
|
||||||
|
|
||||||
// Labels für X-Achse (Zeit)
|
// Gemeinsame Chart-Optionen
|
||||||
const labels = useMemo(() => {
|
const getCommonOptions = () => ({
|
||||||
return sortedData.map(item =>
|
chart: {
|
||||||
format(new Date(item.datetime), 'HH:mm', { locale: de })
|
height: 250,
|
||||||
)
|
animation: false,
|
||||||
}, [sortedData])
|
backgroundColor: 'transparent'
|
||||||
|
|
||||||
// Chart-Konfiguration
|
|
||||||
const commonOptions = {
|
|
||||||
responsive: true,
|
|
||||||
maintainAspectRatio: false,
|
|
||||||
interaction: {
|
|
||||||
mode: 'index',
|
|
||||||
intersect: false,
|
|
||||||
},
|
},
|
||||||
elements: {
|
credits: {
|
||||||
point: {
|
enabled: false
|
||||||
radius: 0,
|
|
||||||
hitRadius: 10,
|
|
||||||
hoverRadius: 5,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
plugins: {
|
title: {
|
||||||
legend: {
|
text: null
|
||||||
display: false,
|
|
||||||
},
|
|
||||||
tooltip: {
|
|
||||||
callbacks: {
|
|
||||||
title: (context) => {
|
|
||||||
const index = context[0].dataIndex
|
|
||||||
return format(new Date(sortedData[index].datetime), 'dd.MM.yyyy HH:mm', { locale: de })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
scales: {
|
legend: {
|
||||||
x: {
|
enabled: false
|
||||||
grid: {
|
},
|
||||||
display: true,
|
tooltip: {
|
||||||
color: 'rgba(0, 0, 0, 0.1)',
|
shared: true,
|
||||||
},
|
crosshairs: true,
|
||||||
ticks: {
|
xDateFormat: '%d.%m.%Y %H:%M'
|
||||||
type: 'time',
|
},
|
||||||
time: {
|
plotOptions: {
|
||||||
unit: 'hour',
|
series: {
|
||||||
stepSize: 4
|
marker: {
|
||||||
},
|
enabled: false,
|
||||||
ticks: {
|
states: {
|
||||||
autoSkip: false
|
hover: {
|
||||||
}
|
enabled: true,
|
||||||
/*
|
radius: 5
|
||||||
maxRotation: 0,
|
|
||||||
autoSkip: false,
|
|
||||||
callback: function(value, index) {
|
|
||||||
if (sortedData.length === 0) return ''
|
|
||||||
|
|
||||||
const date = new Date(sortedData[index]?.datetime)
|
|
||||||
const hours = date.getHours()
|
|
||||||
const minutes = date.getMinutes()
|
|
||||||
|
|
||||||
// Berechne die nächste 4-Stunden-Zeit
|
|
||||||
const nearestFourHour = Math.round(hours / 4) * 4
|
|
||||||
|
|
||||||
// Wenn die Stunde durch 4 teilbar ist UND die Minuten <= 2 sind (also 00:00, 00:05 zählen),
|
|
||||||
// dann ist dies der Datenpunkt, der der 4-Stunden-Zeit am nächsten liegt
|
|
||||||
if (hours % 4 === 0 && minutes <= 2) {
|
|
||||||
return format(new Date(date.getFullYear(), date.getMonth(), date.getDate(), hours, 0), 'HH:mm', { locale: de })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ''
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
|
||||||
},
|
|
||||||
y: {
|
|
||||||
grid: {
|
|
||||||
color: 'rgba(0, 0, 0, 0.05)',
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
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
|
// Temperatur Chart
|
||||||
const temperatureData = {
|
const temperatureOptions = useMemo(() => {
|
||||||
labels,
|
const temps = sortedData.map(item => item.temperature)
|
||||||
datasets: [
|
const min = Math.min(...temps)
|
||||||
{
|
const max = Math.max(...temps)
|
||||||
label: 'Temperatur (°C)',
|
const range = max - min
|
||||||
data: sortedData.map(item => item.temperature),
|
|
||||||
borderColor: 'rgb(255, 99, 132)',
|
|
||||||
backgroundColor: 'rgba(255, 99, 132, 0.1)',
|
|
||||||
fill: 'start',
|
|
||||||
tension: 0.4,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const temperatureOptions = {
|
let yMin = min
|
||||||
...commonOptions,
|
let yMax = max
|
||||||
scales: {
|
|
||||||
...commonOptions.scales,
|
if (range < 15) {
|
||||||
y: {
|
const center = (max + min) / 2
|
||||||
...commonOptions.scales.y,
|
yMin = center - 7.5
|
||||||
afterDataLimits: (axis) => {
|
yMax = center + 7.5
|
||||||
const range = axis.max - axis.min
|
}
|
||||||
if (range < 15) {
|
|
||||||
const center = (axis.max + axis.min) / 2
|
return {
|
||||||
axis.max = center + 7.5
|
...getCommonOptions(),
|
||||||
axis.min = center - 7.5
|
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: 'area',
|
||||||
|
threshold: yMin,
|
||||||
|
tooltip: {
|
||||||
|
valueSuffix: ' °C'
|
||||||
}
|
}
|
||||||
}
|
}]
|
||||||
}
|
}
|
||||||
}
|
}, [sortedData])
|
||||||
|
|
||||||
// Feuchte Chart
|
// Luftfeuchtigkeit Chart
|
||||||
const humidityData = {
|
const humidityOptions = useMemo(() => ({
|
||||||
labels,
|
...getCommonOptions(),
|
||||||
datasets: [
|
yAxis: {
|
||||||
{
|
...getCommonOptions().yAxis,
|
||||||
label: 'Luftfeuchtigkeit (%)',
|
title: { text: 'Luftfeuchtigkeit (%)' },
|
||||||
data: sortedData.map(item => item.humidity),
|
min: 0,
|
||||||
borderColor: 'rgb(54, 162, 235)',
|
max: 100
|
||||||
backgroundColor: 'rgba(54, 162, 235, 0.1)',
|
},
|
||||||
fill: true,
|
series: [{
|
||||||
tension: 0.4,
|
name: 'Luftfeuchtigkeit',
|
||||||
|
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])
|
||||||
|
|
||||||
const humidityOptions = {
|
// Luftdruck Chart
|
||||||
...commonOptions,
|
const pressureOptions = useMemo(() => {
|
||||||
scales: {
|
const pressures = sortedData.map(item => item.pressure)
|
||||||
...commonOptions.scales,
|
const min = Math.min(...pressures)
|
||||||
y: {
|
const max = Math.max(...pressures)
|
||||||
...commonOptions.scales.y,
|
const range = max - min
|
||||||
min: 0,
|
|
||||||
max: 100
|
let yMin = min
|
||||||
}
|
let yMax = max
|
||||||
|
|
||||||
|
if (range < 50) {
|
||||||
|
const center = (max + min) / 2
|
||||||
|
yMin = center - 25
|
||||||
|
yMax = center + 25
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Druck Chart
|
return {
|
||||||
const pressureData = {
|
...getCommonOptions(),
|
||||||
labels,
|
yAxis: {
|
||||||
datasets: [
|
...getCommonOptions().yAxis,
|
||||||
{
|
title: { text: 'Luftdruck (hPa)' },
|
||||||
label: 'Luftdruck (hPa)',
|
min: yMin,
|
||||||
data: sortedData.map(item => item.pressure),
|
max: yMax
|
||||||
borderColor: 'rgb(75, 192, 192)',
|
},
|
||||||
backgroundColor: 'rgba(75, 192, 192, 0.1)',
|
series: [{
|
||||||
fill: true,
|
name: 'Luftdruck',
|
||||||
tension: 0.4,
|
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: [
|
||||||
const pressureOptions = {
|
[0, 'rgba(75, 192, 192, 0.3)'],
|
||||||
...commonOptions,
|
[1, 'rgba(75, 192, 192, 0.1)']
|
||||||
scales: {
|
]
|
||||||
...commonOptions.scales,
|
},
|
||||||
y: {
|
type: 'area',
|
||||||
...commonOptions.scales.y,
|
tooltip: {
|
||||||
afterDataLimits: (axis) => {
|
valueSuffix: ' hPa'
|
||||||
const range = axis.max - axis.min
|
|
||||||
if (range < 50) {
|
|
||||||
const center = (axis.max + axis.min) / 2
|
|
||||||
axis.max = center + 25
|
|
||||||
axis.min = center - 25
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}]
|
||||||
}
|
}
|
||||||
}
|
}, [sortedData])
|
||||||
|
|
||||||
// Regen Chart
|
// Regen Chart
|
||||||
const rainData = {
|
const rainOptions = useMemo(() => ({
|
||||||
labels,
|
...getCommonOptions(),
|
||||||
datasets: [
|
legend: {
|
||||||
{
|
enabled: true,
|
||||||
label: 'Regen (mm)',
|
align: 'center',
|
||||||
data: sortedData.map(item => item.rain),
|
verticalAlign: 'top'
|
||||||
borderColor: 'rgb(54, 162, 235)',
|
},
|
||||||
backgroundColor: 'rgba(54, 162, 235, 0.3)',
|
yAxis: {
|
||||||
fill: true,
|
...getCommonOptions().yAxis,
|
||||||
tension: 0.4,
|
title: { text: 'Regen (mm) / Rate (mm/h)' }
|
||||||
},
|
},
|
||||||
{
|
series: [{
|
||||||
label: 'Regenrate (mm/h)',
|
name: 'Regen',
|
||||||
data: sortedData.map(item => item.rain_rate),
|
data: sortedData.map(item => [new Date(item.datetime).getTime(), item.rain]),
|
||||||
borderColor: 'rgb(59, 130, 246)',
|
color: 'rgb(54, 162, 235)',
|
||||||
backgroundColor: 'rgba(59, 130, 246, 0.1)',
|
fillColor: 'rgba(54, 162, 235, 0.3)',
|
||||||
borderDash: [5, 5],
|
type: 'area',
|
||||||
fill: false,
|
tooltip: {
|
||||||
tension: 0.4,
|
valueSuffix: ' mm'
|
||||||
}
|
}
|
||||||
]
|
}, {
|
||||||
}
|
name: 'Regenrate',
|
||||||
|
data: sortedData.map(item => [new Date(item.datetime).getTime(), item.rain_rate]),
|
||||||
const rainOptions = {
|
color: 'rgb(59, 130, 246)',
|
||||||
...commonOptions,
|
dashStyle: 'Dash',
|
||||||
plugins: {
|
type: 'line',
|
||||||
...commonOptions.plugins,
|
tooltip: {
|
||||||
legend: {
|
valueSuffix: ' mm/h'
|
||||||
display: true,
|
|
||||||
position: 'top',
|
|
||||||
}
|
}
|
||||||
}
|
}]
|
||||||
}
|
}), [sortedData])
|
||||||
|
|
||||||
// Windgeschwindigkeit Chart
|
// Windgeschwindigkeit Chart
|
||||||
const windSpeedData = {
|
const windSpeedOptions = useMemo(() => ({
|
||||||
labels,
|
...getCommonOptions(),
|
||||||
datasets: [
|
legend: {
|
||||||
{
|
enabled: true,
|
||||||
label: 'Windgeschwindigkeit (km/h)',
|
align: 'center',
|
||||||
data: sortedData.map(item => item.wind_speed),
|
verticalAlign: 'top'
|
||||||
borderColor: 'rgb(153, 102, 255)',
|
},
|
||||||
backgroundColor: 'rgba(153, 102, 255, 0.1)',
|
plotOptions: {
|
||||||
fill: true,
|
series: {
|
||||||
tension: 0,
|
marker: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
lineWidth: 2
|
||||||
},
|
},
|
||||||
{
|
line: {
|
||||||
label: 'Windböen (km/h)',
|
step: 'left' // Keine Glättung
|
||||||
data: sortedData.map(item => item.wind_gust),
|
|
||||||
borderColor: 'rgb(255, 159, 64)',
|
|
||||||
backgroundColor: 'rgba(255, 159, 64, 0.1)',
|
|
||||||
fill: true,
|
|
||||||
tension: 0,
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
}
|
yAxis: {
|
||||||
|
...getCommonOptions().yAxis,
|
||||||
const windSpeedOptions = {
|
title: { text: 'Windgeschwindigkeit (km/h)' }
|
||||||
...commonOptions,
|
},
|
||||||
plugins: {
|
series: [{
|
||||||
...commonOptions.plugins,
|
name: 'Windgeschwindigkeit',
|
||||||
legend: {
|
data: sortedData.map(item => [new Date(item.datetime).getTime(), item.wind_speed]),
|
||||||
display: true,
|
color: 'rgb(153, 102, 255)',
|
||||||
position: 'top',
|
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
|
// Windrichtung Chart
|
||||||
const windDirData = {
|
const windDirOptions = useMemo(() => ({
|
||||||
labels,
|
...getCommonOptions(),
|
||||||
datasets: [
|
plotOptions: {
|
||||||
{
|
scatter: {
|
||||||
label: 'Windrichtung (°)',
|
marker: {
|
||||||
data: sortedData.map(item => item.wind_dir),
|
enabled: true,
|
||||||
borderColor: 'rgb(255, 205, 86)',
|
radius: 4,
|
||||||
backgroundColor: 'rgb(255, 205, 86)',
|
states: {
|
||||||
pointRadius: 4,
|
hover: {
|
||||||
pointHoverRadius: 6,
|
enabled: true,
|
||||||
showLine: false,
|
radius: 6
|
||||||
fill: false,
|
}
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
const windDirOptions = {
|
|
||||||
...commonOptions,
|
|
||||||
scales: {
|
|
||||||
...commonOptions.scales,
|
|
||||||
y: {
|
|
||||||
...commonOptions.scales.y,
|
|
||||||
min: 0,
|
|
||||||
max: 360,
|
|
||||||
ticks: {
|
|
||||||
stepSize: 45,
|
|
||||||
callback: (value) => {
|
|
||||||
if (value === 0 || value === 360) return 'N'
|
|
||||||
if (value === 45) return 'NO'
|
|
||||||
if (value === 90) return 'O'
|
|
||||||
if (value === 135) return 'SO'
|
|
||||||
if (value === 180) return 'S'
|
|
||||||
if (value === 225) return 'SW'
|
|
||||||
if (value === 270) return 'W'
|
|
||||||
if (value === 315) return 'NW'
|
|
||||||
return ''
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
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(255, 205, 86)',
|
||||||
|
type: 'scatter',
|
||||||
|
tooltip: {
|
||||||
|
valueSuffix: ' °'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}), [sortedData])
|
||||||
|
|
||||||
// Aktuellste Werte für Übersicht
|
// Aktuellste Werte für Übersicht
|
||||||
const current = sortedData[sortedData.length - 1] || {}
|
const current = sortedData[sortedData.length - 1] || {}
|
||||||
@@ -356,42 +342,42 @@ const WeatherDashboard = ({ data }) => {
|
|||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
<h3>🌡️ Temperatur</h3>
|
<h3>🌡️ Temperatur</h3>
|
||||||
<div className="chart-wrapper">
|
<div className="chart-wrapper">
|
||||||
<Line data={temperatureData} options={temperatureOptions} />
|
<HighchartsReact highcharts={Highcharts} options={temperatureOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
<h3>💧 Luftfeuchtigkeit</h3>
|
<h3>💧 Luftfeuchtigkeit</h3>
|
||||||
<div className="chart-wrapper">
|
<div className="chart-wrapper">
|
||||||
<Line data={humidityData} options={humidityOptions} />
|
<HighchartsReact highcharts={Highcharts} options={humidityOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
<h3>🌐 Luftdruck</h3>
|
<h3>🌐 Luftdruck</h3>
|
||||||
<div className="chart-wrapper">
|
<div className="chart-wrapper">
|
||||||
<Line data={pressureData} options={pressureOptions} />
|
<HighchartsReact highcharts={Highcharts} options={pressureOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
<h3>🌧️ Regen</h3>
|
<h3>🌧️ Regen</h3>
|
||||||
<div className="chart-wrapper">
|
<div className="chart-wrapper">
|
||||||
<Line data={rainData} options={rainOptions} />
|
<HighchartsReact highcharts={Highcharts} options={rainOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
<h3>💨 Windgeschwindigkeit</h3>
|
<h3>💨 Windgeschwindigkeit</h3>
|
||||||
<div className="chart-wrapper">
|
<div className="chart-wrapper">
|
||||||
<Line data={windSpeedData} options={windSpeedOptions} />
|
<HighchartsReact highcharts={Highcharts} options={windSpeedOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="chart-container">
|
<div className="chart-container">
|
||||||
<h3>🧭 Windrichtung</h3>
|
<h3>🧭 Windrichtung</h3>
|
||||||
<div className="chart-wrapper">
|
<div className="chart-wrapper">
|
||||||
<Line data={windDirData} options={windDirOptions} />
|
<HighchartsReact highcharts={Highcharts} options={windDirOptions} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user