From e79712205599eb844d66d904c5bd891bf333170b Mon Sep 17 00:00:00 2001 From: Arno Kaimbacher Date: Wed, 6 Oct 2021 15:20:52 +0200 Subject: [PATCH] - toggleVisibility() and toggleSelection() for legend entries - use FontAwesomeModule also in app.module - select and hide events in geomon-timeseries-chart.component.ts --- src/app/app.module.ts | 5 +- .../legend-entry/legend-entry.component.html | 7 +- .../legend-entry/legend-entry.component.ts | 5 + .../geomon-timeseries-chart.component.scss | 2 +- .../geomon-timeseries-chart.component.ts | 158 ++++++++++++++---- src/shared/models/chart.ts | 40 +++++ 6 files changed, 183 insertions(+), 34 deletions(-) create mode 100644 src/shared/models/chart.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index bda6653..6c2faf1 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -36,6 +36,7 @@ import {MatBadgeModule} from '@angular/material/badge'; import { TimeService } from '../common/core/time/time.service'; import { InternalIdHandler } from '../common/components/services/internal-id-handler.service'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; @NgModule({ // declarations: The components, directives, and pipes that belong to this NgModule. @@ -44,7 +45,9 @@ import { InternalIdHandler } from '../common/components/services/internal-id-han // DatasetByStationSelectorComponent // ], // imports: Other modules whose exported classes are needed by component templates declared in this NgModule. - imports: [BrowserModule, HttpClientModule, AppRoutingModule, ComponentsModule, GraphjsModule, BrowserAnimationsModule, MatDialogModule, MatListModule, MatBadgeModule], + imports: [ + BrowserModule, HttpClientModule, AppRoutingModule, ComponentsModule, GraphjsModule, BrowserAnimationsModule, MatDialogModule, MatListModule, MatBadgeModule, + FontAwesomeModule], providers: [ MarkerService, PopupService, HttpService, DatasetApiService, StationService, MessageService, MapService,DatasetService, InternalIdHandler, TimeService diff --git a/src/app/components/legend-entry/legend-entry.component.html b/src/app/components/legend-entry/legend-entry.component.html index 5dfc2f1..7590e1b 100644 --- a/src/app/components/legend-entry/legend-entry.component.html +++ b/src/app/components/legend-entry/legend-entry.component.html @@ -1,6 +1,6 @@
+ [ngClass]="{'selected': selected}" (click)="toggleSelection();"> @@ -36,6 +36,11 @@
+
+ + +
+
diff --git a/src/app/components/legend-entry/legend-entry.component.ts b/src/app/components/legend-entry/legend-entry.component.ts index 9979cb7..1605094 100644 --- a/src/app/components/legend-entry/legend-entry.component.ts +++ b/src/app/components/legend-entry/legend-entry.component.ts @@ -6,6 +6,8 @@ import { TimeInterval } from '../../../shared/models/timespan'; import { DatasetApiService } from '../../services/dataset-api.service'; import { InternalIdHandler, InternalDatasetId } from '../../../common/components/services/internal-id-handler.service'; import { DatasetOptions } from '../../../shared/models/options'; +import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons'; + @Component({ selector: 'geomon-legend-entry', templateUrl: './legend-entry.component.html', @@ -18,6 +20,9 @@ export class LegendEntryComponent { @Output() public onSelectDate: EventEmitter = new EventEmitter(); + faEye = faEye; + faEyeSlash= faEyeSlash; + // public firstValue: FirstLastValue; // public lastValue: FirstLastValue; public hasData = true; diff --git a/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.scss b/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.scss index 392e9b5..487449c 100644 --- a/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.scss +++ b/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.scss @@ -16,5 +16,5 @@ #line-chart { - border: 1px solid black; + // border: 1px solid black; } \ No newline at end of file diff --git a/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.ts b/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.ts index aa2c565..941d0d1 100644 --- a/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.ts +++ b/src/common/graphjs/geomon-timeseries-chart/geomon-timeseries-chart.component.ts @@ -1,4 +1,6 @@ -import { Input, Component, AfterViewInit, ViewChild, ElementRef, SimpleChanges, DoCheck, IterableDiffer} from '@angular/core'; +import { + Input, Component, AfterViewInit, ViewChild, ElementRef, SimpleChanges, DoCheck, IterableDiffer, IterableDiffers +} from '@angular/core'; // import * as d3 from 'd3'; import { Chart, registerables } from 'chart.js'; @@ -19,6 +21,7 @@ import zoomPlugin from 'chartjs-plugin-zoom'; Chart.register(zoomPlugin); import { InternalIdHandler, InternalDatasetId } from '../../../common/components/services/internal-id-handler.service'; +import { InternalDataEntry } from '../../../shared/models/chart'; // interface Color { // borderColor: string, // pointBackgroundColor: string @@ -71,6 +74,7 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck { // data types protected datasetMap: Map = new Map(); protected listOfUoms: string[] = []; + protected preparedData: InternalDataEntry[] = []; // private loadingData: Set = new Set(); @@ -87,36 +91,40 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck { private selectedDatasetIdsDiffer: IterableDiffer; constructor( + protected iterableDiffers: IterableDiffers, protected datasetIdResolver: InternalIdHandler, protected datasetApiService: DatasetApiService, protected timeService: TimeService, public datasetService: DatasetService, - ) { } + ) { + this.selectedDatasetIdsDiffer = this.iterableDiffers.find([]).create(); + } public ngDoCheck(): void { - // const selectedDatasetIdsChanges = this.selectedDatasetIdsDiffer.diff(this.selectedDatasetIds); - // if (selectedDatasetIdsChanges) { - // selectedDatasetIdsChanges.forEachAddedItem((addedItem) => { - // this.setSelectedId(addedItem.item); - // }); - // selectedDatasetIdsChanges.forEachRemovedItem((removedItem) => { - // this.removeSelectedId(removedItem.item); - // }); - // } + const selectedDatasetIdsChanges = this.selectedDatasetIdsDiffer.diff(this.selectedDatasetIds); + if (selectedDatasetIdsChanges) { + selectedDatasetIdsChanges.forEachAddedItem((addedItem) => { + this.setSelectedId(addedItem.item); + }); + selectedDatasetIdsChanges.forEachRemovedItem((removedItem) => { + this.removeSelectedId(removedItem.item); + }); + } } protected setSelectedId(internalId: string): void { - // const internalEntry = this.preparedData.find((e) => e.internalId === internalId); - // if (internalEntry) { internalEntry.selected = true; } - // this.redrawCompleteGraph(); + const internalEntry = this.preparedData.find((e) => e.internalId === internalId); + if (internalEntry) { internalEntry.selected = true; } + this.redrawCompleteGraph(); } protected removeSelectedId(internalId: string): void { - // const internalEntry = this.preparedData.find((e) => e.internalId === internalId); - // if (internalEntry) { internalEntry.selected = false; } + const internalEntry = this.preparedData.find((e) => e.internalId === internalId); + if (internalEntry) { internalEntry.selected = false; } + this.redrawCompleteGraph(); } - ngAfterViewInit(): void { // this.createSvg(); + ngAfterViewInit(): void { this.canvas = document.getElementById("line-chart") as HTMLCanvasElement; @@ -210,7 +218,7 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck { if (rawdata.valueBeforeTimespan) { rawdata.values.unshift(rawdata.valueBeforeTimespan); } if (rawdata.valueAfterTimespan) { rawdata.values.push(rawdata.valueAfterTimespan); } - const data = this.generalizeData(rawdata, this.width, this.timespan); + // const data = this.generalizeData(rawdata, this.width, this.timespan); let grouped_items = groupBy(rawdata.values, function (b: TimeValueTuple) { @@ -303,19 +311,99 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck { for (let i = 0; i < 6; i++) { color += letters[Math.floor(Math.random() * 16)]; } + + const datasetIdx = this.preparedData.findIndex((e) => e.internalId === dataset.internalId); let datasetOptions = this.datasetOptions.get(dataset.internalId); datasetOptions.color = color; - var newDataset = { - label: dataset.label, - // backgroundColor: 'rgba(99, 255, 132, 0.2)', - backgroundColor: color, - borderColor: color, //'rgba(99, 255, 132, 1)', - borderWidth: 1, + + let dataEntry: InternalDataEntry = { + internalId: dataset.internalId, + selected: this.selectedDatasetIds.indexOf(dataset.internalId) >= 0, + // data: datasetOptions.visible ? data.values.map(d => ({ timestamp: d[0], value: d[1] })) : [], data: values, + options: datasetOptions, + axisOptions: { + uom: dataset.uom, + label: dataset.label, + zeroBased: datasetOptions.zeroBasedYAxis, + // yAxisRange: options.yAxisRange, + autoRangeSelection: datasetOptions.autoRangeSelection, + separateYAxis: datasetOptions.separateYAxis, + parameters: { + feature: dataset.parameters.feature, + phenomenon: dataset.parameters.phenomenon, + offering: dataset.parameters.offering + } + }, + referenceValueData: [], + visible: datasetOptions.visible, + // bar: barConfig + }; + + if (datasetIdx >= 0) { + this.preparedData[datasetIdx] = dataEntry; + } else { + this.preparedData.push(dataEntry); } - // You add the newly created dataset to the list of `data` - chart.data.datasets.push(newDataset); - chart.options.scales.x.ticks.callback = (val, index) => { + + this.processData(dataEntry); + // this.redrawCompleteGraph(); + + // var newDataset = { + // label: dataEntry.axisOptions.label, + // selected: dataEntry.selected, + // backgroundColor: color, + // borderColor: color, + // borderWidth: 1, + // data: values, + // } + // // You add the newly created dataset to the list of `data` + // chart.data.datasets.push(newDataset); + // chart.options.scales.x.ticks.callback = (val, index) => { + // // // Hide the label of every 2nd dataset + // // return xLabels.includes(val.toString()) ? val : null; + // // return index % 2 === 0 ? (val) : ''; + // let valTime = moment(val, "DD/MM HH:mm").format("HH:mm"); + // if (valTime == "08:00" || valTime == "18:00"){ + // return val; + // } else { + // return null; + // } + + // } + // chart.options.scales.y.ticks.callback = (value, index, values) => { + // return value + '°'; + // } + + chart.update(); + this.width = this.calculateWidth(); + } + + private processData(dataEntry: InternalDataEntry, datasetIndex?: number): void { + + let dataset; + + if (datasetIndex != null) { + dataset = this.lineChart.data.datasets[datasetIndex]; + dataset.label = dataEntry.axisOptions.label; + dataset.borderWidth = dataEntry.selected ? 4 : 1; + // dataset.hidden = dataEntry.selected; + } else { + dataset = { + label: dataEntry.axisOptions.label, + // selected: dataEntry.selected, + // backgroundColor: 'rgba(99, 255, 132, 0.2)', + backgroundColor: dataEntry.options.color, + borderColor: dataEntry.options.color, //'rgba(99, 255, 132, 1)', + borderWidth: 1, + data: dataEntry.data, + }; + this.lineChart.data.datasets.push(dataset); + } + + // You add the newly created dataset to the list of `data` + // this.lineChart.data.datasets.push(newDataset); + this.lineChart.options.scales.x.ticks.callback = (val, index) => { // // Hide the label of every 2nd dataset // return xLabels.includes(val.toString()) ? val : null; // return index % 2 === 0 ? (val) : ''; @@ -327,12 +415,17 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck { } } - chart.options.scales.y.ticks.callback = (value, index, values) => { + this.lineChart.options.scales.y.ticks.callback = (value, index, values) => { return value + '°'; } - - chart.update(); - this.width = this.calculateWidth(); + } + + private redrawCompleteGraph(): void { + this.preparedData.forEach((dataEntry: InternalDataEntry, index) => { + + this.processData(dataEntry, index); + }); + this.lineChart.update(); } private initChart(): void { @@ -388,6 +481,9 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck { }, mode: 'xy', } + }, + legend: { + display: false } }, scales: { diff --git a/src/shared/models/chart.ts b/src/shared/models/chart.ts new file mode 100644 index 0000000..b5aceb3 --- /dev/null +++ b/src/shared/models/chart.ts @@ -0,0 +1,40 @@ +import { DatasetOptions } from "./options"; +import { Duration, unitOfTime } from 'moment'; + +export interface DataEntry { + timestamp: number; + value: number; + xDiagCoord?: number; + yDiagCoord?: number; +} + +export interface InternalDataEntry { + internalId: string; + // hoverId: string; + data: number[]; + selected?: boolean; + options: DatasetOptions; + bar?: { + startOf: unitOfTime.StartOf; + period: Duration; + }; + axisOptions: { + uom: string; + label?: string; + zeroBased?: boolean; + // yAxisRange?: MinMaxRange; + autoRangeSelection?: boolean; + separateYAxis?: boolean; + parameters?: { + feature?: { id: string, label: string }; + phenomenon?: { id: string, label: string }; + offering?: { id: string, label: string }; + }; + }; + referenceValueData: { + id: string; + color: string; + data: DataEntry[]; + }[]; + visible: boolean; +} \ No newline at end of file