diff --git a/src/app/components/diagrams/diagrams.html b/src/app/components/diagrams/diagrams.html index 6861fe7..cbca2e2 100644 --- a/src/app/components/diagrams/diagrams.html +++ b/src/app/components/diagrams/diagrams.html @@ -1,3 +1,7 @@
+
+ + +
diff --git a/src/app/components/diagrams/diagrams.ts b/src/app/components/diagrams/diagrams.ts index 5110632..b9bcf1d 100644 --- a/src/app/components/diagrams/diagrams.ts +++ b/src/app/components/diagrams/diagrams.ts @@ -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!) } } diff --git a/src/app/components/diagrams/humidity/humidity.css b/src/app/components/diagrams/humidity/humidity.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/diagrams/humidity/humidity.html b/src/app/components/diagrams/humidity/humidity.html new file mode 100644 index 0000000..176e341 --- /dev/null +++ b/src/app/components/diagrams/humidity/humidity.html @@ -0,0 +1,37 @@ +@if(measurements) { + + + Luftfeuchtigkeit + + + line_axis + Line + + + bar_chart + Balken + + + area_chart + Fläche + + + + + + + + + +} diff --git a/src/app/components/diagrams/humidity/humidity.spec.ts b/src/app/components/diagrams/humidity/humidity.spec.ts new file mode 100644 index 0000000..f56060c --- /dev/null +++ b/src/app/components/diagrams/humidity/humidity.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Humidity } from './humidity'; + +describe('Humidity', () => { + let component: Humidity; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [Humidity], + }).compileComponents(); + + fixture = TestBed.createComponent(Humidity); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/diagrams/humidity/humidity.ts b/src/app/components/diagrams/humidity/humidity.ts new file mode 100644 index 0000000..8d0884b --- /dev/null +++ b/src/app/components/diagrams/humidity/humidity.ts @@ -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(); + } +} diff --git a/src/app/components/diagrams/pressure/pressure.css b/src/app/components/diagrams/pressure/pressure.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/components/diagrams/pressure/pressure.html b/src/app/components/diagrams/pressure/pressure.html new file mode 100644 index 0000000..a0ba5aa --- /dev/null +++ b/src/app/components/diagrams/pressure/pressure.html @@ -0,0 +1,37 @@ +@if(measurements) { + + + Luftdruck + + + line_axis + Line + + + bar_chart + Balken + + + area_chart + Fläche + + + + + + + + + +} diff --git a/src/app/components/diagrams/pressure/pressure.spec.ts b/src/app/components/diagrams/pressure/pressure.spec.ts new file mode 100644 index 0000000..bf66bc8 --- /dev/null +++ b/src/app/components/diagrams/pressure/pressure.spec.ts @@ -0,0 +1,22 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { Pressure } from './pressure'; + +describe('Pressure', () => { + let component: Pressure; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [Pressure], + }).compileComponents(); + + fixture = TestBed.createComponent(Pressure); + component = fixture.componentInstance; + await fixture.whenStable(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/diagrams/pressure/pressure.ts b/src/app/components/diagrams/pressure/pressure.ts new file mode 100644 index 0000000..13e1a4b --- /dev/null +++ b/src/app/components/diagrams/pressure/pressure.ts @@ -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(); + } +}