- add chartjs-plugin-zoom via npm

- add label to timeseries graph only for 08:00 and 18:00
This commit is contained in:
Arno Kaimbacher 2021-10-01 14:37:43 +02:00
parent 4241bd2cb9
commit dbf8aa495e
10 changed files with 2198 additions and 2258 deletions

View file

@ -222,8 +222,15 @@ CREATE src/app/app-router.service.ts (138 bytes)
=============================== chart.js ====================================== =============================== chart.js ======================================
npm install --save chart.js npm install --save chart.js
import { Chart } from 'chart.js';
npm install --save moment npm install --save moment
npm install moment chartjs-adapter-moment --save npm install moment chartjs-adapter-moment --save
import 'chartjs-adapter-moment'; import 'chartjs-adapter-moment';
npm install chartjs-plugin-zoom
import zoomPlugin from 'chartjs-plugin-zoom';
Chart.register(zoomPlugin);

4242
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -64,6 +64,7 @@
"bulma": "^0.9.3", "bulma": "^0.9.3",
"chart.js": "^3.5.1", "chart.js": "^3.5.1",
"chartjs-adapter-moment": "^1.0.0", "chartjs-adapter-moment": "^1.0.0",
"chartjs-plugin-zoom": "^1.1.1",
"core-js": "^3.16.0", "core-js": "^3.16.0",
"leaflet": "^1.7.1", "leaflet": "^1.7.1",
"moment": "^2.29.1", "moment": "^2.29.1",

View file

@ -46,16 +46,13 @@
<section id="app" class="hero"> <section id="app" class="hero">
<div class="main columns"> <div>
<div class="canvas-area is-8 column"> <router-outlet></router-outlet>
<!-- <div id="div-map">
<app-map [mapId]="'map'" [mapOptions]="mapOptions" [serviceUrl]="providerUrl" [baseMaps]="baseMaps" </div>
(onSelected)="onStationSelected($event)" (onMapInitializedEvent)="onMapInitialized($event)"> <!-- <div class="canvas-area is-8 column">
</app-map>
</div> -->
<router-outlet></router-outlet> <router-outlet></router-outlet>
</div> </div>
@ -64,25 +61,12 @@
<app-messages></app-messages> <app-messages></app-messages>
</div> </div>
</div> </div>
</div> </div> -->
<!-- <app-dashboard></app-dashboard> --> <!-- <app-dashboard></app-dashboard> -->
<!-- <span>{{ name }} app is running!</span> --> <!-- <span>{{ name }} app is running!</span> -->
<!-- <div>
<n52-station-map-selector [mapId]="'timeseries'" [serviceUrl]="providerUrl"
[mapOptions]="mapOptions"></n52-station-map-selector>
</div>
<div>Is loading: {{loadingStations}}</div> -->
<!-- <h1>{{ name }}</h1>
<nav>
<a routerLink="/dashboard">Dashboard</a>
<a routerLink="/map">Map</a>
</nav>-->
<!-- <router-outlet></router-outlet> -->
<!-- <app-messages></app-messages> -->
</section> </section>

View file

@ -18,7 +18,7 @@ import { deserialize } from 'class-transformer';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { InternalIdHandler } from '../../common/components/services/internal-id-handler.service'; import { InternalIdHandler } from '../../common/components/services/internal-id-handler.service';
import moment from "moment"; import * as moment from "moment";
import { Timespan } from '../../shared/models/timespan'; import { Timespan } from '../../shared/models/timespan';
import { GeomonDataset } from '../../shared/models/dataset'; import { GeomonDataset } from '../../shared/models/dataset';

View file

@ -1,4 +1,16 @@
<!-- <h2>Bar Chart</h2>
<canvas id="line-chart" width="800" height="450"></canvas> --> <div class="main columns">
<geomon-timeseries-chart [datasetOptions]="datasetOptions"
[datasetIds]="datasetIds" [timeInterval]="datasetService.timespan"></geomon-timeseries-chart> <div class="canvas-area is-8 column">
<!-- <h2>Bar Chart</h2>
<canvas id="line-chart" width="800" height="450"></canvas> -->
<geomon-timeseries-chart [datasetOptions]="datasetOptions"
[datasetIds]="datasetIds" [timeInterval]="datasetService.timespan"></geomon-timeseries-chart>
</div>
<div class="input-area is-4 column">
Test
</div>
</div>

View file

@ -5,8 +5,20 @@
</n52-station-map-selector> </n52-station-map-selector>
</div> --> </div> -->
<div id="div-map"> <div class="main columns">
<app-map [mapId]="'map'" [mapOptions]="mapOptions" [serviceUrl]="providerUrl" [baseMaps]="baseMaps"
(onSelected)="onStationSelected($event)" (onMapInitializedEvent)="onMapInitialized($event)" class="vbox boxItem fullHeight"> <div class="canvas-area is-8 column">
</app-map> <div id="div-map">
<app-map [mapId]="'map'" [mapOptions]="mapOptions" [serviceUrl]="providerUrl" [baseMaps]="baseMaps"
(onSelected)="onStationSelected($event)" (onMapInitializedEvent)="onMapInitialized($event)"
class="vbox boxItem fullHeight">
</app-map>
</div>
</div>
<div class="input-area is-4 column">
</div>
</div> </div>

View file

@ -8,11 +8,13 @@ import { DatasetService } from '../../../app/services/dataset.service';
import { Timespan } from '../../../shared/models/timespan'; import { Timespan } from '../../../shared/models/timespan';
import { TimeService } from '../../core/time/time.service'; import { TimeService } from '../../core/time/time.service';
import moment from 'moment'; import * as moment from 'moment';
// import 'moment-duration-format'; // import 'moment-duration-format';
import { TimeValueTuple, Data } from '../../../shared/models/dataset'; import { TimeValueTuple, Data } from '../../../shared/models/dataset';
import 'chartjs-adapter-moment'; import 'chartjs-adapter-moment';
import { MAT_SELECTION_LIST_VALUE_ACCESSOR } from '@angular/material/list';
import zoomPlugin from 'chartjs-plugin-zoom';
Chart.register(zoomPlugin);
@Component({ @Component({
selector: 'geomon-timeseries-chart', selector: 'geomon-timeseries-chart',
@ -159,8 +161,57 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit {
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) {
return moment(b[0]).format('YYYY-MM-DD');
});
// Object.keys(grouped_items).forEach(function (value: any, key: string) {
for (let [key, value] of grouped_items) {
// grouped_items[key] = findMinMax(grouped_items.get(key));
// let test = grouped_items.get(key);
let reducedValues = findMinMax(grouped_items.get(key));
let ar = new Array<TimeValueTuple>(reducedValues.min);
// ar.push(reducedValues.min, reducedValues.max);
grouped_items.set(key, ar);
}
function groupBy(list: Array<[number, number]>, keyGetter: any): Map<string, TimeValueTuple[]> {
const map = new Map();
list.forEach((item: any) => {
const key = keyGetter(item);
const collection = map.get(key);
if (!collection) {
map.set(key, [item]);
} else {
collection.push(item);
}
});
return map;
}
function findMinMax(values: TimeValueTuple[]) {
var res = { min: values[0], max: values[0] };
values.forEach(function (val: [number, number]) {
res.min = val[0] < res.min[0] ? val : res.min;
res.max = val[0] > res.max[0] ? val : res.max;
});
return res;
}
let values = Array.from( grouped_items.values() );
values = [].concat(...values);
let xLabels = values.map(function (label) {
let date = moment(label[0]).format("DD/MM HH:mm");
return date;
});
// console.log(values);
// this.datasetMap.get(dataset.internalId).data = data; // this.datasetMap.get(dataset.internalId).data = data;
this.addData(this.lineChart, dataset, rawdata); this.addData(this.lineChart, dataset, rawdata, xLabels);
} }
} }
@ -181,7 +232,7 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit {
return data; return data;
} }
private addData(chart: Chart, dataset: GeomonTimeseries, data: GeomonTimeseriesData): void { private addData(chart: Chart, dataset: GeomonTimeseries, data: GeomonTimeseriesData, xLabels: string[]): void {
let labels = data.values.map(function (label) { let labels = data.values.map(function (label) {
let date = moment(label[0]).format("YYYY-MM-DD HH:mm"); let date = moment(label[0]).format("YYYY-MM-DD HH:mm");
@ -205,12 +256,28 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit {
label: dataset.label, label: dataset.label,
// backgroundColor: 'rgba(99, 255, 132, 0.2)', // backgroundColor: 'rgba(99, 255, 132, 0.2)',
backgroundColor: color, backgroundColor: color,
// borderColor: 'rgba(99, 255, 132, 1)', borderColor: color, //'rgba(99, 255, 132, 1)',
borderWidth: 1, borderWidth: 1,
data: values, data: values,
} }
// You add the newly created dataset to the list of `data` // You add the newly created dataset to the list of `data`
chart.data.datasets.push(newDataset); 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(); chart.update();
this.width = this.calculateWidth(); this.width = this.calculateWidth();
} }
@ -252,20 +319,36 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit {
] ]
}, },
options: { options: {
plugins: {
zoom: {
pan: {
enabled: true
},
zoom: {
wheel: {
enabled: true,
},
pinch: {
enabled: true
},
mode: 'xy',
}
}
},
scales: { scales: {
y: { y: {
suggestedMin: 0, // minimum will be 0, unless there is a lower value. suggestedMin: 0, // minimum will be 0, unless there is a lower value.
// OR // // OR //
beginAtZero: true // minimum value will be 0. beginAtZero: true // minimum value will be 0.
}, },
x: { x: {
type: 'time', type: 'time',
time: { time: {
unit: 'minute', unit: 'minute',
displayFormats: { displayFormats: {
minute: "DD/MM HH:mm", minute: "DD/MM HH:mm",
hour: "DD/MM HH:mm", hour: "DD/MM HH:mm",
day: "dd/MM", day: "dd/MM",
week: "dd/MM", week: "dd/MM",
@ -274,12 +357,21 @@ export class GeomonTimeseriesChartComponent implements AfterViewInit {
year: "yyyy", year: "yyyy",
} }
}, },
// ticks: {
// labelOffset: 10 ticks: {
// }
// callback: function(val, index) {
// // Hide the label of every 2nd dataset
// return index % 2 === 0 ? (val) : '';
// },
// autoSkip: true,
// maxRotation: 0,
// minRotation: 0
}
} }
}, },
} }
// options: { // options: {
// title: { // title: {
// display: true, // display: true,

View file

@ -132,11 +132,11 @@ export interface GeomonData { }
export class GeomonTimeseriesData implements GeomonData { export class GeomonTimeseriesData implements GeomonData {
referenceValues: ReferenceValues<TimeValueTuple> = {}; referenceValues: ReferenceValues<TimeValueTuple> = {};
valueBeforeTimespan: TimeValueTuple; valueBeforeTimespan: [number, number]; // TimeValueTuple;
valueAfterTimespan: TimeValueTuple; valueAfterTimespan: [number, number]; //TimeValueTuple;
constructor( constructor(
public values: TimeValueTuple[], public values: Array<[number, number]>,
) { } ) { }
} }

View file

@ -94,7 +94,7 @@ ul {
} }
.main { .main {
padding-top: 51px; padding-top: 65px;
// display: flex; // display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;