diff --git a/src/main/angular/src/app/app.config.ts b/src/main/angular/src/app/app.config.ts index 2155a8a..1363f71 100644 --- a/src/main/angular/src/app/app.config.ts +++ b/src/main/angular/src/app/app.config.ts @@ -9,12 +9,12 @@ import {registerLocaleData} from '@angular/common'; import localeDe from '@angular/common/locales/de'; import localeDeExtra from '@angular/common/locales/extra/de'; import {stompServiceFactory} from './common'; -import {Chart, registerables} from 'chart.js'; +import {BarController, BarElement, Chart, Legend, LinearScale, TimeScale, Tooltip} from 'chart.js'; import 'chartjs-adapter-date-fns'; registerLocaleData(localeDe, 'de-DE', localeDeExtra); -Chart.register(...registerables); +Chart.register(TimeScale, LinearScale, BarController, BarElement, Tooltip, Legend); export const appConfig: ApplicationConfig = { providers: [ diff --git a/src/main/angular/src/app/app.html b/src/main/angular/src/app/app.html index 8fff476..a79f044 100644 --- a/src/main/angular/src/app/app.html +++ b/src/main/angular/src/app/app.html @@ -9,16 +9,6 @@ {{ menuService.title }} - @if (locationService.id !== null) { - - } - diff --git a/src/main/angular/src/app/app.ts b/src/main/angular/src/app/app.ts index 5d2810e..00b13bc 100644 --- a/src/main/angular/src/app/app.ts +++ b/src/main/angular/src/app/app.ts @@ -1,13 +1,12 @@ import {Component, OnDestroy, OnInit} from '@angular/core'; import {Router, RouterLink, RouterLinkActive, RouterOutlet} from '@angular/router'; import {FaIconComponent} from '@fortawesome/angular-fontawesome'; -import {faBars, faBookmark as faBookmarkSolid, faGears} from '@fortawesome/free-solid-svg-icons'; +import {faBars, faGears} from '@fortawesome/free-solid-svg-icons'; import {MenuService} from './menu-service'; import {Location} from './location/Location'; import {LocationService} from './location/location-service'; import {WebsocketService} from './common'; -import {faBookmark as faBookmarkRegular, faHome} from '@fortawesome/free-regular-svg-icons'; -import {ConfigService} from './config.service'; +import {faHome} from '@fortawesome/free-regular-svg-icons'; @Component({ selector: 'app-root', @@ -21,10 +20,6 @@ export class App implements OnInit, OnDestroy { protected readonly location = location; - protected readonly faBookmarkRegular = faBookmarkRegular; - - protected readonly faBookmarkSolid = faBookmarkSolid; - protected readonly faGears = faGears; protected readonly faBars = faBars; @@ -35,7 +30,6 @@ export class App implements OnInit, OnDestroy { constructor( readonly locationService: LocationService, - readonly configService: ConfigService, readonly menuService: MenuService, readonly router: Router, readonly ws: WebsocketService, diff --git a/src/main/angular/src/app/location/energy/charts/energy-charts.ts b/src/main/angular/src/app/location/energy/charts/energy-charts.ts index 2904bf7..2d2d063 100644 --- a/src/main/angular/src/app/location/energy/charts/energy-charts.ts +++ b/src/main/angular/src/app/location/energy/charts/energy-charts.ts @@ -1,4 +1,4 @@ -import {Component, Input, ViewChild} from '@angular/core'; +import {AfterViewInit, Component, Inject, Input, LOCALE_ID, ViewChild} from '@angular/core'; import {Interval} from '../../../series/Interval'; import {PointService} from '../../../point/point-service'; import {Location} from '../../Location'; @@ -7,7 +7,6 @@ import {ChartConfiguration} from 'chart.js'; import {de} from 'date-fns/locale'; import {PointSeries} from '../../../point/PointSeries'; import {formatNumber} from '@angular/common'; -import {PointResponse} from '../../../point/PointResponse'; const COLOR_BACK_PURCHASE = "#ffb9b9"; const COLOR_BACK_DELIVER = "#ff59ff"; @@ -23,7 +22,10 @@ const COLOR_BACK_CONSUME = "#ffc07a"; templateUrl: './energy-charts.html', styleUrl: './energy-charts.less', }) -class EnergyCharts { +export class EnergyCharts implements AfterViewInit { + + @ViewChild(BaseChartDirective) + chart?: BaseChartDirective; @Input() unit: string = ""; @@ -37,62 +39,112 @@ class EnergyCharts { @Input() minY: number | undefined = undefined; - private _offset!: number | null; + @Input() + interval!: Interval; @Input() - set offset(value: number | null) { - this._offset = value; - this.fetch(); - } - - @ViewChild(BaseChartDirective) - chart?: BaseChartDirective; - - private _interval!: Interval | null; + location!: Location; @Input() - set interval(value: Interval | null) { - this._interval = value; - this.fetch(); - } + offset: number = 0; - private _location!: Location | null; + protected data: ChartConfiguration['data'] = { + datasets: [], + }; - @Input() - set location(value: Location | null) { - this._location = value; - this.fetch(); - } + protected options: ChartConfiguration['options'] = { + responsive: true, + maintainAspectRatio: false, + animation: false, + scales: { + x: { + type: 'time', + time: { + displayFormats: { + minute: "HH:mm", + hour: "HH:mm", + day: "dd.MM" + }, + }, + adapters: { + date: { + locale: de + }, + }, + bounds: 'ticks', + }, + y: { + max: this.maxY, + min: this.minY, + } + }, + interaction: { + mode: 'index', + intersect: false + }, + plugins: { + legend: { + display: false, + }, + tooltip: { + mode: 'index', + intersect: false, + itemSort: (a, b) => b.datasetIndex - a.datasetIndex, + callbacks: { + title: (items) => { + const date = new Date(items[0].parsed.x || 0); + const d = date.toLocaleString(this.locale, { + dateStyle: 'long', + }); + const t = date.toLocaleString(this.locale, { + timeStyle: 'long', + }); + return `${d}\n${t}`; + }, + label: ((ctx: any) => { + const groups = /^.*Energie (?.+)\[(?.+)]$/.exec(ctx.dataset.label || '')?.groups; + if (groups) { + const value = ctx.parsed.y === null ? '-' : formatNumber(Math.abs(ctx.parsed.y), this.locale, '0.2-2'); + return `${value} ${groups['unit']} ${groups['name']}`; + } + return ctx.dataset.label; + }) as any, + }, + }, + }, + }; constructor( readonly pointService: PointService, + @Inject(LOCALE_ID) readonly locale: string, ) { // } - fetch(): void { - if (!this._location || !this._interval || this._offset == null) { - return; - } + ngAfterViewInit(): void { const series = [ - this._location.energyPurchase, - this._location.energyDeliver, - this._location.energyProduce, + this.location.energyPurchase, + this.location.energyDeliver, + this.location.energyProduce, ]; - const location = this._location; - const interval = this._interval; - const offset = this._offset; + const location = this.location; + const interval = this.interval; + const offset = this.offset; this.pointService.relative(series, interval, offset, 1, interval.inner, result => { + this.data.datasets.length = 0; + const xScale = this.chart?.chart?.options?.scales?.['x']; + if (xScale) { + xScale.min = result ? result.begin.getTime() : undefined; + xScale.max = result ? result.end.getTime() - (this.interval?.inner?.millis || 0) : undefined; + } const energyPurchase = result.series.filter(s => s.series.id === location.energyPurchase?.id)[0] || null; const energyDeliver = result.series.filter(s => s.series.id === location.energyDeliver?.id)[0] || null; const energyProduce = result.series.filter(s => s.series.id === location.energyProduce?.id)[0] || null; const energySelf = energyProduce?.merge(energyDeliver, "Energie Selbst", (a, b) => a - b) || null; - this.data.datasets.length = 0; this.add(energyDeliver, COLOR_BACK_DELIVER, -1, "a"); this.add(energySelf, COLOR_BACK_SELF, 1, "a"); this.add(energyPurchase, COLOR_BACK_PURCHASE, 1, "a"); - this.options = this.newOptions(result); - this.chart?.update(); + this.chart?.chart?.update(); }); } @@ -114,69 +166,4 @@ class EnergyCharts { }); } - protected data: ChartConfiguration['data'] = { - datasets: [], - }; - - protected options: ChartConfiguration['options'] = {}; - - private newOptions(result: PointResponse): ChartConfiguration['options'] { - return { - responsive: true, - maintainAspectRatio: false, - animation: false, - scales: { - x: { - type: 'time', - min: result.begin.getTime(), - max: result.end.getTime() - (this._interval?.inner?.millis || 0), - time: { - displayFormats: { - minute: "HH:mm", - hour: "HH:mm", - day: "dd.MM" - }, - }, - adapters: { - date: { - locale: de - }, - }, - bounds: 'ticks', - }, - y: { - max: this.maxY, - min: this.minY, - } - }, - - interaction: { - mode: 'index', - intersect: false - }, - plugins: { - legend: { - display: false, - }, - tooltip: { - mode: 'index', - intersect: false, - itemSort: (a, b) => b.datasetIndex - a.datasetIndex, - callbacks: { - label: (ctx) => { - const groups = /^.*Energie (?.+)\[(?.+)]$/.exec(ctx.dataset.label || '')?.groups; - if (groups) { - const value = ctx.parsed.y === null ? '-' : formatNumber(Math.abs(ctx.parsed.y), 'de-DE', '0.2-2'); - return `${value} ${groups['unit']} ${groups['name']}`; - } - return ctx.dataset.label; - }, - }, - }, - }, - }; - } - } - -export default EnergyCharts diff --git a/src/main/angular/src/app/location/energy/location-energy.ts b/src/main/angular/src/app/location/energy/location-energy.ts index b84b249..eed8513 100644 --- a/src/main/angular/src/app/location/energy/location-energy.ts +++ b/src/main/angular/src/app/location/energy/location-energy.ts @@ -7,14 +7,13 @@ import {PointService} from '../../point/point-service'; import {SeriesService} from '../../series/series-service'; import {Subscription} from 'rxjs'; import {Value} from '../../series/Value'; -import EnergyCharts from './charts/energy-charts'; import {ConfigService} from '../../config.service'; +import {EnergyCharts} from './charts/energy-charts'; @Component({ selector: 'app-location-energy', imports: [ EnergyCharts, - EnergyCharts ], templateUrl: './location-energy.html', styleUrl: './location-energy.less',