- toggleVisibility() and toggleSelection() for legend entries
- use FontAwesomeModule also in app.module - select and hide events in geomon-timeseries-chart.component.ts
This commit is contained in:
parent
91cd763da0
commit
e797122055
6 changed files with 183 additions and 34 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
<div id="geomon-legend-entry" class="legendItem" style="position: relative;" [ngStyle]="{'border-color': datasetOption?.color}"
|
||||
[ngClass]="{'selected': selected}" (click)="toggleVisibility(); $event.stopPropagation();">
|
||||
[ngClass]="{'selected': selected}" (click)="toggleSelection();">
|
||||
<!-- <div class="loading-overlay" *ngIf="loading" [ngStyle]="{'background-color': datasetOption?.color}">
|
||||
<div class="fa fa-refresh fa-spin fa-3x fa-fw"></div>
|
||||
</div> -->
|
||||
|
@ -36,6 +36,11 @@
|
|||
<div class="small-label" *ngIf="categoryLabel != phenomenonLabel">
|
||||
<label>{{categoryLabel}}</label>
|
||||
</div>
|
||||
<div class="legendicons">
|
||||
<!-- <span class="fa" [ngClass]="{'fa-eye-slash': datasetOption?.visible, 'fa-eye': !datasetOption?.visible}" (click)="toggleVisibility(); $event.stopPropagation();"></span> -->
|
||||
<fa-icon [icon]="datasetOption?.visible ? faEye : faEyeSlash" (click)="toggleVisibility(); $event.stopPropagation();"></fa-icon>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -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<Date> = new EventEmitter();
|
||||
|
||||
faEye = faEye;
|
||||
faEyeSlash= faEyeSlash;
|
||||
|
||||
// public firstValue: FirstLastValue;
|
||||
// public lastValue: FirstLastValue;
|
||||
public hasData = true;
|
||||
|
|
|
@ -16,5 +16,5 @@
|
|||
|
||||
#line-chart {
|
||||
|
||||
border: 1px solid black;
|
||||
// border: 1px solid black;
|
||||
}
|
|
@ -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<string, DataConst> = new Map();
|
||||
protected listOfUoms: string[] = [];
|
||||
protected preparedData: InternalDataEntry[] = [];
|
||||
|
||||
// private loadingData: Set<string> = new Set();
|
||||
|
||||
|
@ -87,36 +91,40 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit, DoCheck {
|
|||
private selectedDatasetIdsDiffer: IterableDiffer<string>;
|
||||
|
||||
constructor(
|
||||
protected iterableDiffers: IterableDiffers,
|
||||
protected datasetIdResolver: InternalIdHandler,
|
||||
protected datasetApiService: DatasetApiService,
|
||||
protected timeService: TimeService,
|
||||
public datasetService: DatasetService<DatasetOptions>,
|
||||
) { }
|
||||
) {
|
||||
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);
|
||||
}
|
||||
|
||||
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`
|
||||
chart.data.datasets.push(newDataset);
|
||||
chart.options.scales.x.ticks.callback = (val, index) => {
|
||||
// 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: {
|
||||
|
|
40
src/shared/models/chart.ts
Normal file
40
src/shared/models/chart.ts
Normal file
|
@ -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;
|
||||
}
|
Loading…
Add table
Reference in a new issue