diff --git a/src/main/angular/public/favicon.ico b/src/main/angular/public/favicon.ico deleted file mode 100644 index 57614f9..0000000 Binary files a/src/main/angular/public/favicon.ico and /dev/null differ diff --git a/src/main/angular/public/favicon.svg b/src/main/angular/public/favicon.svg new file mode 100644 index 0000000..d0e96ff --- /dev/null +++ b/src/main/angular/public/favicon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/angular/src/app/location/detail/history/series-history.html b/src/main/angular/src/app/location/detail/history/series-history.html index 216fe02..3159e9a 100644 --- a/src/main/angular/src/app/location/detail/history/series-history.html +++ b/src/main/angular/src/app/location/detail/history/series-history.html @@ -2,6 +2,7 @@
{{ heading }} +
@@ -11,7 +12,7 @@ Bezug
- {{ purchase?.toValueString(true, interval ? null : now) }} + {{ purchase.toValueString(true, interval ? null : now) }}
@@ -20,7 +21,7 @@ Solar
- {{ produce?.toValueString(true, interval ? null : now) }} + {{ produce.toValueString(true, interval ? null : now) }}
@@ -29,7 +30,7 @@ Verbrauch
- {{ consume?.toValueString(true, interval ? null : now) }} + {{ consume.toValueString(true, interval ? null : now) }}
@@ -38,7 +39,7 @@ Einspeisung
- {{ deliver?.toValueString(true, interval ? null : now) }} + {{ deliver.toValueString(true, interval ? null : now) }}
diff --git a/src/main/angular/src/app/location/detail/history/series-history.ts b/src/main/angular/src/app/location/detail/history/series-history.ts index 4f5ab18..1567646 100644 --- a/src/main/angular/src/app/location/detail/history/series-history.ts +++ b/src/main/angular/src/app/location/detail/history/series-history.ts @@ -20,19 +20,28 @@ export class SeriesHistory implements OnInit, AfterViewInit, OnDestroy { private readonly subs: Subscription[] = []; - protected purchase: Value | null = null; + protected purchase: Value = Value.NONE; - protected deliver: Value | null = null; + protected deliver: Value = Value.NONE; - protected produce: Value | null = null; + protected produce: Value = Value.NONE; - protected consume: Value | null = null; + protected consume: Value = Value.NONE; @Input() - heading!: string; + heading: string = ""; + + private _o_: number = 0; @Input() - offset: number = 0; + set offset(value: number) { + this._o_ = value; + this.ngAfterViewInit(); + } + + get offset(): number { + return this._o_; + } @Input() interval: Interval | null = null; @@ -85,11 +94,11 @@ export class SeriesHistory implements OnInit, AfterViewInit, OnDestroy { } }; - private history(fresh: Series | null | undefined, series: Series | null | undefined, next: Next) { - const n = (value: Value | null) => { + private history(fresh: Series | null | undefined, series: Series | null | undefined, next: Next): void { + const callNextAndUpdateConsume = (value: Value) => { next(value); - this.consume = this.purchase?.plus(this.produce)?.minus(this.deliver) || null; - } + this.consume = this.purchase.plus(this.produce).minus(this.deliver); + }; if (fresh !== null && fresh !== undefined) { if (fresh.id !== series?.id) { return; @@ -97,18 +106,14 @@ export class SeriesHistory implements OnInit, AfterViewInit, OnDestroy { series = fresh; } if (!series) { - n(null); + callNextAndUpdateConsume(Value.NONE); return } if (this.interval) { - this.pointService.relative([series], this.interval, this.offset, 1, response => n(Value.ofPoint(response, 0, 0, 1))); + this.pointService.relative([series], this.interval, this.offset, 1, response => callNextAndUpdateConsume(Value.ofPoint(response, 0, 0, 1))); } else { - n(series.value); + callNextAndUpdateConsume(series.value); } } - protected nullOrZero(value: Value | null | undefined): boolean { - return value === null || value === undefined || value.value === 0; - } - } diff --git a/src/main/angular/src/app/location/detail/location-detail.html b/src/main/angular/src/app/location/detail/location-detail.html index e5561f7..604d471 100644 --- a/src/main/angular/src/app/location/detail/location-detail.html +++ b/src/main/angular/src/app/location/detail/location-detail.html @@ -4,7 +4,18 @@ - + + +
+   +
+   +
+   +
{{ offsetDayTitle() }}
+
+
+
diff --git a/src/main/angular/src/app/location/detail/location-detail.ts b/src/main/angular/src/app/location/detail/location-detail.ts index 085f0eb..e97bf42 100644 --- a/src/main/angular/src/app/location/detail/location-detail.ts +++ b/src/main/angular/src/app/location/detail/location-detail.ts @@ -1,4 +1,4 @@ -import {Component, OnDestroy, OnInit} from '@angular/core'; +import {Component, Inject, LOCALE_ID, OnDestroy, OnInit} from '@angular/core'; import {LocationService} from '../location-service'; import {ActivatedRoute} from '@angular/router'; import {Location} from '../Location'; @@ -12,6 +12,7 @@ import {Subscription, timer} from 'rxjs'; import {SeriesHistory} from './history/series-history'; import {Interval} from '../../series/Interval'; import {MenuService} from '../../menu-service'; +import {DatePipe} from '@angular/common'; function yesterday(now: any) { const yesterday = new Date(now.getTime()); @@ -34,6 +35,8 @@ export class LocationDetail implements OnInit, OnDestroy { protected readonly Interval = Interval; + protected readonly Math = Math; + protected location: Location | null = null; private readonly subs: Subscription [] = []; @@ -44,13 +47,18 @@ export class LocationDetail implements OnInit, OnDestroy { protected yesterday: Date = yesterday(this.now); + protected offset: number = 1; + + private readonly datePipe: DatePipe; + constructor( readonly locationService: LocationService, readonly seriesService: SeriesService, readonly activatedRoute: ActivatedRoute, readonly menuService: MenuService, + @Inject(LOCALE_ID) readonly locale: string, ) { - // + this.datePipe = new DatePipe(locale); } ngOnInit(): void { @@ -96,4 +104,19 @@ export class LocationDetail implements OnInit, OnDestroy { return this.series.filter(series => series.type === SeriesType.VARYING && series.unit === 'W'); }; + protected offsetDayTitle(): string { + if (this.offset === 1) { + return 'Gestern'; + } else if (this.offset === 2) { + return 'Vorgestern'; + } else { + if (this.offset < 7) { + const d = new Date(this.now); + d.setDate(d.getDate() - this.offset); + return this.datePipe.transform(d, 'EEEE') || ''; + } + return `Vor ${this.offset} Tagen`; + } + } + } diff --git a/src/main/angular/src/app/series/Series.ts b/src/main/angular/src/app/series/Series.ts index f4e0bc1..8d455a8 100644 --- a/src/main/angular/src/app/series/Series.ts +++ b/src/main/angular/src/app/series/Series.ts @@ -5,7 +5,7 @@ import {Value} from './Value'; export class Series { - readonly value: Value | null = null; + readonly value: Value; constructor( readonly id: number, diff --git a/src/main/angular/src/app/series/Value.ts b/src/main/angular/src/app/series/Value.ts index c0bd367..1baee61 100644 --- a/src/main/angular/src/app/series/Value.ts +++ b/src/main/angular/src/app/series/Value.ts @@ -4,8 +4,10 @@ import {Series} from './Series'; export class Value { - constructor( - readonly value: number, + static readonly NONE: Value = new Value(null, 0, 0, "", new Date()); + + private constructor( + readonly value: number | null, readonly precision: number, readonly seconds: number, readonly unit: string, @@ -15,8 +17,8 @@ export class Value { } toValueString(zeroToDash: boolean, now_ageCheckToDash: Date | null): string { - if (this.value === null || this.value === undefined) { - return "[???]"; + if (this.value === null) { + return "-"; } if (this.value === 0) { return zeroToDash ? "-" : `0 ${this.unit}`; @@ -39,20 +41,20 @@ export class Value { return formatNumber(this.value, "de-DE", `0.${-rest}-${-rest}`) + ' ' + this.unit; } - plus(other: Value | null | undefined): Value | null { + plus(other: Value): Value { return this.operateSameUnit("plus", other, (a, b) => a + b); } - minus(other: Value | null | undefined): Value | null { + minus(other: Value): Value { return this.operateSameUnit("minus", other, (a, b) => a - b); } - operateSameUnit(operationName: string, other: Value | null | undefined, operation: (a: number, b: number) => number): Value | null { - if (!other) { - return null; + operateSameUnit(name: string, other: Value, operation: (a: number, b: number) => number): Value { + if (this.value === null || other.value === null) { + return Value.NONE; } if (this.unit !== other.unit) { - throw new Error(`Operation '${operationName} needs units to be the same: this=${this}, other=${other}`); + throw new Error(`Operation '${name} needs units to be the same: this=${this}, other=${other}`); } const decimals = Math.max(this.precision, other.precision); const seconds = Math.max(this.seconds, other.seconds); @@ -60,25 +62,27 @@ export class Value { return new Value(operation(this.value, other.value), decimals, seconds, this.unit, date); } - static of(series: Series, value: number | null | undefined, date: Date | null | undefined): Value | null { - if (value === null || value === undefined) { - return null; + static of(series: Series, value: number | null | undefined, date: Date | null | undefined): Value { + value = value === undefined ? null : value; + date = date === undefined ? null : date; + if (value === null) { + return this.NONE; } - if (date === null || date === undefined) { + if (date === null) { throw new Error("When 'value' is set, 'last' must be set too, but isn't!") } return new Value(value, series.precision, series.seconds, series.unit, date); } - static ofPoint(response: PointResponse, seriesIndex: number, pointIndex: number, valueIndex: number): Value | null { + static ofPoint(response: PointResponse, seriesIndex: number, pointIndex: number, valueIndex: number): Value { const series = response.series[seriesIndex]; if (!series) { - return null; + return this.NONE; } const point = series.points[pointIndex]; if (!point) { - return null; + return this.NONE; } const date = new Date(point[0] * 1000); diff --git a/src/main/angular/src/app/series/select/series-select.html b/src/main/angular/src/app/series/select/series-select.html index 8ed6faa..c7844e1 100644 --- a/src/main/angular/src/app/series/select/series-select.html +++ b/src/main/angular/src/app/series/select/series-select.html @@ -8,7 +8,7 @@ @for (series of series; track series.id) { } diff --git a/src/main/angular/src/index.html b/src/main/angular/src/index.html index d83079f..a1d0c5f 100644 --- a/src/main/angular/src/index.html +++ b/src/main/angular/src/index.html @@ -2,11 +2,11 @@ - Angular + Data2025 - + diff --git a/src/main/angular/src/styles.less b/src/main/angular/src/styles.less index e8cf5cc..0edb031 100644 --- a/src/main/angular/src/styles.less +++ b/src/main/angular/src/styles.less @@ -4,6 +4,7 @@ body { margin: 0; font-family: sans-serif; font-size: 4vw; + user-select: none; } div { @@ -46,6 +47,7 @@ div { > .SectionHeading { color: dimgray; + > .SectionHeadingText { font-size: 70%; font-style: italic;