ADD: Humidity and Air Pressure Diagrams

This commit is contained in:
sebastian 2026-06-30 18:17:23 +02:00
parent fe3e7334ce
commit f8e59e3649
10 changed files with 358 additions and 1 deletions

View File

@ -1,3 +1,7 @@
<div class="diagrams-container">
<app-temperature #temperature [measurements]="measurements"></app-temperature>
<div style="display: flex">
<app-humidity style="width: 50%" #humidity [measurements]="measurements"></app-humidity>
<app-pressure style="width: 50%;" #pressure [measurements]="measurements"></app-pressure>
</div>
</div>

View File

@ -3,11 +3,15 @@ import {TemperatureComponent, TimeResolution} from './temperature/temperature';
import {DefaultService, MeasurementListResponse, MeasurementResolution, StationListResponse} from '../../api';
import {ApexOptions} from 'ng-apexcharts';
import {addDays, addHours, addMonths, addYears, startOfDay} from 'date-fns';
import {Humidity} from './humidity/humidity';
import {Pressure} from './pressure/pressure';
@Component({
selector: 'app-diagrams',
imports: [
TemperatureComponent
TemperatureComponent,
Humidity,
Pressure
],
templateUrl: './diagrams.html',
styleUrl: './diagrams.css',
@ -16,6 +20,8 @@ export class Diagrams {
timeResolution: TimeResolution = '7d';
@Input() activeStations: StationListResponse[] = [];
@ViewChild('temperature') temperatureDiagram?: TemperatureComponent
@ViewChild('humidity') humidityDiagram?: TemperatureComponent
@ViewChild('pressure') pressureDiagram?: TemperatureComponent
resolution: MeasurementResolution = MeasurementResolution.Daily;
measurements: MeasurementListResponse | undefined;
@ -77,5 +83,7 @@ export class Diagrams {
buildCharts() {
this.temperatureDiagram?.buildChart(this.measurements!)
this.humidityDiagram?.buildChart(this.measurements!)
this.pressureDiagram?.buildChart(this.measurements!)
}
}

View File

@ -0,0 +1,37 @@
@if(measurements) {
<mat-card>
<mat-card-header>
<mat-card-title>Luftfeuchtigkeit
<mat-button-toggle-group name="fontStyle" aria-label="Font Style" (valueChange)="switchChartType($event)" [value]="'bar'">
<mat-button-toggle value="line">
<mat-icon>line_axis</mat-icon>
Line
</mat-button-toggle>
<mat-button-toggle value="bar">
<mat-icon>bar_chart</mat-icon>
Balken
</mat-button-toggle>
<mat-button-toggle value="area">
<mat-icon>area_chart</mat-icon>
Fläche
</mat-button-toggle>
</mat-button-toggle-group>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<apx-chart
[series]="chartOptions.series!"
[chart]="chartOptions.chart!"
[xaxis]="chartOptions.xaxis!"
[yaxis]="chartOptions.yaxis!"
[stroke]="chartOptions.stroke!"
[grid]="chartOptions.grid!"
[dataLabels]="chartOptions.dataLabels!"
[tooltip]="chartOptions.tooltip!"
[legend]="chartOptions.legend!"
[theme]="chartOptions.theme!"
/>
</mat-card-content>
</mat-card>
}

View File

@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Humidity } from './humidity';
describe('Humidity', () => {
let component: Humidity;
let fixture: ComponentFixture<Humidity>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Humidity],
}).compileComponents();
fixture = TestBed.createComponent(Humidity);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,114 @@
import {ChangeDetectorRef, Component, Input} from '@angular/core';
import {DefaultService, MeasurementListResponse} from '../../../api';
import {ApexOptions, ChartComponent, ChartType} from 'ng-apexcharts';
import {MatButtonToggle, MatButtonToggleGroup} from '@angular/material/button-toggle';
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from '@angular/material/card';
import {MatIcon} from '@angular/material/icon';
@Component({
selector: 'app-humidity',
imports: [
ChartComponent,
MatButtonToggle,
MatButtonToggleGroup,
MatCard,
MatCardContent,
MatCardHeader,
MatCardTitle,
MatIcon
],
templateUrl: './humidity.html',
styleUrl: './humidity.css',
})
export class Humidity {
@Input() measurements: MeasurementListResponse | undefined;
chartOptions: ApexOptions = {};
chartType: ChartType = 'bar';
constructor(private api: DefaultService, private cdr: ChangeDetectorRef) {}
switchChartType(type: 'bar' | 'area' | 'line') {
this.chartType = type;
this.buildChart(this.measurements!)
}
public buildChart(measurements: MeasurementListResponse) {
this.measurements = measurements;
if (!this.measurements) return;
const isBar = this.chartType === 'bar';
const isArea = this.chartType === 'area';
this.chartOptions = {
chart: {
type: this.chartType,
height: 280,
toolbar: { show: false },
animations: { enabled: true },
background: 'transparent',
stacked: false,
},
theme: { mode: 'dark' },
dataLabels: {
enabled: false, // <- das hat gefehlt
},
stroke: {
curve: 'smooth',
width: isBar ? 0 : 2,
},
fill: {
type: isArea ? 'gradient' : 'solid',
opacity: isArea ? 0.3 : (isBar ? 0.85 : 1),
gradient: isArea ? {
shadeIntensity: 1,
opacityFrom: 0.4,
opacityTo: 0.05,
stops: [0, 100]
} : undefined,
},
plotOptions: {
bar: {
columnWidth: '70%',
borderRadius: 3,
}
},
series: this.measurements.stations.map(s => ({
name: `${s.station.name} ${s.indoor ? '(innen)' : '(außen)'}`,
data: s.measurements.map(m => ({
x: new Date(m.timestamp).getTime(),
y: m.humidity
}))
})),
xaxis: {
type: 'datetime',
labels: {
datetimeUTC: false,
style: { colors: '#9e9e9e', fontSize: '11px' }
},
axisBorder: { show: false },
axisTicks: { show: false },
},
yaxis: {
labels: {
style: { colors: '#9e9e9e', fontSize: '11px' },
formatter: (val: number) => `${val.toFixed(1)}%`
}
},
grid: {
borderColor: 'rgba(255,255,255,0.06)',
strokeDashArray: 4,
},
tooltip: {
theme: 'dark',
shared: true,
intersect: false,
x: { format: 'dd.MM.yyyy HH:mm' },
y: { formatter: (val: number) => `${val?.toFixed(1)} %` }
},
legend: {
labels: { colors: '#9e9e9e' }
},
};
this.cdr.detectChanges();
}
}

View File

@ -0,0 +1,37 @@
@if(measurements) {
<mat-card>
<mat-card-header>
<mat-card-title>Luftdruck
<mat-button-toggle-group name="fontStyle" aria-label="Font Style" (valueChange)="switchChartType($event)" [value]="'bar'">
<mat-button-toggle value="line">
<mat-icon>line_axis</mat-icon>
Line
</mat-button-toggle>
<mat-button-toggle value="bar">
<mat-icon>bar_chart</mat-icon>
Balken
</mat-button-toggle>
<mat-button-toggle value="area">
<mat-icon>area_chart</mat-icon>
Fläche
</mat-button-toggle>
</mat-button-toggle-group>
</mat-card-title>
</mat-card-header>
<mat-card-content>
<apx-chart
[series]="chartOptions.series!"
[chart]="chartOptions.chart!"
[xaxis]="chartOptions.xaxis!"
[yaxis]="chartOptions.yaxis!"
[stroke]="chartOptions.stroke!"
[grid]="chartOptions.grid!"
[dataLabels]="chartOptions.dataLabels!"
[tooltip]="chartOptions.tooltip!"
[legend]="chartOptions.legend!"
[theme]="chartOptions.theme!"
/>
</mat-card-content>
</mat-card>
}

View File

@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { Pressure } from './pressure';
describe('Pressure', () => {
let component: Pressure;
let fixture: ComponentFixture<Pressure>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [Pressure],
}).compileComponents();
fixture = TestBed.createComponent(Pressure);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,113 @@
import {ChangeDetectorRef, Component, Input} from '@angular/core';
import {ApexOptions, ChartComponent, ChartType} from "ng-apexcharts";
import {MatButtonToggle, MatButtonToggleGroup} from "@angular/material/button-toggle";
import {MatCard, MatCardContent, MatCardHeader, MatCardTitle} from "@angular/material/card";
import {MatIcon} from "@angular/material/icon";
import {DefaultService, MeasurementListResponse} from '../../../api';
@Component({
selector: 'app-pressure',
imports: [
ChartComponent,
MatButtonToggle,
MatButtonToggleGroup,
MatCard,
MatCardContent,
MatCardHeader,
MatCardTitle,
MatIcon
],
templateUrl: './pressure.html',
styleUrl: './pressure.css',
})
export class Pressure {
@Input() measurements: MeasurementListResponse | undefined;
chartOptions: ApexOptions = {};
chartType: ChartType = 'bar';
constructor(private api: DefaultService, private cdr: ChangeDetectorRef) {}
switchChartType(type: 'bar' | 'area' | 'line') {
this.chartType = type;
this.buildChart(this.measurements!)
}
public buildChart(measurements: MeasurementListResponse) {
this.measurements = measurements;
if (!this.measurements) return;
const isBar = this.chartType === 'bar';
const isArea = this.chartType === 'area';
this.chartOptions = {
chart: {
type: this.chartType,
height: 280,
toolbar: { show: false },
animations: { enabled: true },
background: 'transparent',
stacked: false,
},
theme: { mode: 'dark' },
dataLabels: {
enabled: false, // <- das hat gefehlt
},
stroke: {
curve: 'smooth',
width: isBar ? 0 : 2,
},
fill: {
type: isArea ? 'gradient' : 'solid',
opacity: isArea ? 0.3 : (isBar ? 0.85 : 1),
gradient: isArea ? {
shadeIntensity: 1,
opacityFrom: 0.4,
opacityTo: 0.05,
stops: [0, 100]
} : undefined,
},
plotOptions: {
bar: {
columnWidth: '70%',
borderRadius: 3,
}
},
series: this.measurements.stations.map(s => ({
name: `${s.station.name} ${s.indoor ? '(innen)' : '(außen)'}`,
data: s.measurements.map(m => ({
x: new Date(m.timestamp).getTime(),
y: m.pressure
}))
})),
xaxis: {
type: 'datetime',
labels: {
datetimeUTC: false,
style: { colors: '#9e9e9e', fontSize: '11px' }
},
axisBorder: { show: false },
axisTicks: { show: false },
},
yaxis: {
labels: {
style: { colors: '#9e9e9e', fontSize: '11px' },
formatter: (val: number) => `${val.toFixed(1)}hPa`
}
},
grid: {
borderColor: 'rgba(255,255,255,0.06)',
strokeDashArray: 4,
},
tooltip: {
theme: 'dark',
shared: true,
intersect: false,
x: { format: 'dd.MM.yyyy HH:mm' },
y: { formatter: (val: number) => `${val?.toFixed(1)} hPa` }
},
legend: {
labels: { colors: '#9e9e9e' }
},
};
this.cdr.detectChanges();
}
}