- add "moment": "^2.29.1" and "chartjs-adapter-moment": "^1.0.0",
- add core module for time.service.ts - add interfaces for timespan.ts an dataset.ts
This commit is contained in:
parent
5f657dc9e4
commit
4241bd2cb9
15 changed files with 706 additions and 57 deletions
|
@ -222,3 +222,8 @@ CREATE src/app/app-router.service.ts (138 bytes)
|
||||||
|
|
||||||
=============================== chart.js ======================================
|
=============================== chart.js ======================================
|
||||||
npm install --save chart.js
|
npm install --save chart.js
|
||||||
|
|
||||||
|
npm install --save moment
|
||||||
|
|
||||||
|
npm install moment chartjs-adapter-moment --save
|
||||||
|
import 'chartjs-adapter-moment';
|
17
package-lock.json
generated
17
package-lock.json
generated
|
@ -27,8 +27,10 @@
|
||||||
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
||||||
"bulma": "^0.9.3",
|
"bulma": "^0.9.3",
|
||||||
"chart.js": "^3.5.1",
|
"chart.js": "^3.5.1",
|
||||||
|
"chartjs-adapter-moment": "^1.0.0",
|
||||||
"core-js": "^3.16.0",
|
"core-js": "^3.16.0",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
|
"moment": "^2.29.1",
|
||||||
"rxjs": "^7.3.0",
|
"rxjs": "^7.3.0",
|
||||||
"zone.js": "^0.11.4"
|
"zone.js": "^0.11.4"
|
||||||
},
|
},
|
||||||
|
@ -5012,6 +5014,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.1.tgz",
|
||||||
"integrity": "sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ=="
|
"integrity": "sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/chartjs-adapter-moment": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-PqlerEvQcc5hZLQ/NQWgBxgVQ4TRdvkW3c/t+SUEQSj78ia3hgLkf2VZ2yGJtltNbEEFyYGm+cA6XXevodYvWA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"chart.js": "^3.0.0",
|
||||||
|
"moment": "^2.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.2",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||||
|
@ -22990,6 +23001,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.5.1.tgz",
|
||||||
"integrity": "sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ=="
|
"integrity": "sha512-m5kzt72I1WQ9LILwQC4syla/LD/N413RYv2Dx2nnTkRS9iv/ey1xLTt0DnPc/eWV4zI+BgEgDYBIzbQhZHc/PQ=="
|
||||||
},
|
},
|
||||||
|
"chartjs-adapter-moment": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/chartjs-adapter-moment/-/chartjs-adapter-moment-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-PqlerEvQcc5hZLQ/NQWgBxgVQ4TRdvkW3c/t+SUEQSj78ia3hgLkf2VZ2yGJtltNbEEFyYGm+cA6XXevodYvWA==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "3.5.2",
|
"version": "3.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||||
|
|
|
@ -63,8 +63,10 @@
|
||||||
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
"babel-plugin-transform-typescript-metadata": "^0.3.2",
|
||||||
"bulma": "^0.9.3",
|
"bulma": "^0.9.3",
|
||||||
"chart.js": "^3.5.1",
|
"chart.js": "^3.5.1",
|
||||||
|
"chartjs-adapter-moment": "^1.0.0",
|
||||||
"core-js": "^3.16.0",
|
"core-js": "^3.16.0",
|
||||||
"leaflet": "^1.7.1",
|
"leaflet": "^1.7.1",
|
||||||
|
"moment": "^2.29.1",
|
||||||
"rxjs": "^7.3.0",
|
"rxjs": "^7.3.0",
|
||||||
"zone.js": "^0.11.4"
|
"zone.js": "^0.11.4"
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import { MapViewComponent } from "./views/map-view/map-view.component";
|
||||||
|
|
||||||
import { ComponentsModule } from '../../src/common/components/components.module';
|
import { ComponentsModule } from '../../src/common/components/components.module';
|
||||||
import { GraphjsModule } from '../../src/common/graphjs/graphjs.module';
|
import { GraphjsModule } from '../../src/common/graphjs/graphjs.module';
|
||||||
|
// import { CoreModule } from '../../src/common/core/core.module';
|
||||||
|
|
||||||
import { HttpClientModule, HttpClient } from '@angular/common/http'; //for http requests
|
import { HttpClientModule, HttpClient } from '@angular/common/http'; //for http requests
|
||||||
import { MarkerService } from './services/marker.service';
|
import { MarkerService } from './services/marker.service';
|
||||||
|
@ -32,6 +33,7 @@ import { DatasetByStationSelectorComponent } from './components/dataset-by-stati
|
||||||
import { MatListModule } from '@angular/material/list';
|
import { MatListModule } from '@angular/material/list';
|
||||||
import {MatBadgeModule} from '@angular/material/badge';
|
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 { InternalIdHandler } from '../common/components/services/internal-id-handler.service';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -43,7 +45,7 @@ import { InternalIdHandler } from '../common/components/services/internal-id-han
|
||||||
// imports: Other modules whose exported classes are needed by component templates declared in this NgModule.
|
// 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],
|
||||||
providers: [
|
providers: [
|
||||||
MarkerService, PopupService, HttpService, DatasetApiService, StationService, MessageService, MapService,DatasetService, InternalIdHandler
|
MarkerService, PopupService, HttpService, DatasetApiService, StationService, MessageService, MapService,DatasetService, InternalIdHandler, TimeService
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// provide: DatasetApiInterface,
|
// provide: DatasetApiInterface,
|
||||||
|
|
|
@ -13,7 +13,7 @@ export class AppRouterService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public toDiagram() {
|
public toDiagram() {
|
||||||
this.router.navigate(['diagram'])
|
this.router.navigate(['diagram']);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// https://github.com/52North/helgoland-toolbox/blob/495f75cadcc3e7232206db1cd5dd8bbf3a172c4b/libs/core/src/lib/api-communication/connectors/dataset-api-v3-connector/api-v3-interface.ts#L321
|
// https://github.com/52North/helgoland-toolbox/blob/495f75cadcc3e7232206db1cd5dd8bbf3a172c4b/libs/core/src/lib/api-communication/connectors/dataset-api-v3-connector/api-v3-interface.ts#L321
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable, Observer, forkJoin } from 'rxjs';
|
||||||
import { Phenomenon } from '../../shared/models/phenomenon';
|
import { Phenomenon } from '../../shared/models/phenomenon';
|
||||||
import { Station } from '../../shared/models/station';
|
import { Station } from '../../shared/models/station';
|
||||||
|
|
||||||
|
@ -15,12 +15,64 @@ import { GeomonPlatform } from '../../shared/models/platform';
|
||||||
import { Dataset, GeomonTimeseries } from '../../shared/models/dataset';
|
import { Dataset, GeomonTimeseries } from '../../shared/models/dataset';
|
||||||
|
|
||||||
import { deserialize } from 'class-transformer';
|
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 { Timespan } from '../../shared/models/timespan';
|
||||||
|
import { GeomonDataset } from '../../shared/models/dataset';
|
||||||
|
|
||||||
|
import { GeomonTimeseriesData, Data, HelgolandDataFilter } from '../../shared/models/dataset';
|
||||||
// @Injectable({
|
// @Injectable({
|
||||||
// providedIn: 'root'
|
// providedIn: 'root'
|
||||||
// })
|
// })
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export interface ParameterFilter {
|
||||||
|
service?: string;
|
||||||
|
category?: string;
|
||||||
|
offering?: string;
|
||||||
|
phenomenon?: string;
|
||||||
|
procedure?: string;
|
||||||
|
feature?: string;
|
||||||
|
valueTypes?: string;
|
||||||
|
platformTypes?: string;
|
||||||
|
expanded?: boolean;
|
||||||
|
lang?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ApiV3DatasetDataFilter {
|
||||||
|
timespan?: string;
|
||||||
|
generalize?: boolean;
|
||||||
|
format?: string;
|
||||||
|
unixTime?: boolean;
|
||||||
|
expanded?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeValueTuple = [number, number];
|
||||||
|
|
||||||
|
class UriParameterCoder {
|
||||||
|
|
||||||
|
public encodeKey(key: string): string {
|
||||||
|
return encodeURIComponent(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public encodeValue(value: string): string {
|
||||||
|
return encodeURIComponent(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public decodeKey(key: string): string {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decodeValue(value: string): string {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DatasetApiService {
|
export class DatasetApiService {
|
||||||
|
|
||||||
|
@ -60,7 +112,7 @@ export class DatasetApiService {
|
||||||
return this.getStations(apiUrl, params, options).pipe(map(res => res.map(f => this.createGeomonPlatform(f))));
|
return this.getStations(apiUrl, params, options).pipe(map(res => res.map(f => this.createGeomonPlatform(f))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public getPlatform(
|
public getPlatform(
|
||||||
id: string,
|
id: string,
|
||||||
|
@ -70,20 +122,157 @@ export class DatasetApiService {
|
||||||
): Observable<GeomonPlatform> {
|
): Observable<GeomonPlatform> {
|
||||||
// const url = this.createRequestUrl(apiUrl, 'platforms', id);
|
// const url = this.createRequestUrl(apiUrl, 'platforms', id);
|
||||||
// return this.requestApi<GeomonPlatform>(url, params, options);
|
// return this.requestApi<GeomonPlatform>(url, params, options);
|
||||||
return this.getFeature(id, apiUrl,params, options).pipe(map(res => this.createGeomonPlatform(res)));
|
return this.getFeature(id, apiUrl, params, options).pipe(map(res => this.createGeomonPlatform(res)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public getDataset(id: string, apiUrl: string, params?: any, options?: HttpRequestOptions): Observable<GeomonTimeseries> {
|
public getDataset(id: string, apiUrl: string, params?: any, options?: HttpRequestOptions): Observable<GeomonTimeseries> {
|
||||||
const url = this.createRequestUrl(apiUrl, 'datasets', id);
|
const url = this.createRequestUrl(apiUrl, 'datasets', id);
|
||||||
return this.requestApi<GeomonTimeseries>(url, params, options)
|
return this.requestApi<GeomonTimeseries>(url, params, options)
|
||||||
.pipe(
|
.pipe(
|
||||||
map((res) => this.prepareDataset(res, apiUrl))
|
map((res) => this.prepareDataset(res, apiUrl))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDatasetData(dataset: GeomonDataset, timespan: Timespan, filter: HelgolandDataFilter): Observable<GeomonTimeseriesData> {
|
||||||
|
|
||||||
|
const maxTimeExtent = moment.duration(1, 'year').asMilliseconds();//31536000000
|
||||||
|
const params: ApiV3DatasetDataFilter = { format: 'flot' };
|
||||||
|
if (filter.expanded !== undefined) { params.expanded = filter.expanded };
|
||||||
|
if (filter.generalize !== undefined) { params.generalize = filter.generalize };
|
||||||
|
// if greater than one year
|
||||||
|
if ((timespan.to - timespan.from) > maxTimeExtent) {
|
||||||
|
const requests: Array<Observable<GeomonTimeseriesData>> = [];
|
||||||
|
let start = moment(timespan.from).startOf('year');
|
||||||
|
let end = moment(timespan.from).endOf('year');
|
||||||
|
while (start.isBefore(moment(timespan.to))) {
|
||||||
|
const chunkSpan = new Timespan(start.unix() * 1000, end.unix() * 1000);
|
||||||
|
params.timespan = this.createRequestTimespan(chunkSpan);
|
||||||
|
requests.push(
|
||||||
|
this.getApiData<TimeValueTuple>(dataset.id, dataset.url, params)
|
||||||
|
.pipe(map(res => {
|
||||||
|
return this.createTimeseriesData(res);
|
||||||
|
// return res;
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
start = end.add(1, 'millisecond');
|
||||||
|
end = moment(start).endOf('year');
|
||||||
|
}
|
||||||
|
return forkJoin(requests).pipe(map((e) => {
|
||||||
|
const mergedResult = e.reduce((previous, current) => {
|
||||||
|
const next: GeomonTimeseriesData = new GeomonTimeseriesData(previous.values.concat(current.values));
|
||||||
|
if (previous.valueBeforeTimespan) {
|
||||||
|
next.valueBeforeTimespan = previous.valueBeforeTimespan;
|
||||||
|
}
|
||||||
|
if (current.valueAfterTimespan) {
|
||||||
|
next.valueAfterTimespan = current.valueAfterTimespan;
|
||||||
|
}
|
||||||
|
for (const key in previous.referenceValues) {
|
||||||
|
if (previous.referenceValues.hasOwnProperty(key)) {
|
||||||
|
next.referenceValues[key] = {
|
||||||
|
values: previous.referenceValues[key].values.concat(current.referenceValues[key].values)
|
||||||
|
};
|
||||||
|
if (previous.referenceValues[key].valueBeforeTimespan) {
|
||||||
|
next.referenceValues[key].valueBeforeTimespan = previous.referenceValues[key].valueBeforeTimespan;
|
||||||
|
}
|
||||||
|
if (current.referenceValues[key].valueAfterTimespan) {
|
||||||
|
next.referenceValues[key].valueAfterTimespan = current.referenceValues[key].valueAfterTimespan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
if (mergedResult.values && mergedResult.values.length > 0) {
|
||||||
|
// cut first
|
||||||
|
const fromIdx = mergedResult.values.findIndex(el => el[0] >= timespan.from);
|
||||||
|
mergedResult.values = mergedResult.values.slice(fromIdx);
|
||||||
|
// cut last
|
||||||
|
const toIdx = mergedResult.values.findIndex(el => el[0] >= timespan.to);
|
||||||
|
if (toIdx >= 0) { mergedResult.values = mergedResult.values.slice(0, toIdx + 1); }
|
||||||
|
}
|
||||||
|
return mergedResult;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
params.timespan = this.createRequestTimespan(timespan);
|
||||||
|
if (filter.expanded !== undefined) { params.expanded = filter.expanded };
|
||||||
|
return this.getApiData<TimeValueTuple>(dataset.id, dataset.url, params)
|
||||||
|
.pipe(map(res => this.createTimeseriesData(res)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createTimeseriesData(res: Data<TimeValueTuple>): GeomonTimeseriesData {
|
||||||
|
const data = new GeomonTimeseriesData(res.values);
|
||||||
|
data.referenceValues = res.referenceValues ? res.referenceValues : {};
|
||||||
|
if (res.valueBeforeTimespan) {
|
||||||
|
data.valueBeforeTimespan = res.valueBeforeTimespan;
|
||||||
|
}
|
||||||
|
if (res.valueAfterTimespan) {
|
||||||
|
data.valueAfterTimespan = res.valueAfterTimespan;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getApiData<T>(id: string, apiUrl: string, params?: ApiV3DatasetDataFilter): Observable<Data<T>> {
|
||||||
|
const url = this.createRequestUrl(apiUrl, 'datasets', `${id}/observations`);
|
||||||
|
return this.requestApi<Data<T>>(url, this.prepareParams(params)).pipe(
|
||||||
|
map(res => {
|
||||||
|
// if (params.expanded) { res = res[id]; }
|
||||||
|
return res;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region Helper method
|
protected prepareParams(params: any): HttpParams {
|
||||||
|
let httpParams = new HttpParams({ encoder: new UriParameterCoder() });
|
||||||
|
if (params) {
|
||||||
|
Object.getOwnPropertyNames(params).forEach((key) => {
|
||||||
|
if (params[key] instanceof Array) {
|
||||||
|
httpParams = httpParams.set(key, params[key].join(','));
|
||||||
|
} else {
|
||||||
|
httpParams = httpParams.set(key, params[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return httpParams;
|
||||||
|
}
|
||||||
|
|
||||||
private prepareDataset(datasetObj:GeomonTimeseries, apiUrl: string) {
|
|
||||||
|
// getDatasetData(dataset: GeomonDataset, timespan: Timespan, filter: HelgolandDataFilter): Observable<HelgolandData> {
|
||||||
|
// const dataFilter = this.createDataFilter(filter);
|
||||||
|
// dataFilter.format = 'flot';
|
||||||
|
// return this.api.getTsData<TimeValueTuple>(dataset.id, dataset.url, timespan, dataFilter).pipe(map(res => {
|
||||||
|
// const data = new HelgolandTimeseriesData(res.values);
|
||||||
|
// data.referenceValues = res.referenceValues ? res.referenceValues : {};
|
||||||
|
// if (res.valueBeforeTimespan) { data.valueBeforeTimespan = res.valueBeforeTimespan; }
|
||||||
|
// if (res.valueAfterTimespan) { data.valueAfterTimespan = res.valueAfterTimespan; }
|
||||||
|
// return data;
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// public getTsData<T>(
|
||||||
|
// id: string,
|
||||||
|
// apiUrl: string,
|
||||||
|
// timespan: Timespan,
|
||||||
|
// params: DataParameterFilter = {},
|
||||||
|
// options: HttpRequestOptions
|
||||||
|
// ): Observable<Data<T>> {
|
||||||
|
// const url = this.createRequestUrl(apiUrl, 'timeseries', id) + '/getData';
|
||||||
|
// params.timespan = this.createRequestTimespan(timespan);
|
||||||
|
// return this.requestApi<Data<T>>(url, params, options).pipe(
|
||||||
|
// map((res: any) => {
|
||||||
|
// if (params.expanded) { res = res[id]; }
|
||||||
|
// return res;
|
||||||
|
// }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
//#region Helper method
|
||||||
|
|
||||||
|
private prepareDataset(datasetObj: GeomonTimeseries, apiUrl: string) {
|
||||||
let dataset = deserialize<GeomonTimeseries>(GeomonTimeseries, JSON.stringify(datasetObj));
|
let dataset = deserialize<GeomonTimeseries>(GeomonTimeseries, JSON.stringify(datasetObj));
|
||||||
dataset.url = apiUrl;
|
dataset.url = apiUrl;
|
||||||
this.internalDatasetId.generateInternalId(dataset);
|
this.internalDatasetId.generateInternalId(dataset);
|
||||||
|
@ -97,12 +286,12 @@ export class DatasetApiService {
|
||||||
protected createGeomonPlatform(feature: Station): GeomonPlatform {
|
protected createGeomonPlatform(feature: Station): GeomonPlatform {
|
||||||
const datasetIds = [];
|
const datasetIds = [];
|
||||||
for (const key in feature.properties.datasets) {
|
for (const key in feature.properties.datasets) {
|
||||||
if (feature.properties.datasets.hasOwnProperty(key)) {
|
if (feature.properties.datasets.hasOwnProperty(key)) {
|
||||||
datasetIds.push(key);
|
datasetIds.push(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new GeomonPlatform(feature.id, feature.properties.label, datasetIds, feature.geometry);
|
return new GeomonPlatform(feature.id, feature.properties.label, datasetIds, feature.geometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createRequestUrl(apiUrl: string, endpoint: string, id?: string) {
|
protected createRequestUrl(apiUrl: string, endpoint: string, id?: string) {
|
||||||
// TODO Check whether apiUrl ends with slash
|
// TODO Check whether apiUrl ends with slash
|
||||||
|
@ -111,6 +300,12 @@ export class DatasetApiService {
|
||||||
return requestUrl;
|
return requestUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private requestApiTextedPost(url: string, params: ParameterFilter = {}, options: HttpRequestOptions = {}): Observable<Object> {
|
||||||
|
return this.httpService.client().post(url, params, {
|
||||||
|
responseType: 'json'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected requestApi<T>(url: string, params: HttpParams = new HttpParams(), options: HttpRequestOptions = {}
|
protected requestApi<T>(url: string, params: HttpParams = new HttpParams(), options: HttpRequestOptions = {}
|
||||||
): Observable<T> {
|
): Observable<T> {
|
||||||
return this.httpService.client(options).get<T>(url,
|
return this.httpService.client(options).get<T>(url,
|
||||||
|
@ -121,6 +316,12 @@ export class DatasetApiService {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected createRequestTimespan(timespan: Timespan): string {
|
||||||
|
return encodeURI(moment(timespan.from).format() + '/' + moment(timespan.to).format());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected createBasicAuthHeader(token: string): HttpHeaders {
|
protected createBasicAuthHeader(token: string): HttpHeaders {
|
||||||
const headers = new HttpHeaders();
|
const headers = new HttpHeaders();
|
||||||
if (token) { return headers.set('Authorization', token); }
|
if (token) { return headers.set('Authorization', token); }
|
||||||
|
|
|
@ -1,14 +1,40 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { EventEmitter } from '@angular/core';
|
import { EventEmitter } from '@angular/core';
|
||||||
|
import { Timespan } from '../../shared/models/timespan';
|
||||||
|
import * as moment from "moment";
|
||||||
|
|
||||||
|
const TIMESERIES_OPTIONS_CACHE_PARAM = 'timeseriesOptions';
|
||||||
|
const TIMESERIES_IDS_CACHE_PARAM = 'timeseriesIds';
|
||||||
|
const TIME_CACHE_PARAM = 'timeseriesTime';
|
||||||
|
// https://github.com/52North/helgoland-toolbox/blob/fe6af1b9df0e5d78eeec236e4690aeb7dc92119b/apps/helgoland/src/app/services/timeseries-service.service.ts#L22
|
||||||
|
|
||||||
|
import { TimeService } from '../../common/core/time/time.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DatasetService<T> {
|
export class DatasetService<T> {
|
||||||
|
|
||||||
public datasetIds: string[] = [];
|
public datasetIds: string[] = [];
|
||||||
public datasetService: Map<string, T> = new Map();
|
public datasetService: Map<string, T> = new Map();
|
||||||
|
|
||||||
|
private _timespan: Timespan;
|
||||||
|
|
||||||
public datasetIdsChanged: EventEmitter<string[]> = new EventEmitter();
|
public datasetIdsChanged: EventEmitter<string[]> = new EventEmitter();
|
||||||
|
|
||||||
|
constructor(private timeService: TimeService) {
|
||||||
|
this.initTimespan();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public get timespan(): Timespan {
|
||||||
|
return this._timespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set timespan(v: Timespan) {
|
||||||
|
this._timespan = v;
|
||||||
|
// this.timeSrvc.saveTimespan(TIME_CACHE_PARAM, this._timespan);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the dataset to the selection
|
* Adds the dataset to the selection
|
||||||
*
|
*
|
||||||
|
@ -67,4 +93,12 @@ export class DatasetService<T> {
|
||||||
this.datasetService.set(internalId, options);
|
this.datasetService.set(internalId, options);
|
||||||
// this.saveState();
|
// this.saveState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private initTimespan() {
|
||||||
|
if (!this._timespan) {
|
||||||
|
this._timespan = new Timespan(1323239694000, 1323844494000);
|
||||||
|
//this.timeService.createByDurationWithEnd(moment.duration(1, 'days'), new Date(2011, 9), 'day');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
<!-- <h2>Bar Chart</h2>
|
<!-- <h2>Bar Chart</h2>
|
||||||
<canvas id="line-chart" width="800" height="450"></canvas> -->
|
<canvas id="line-chart" width="800" height="450"></canvas> -->
|
||||||
<geomon-timeseries-chart></geomon-timeseries-chart>
|
<geomon-timeseries-chart [datasetOptions]="datasetOptions"
|
||||||
|
[datasetIds]="datasetIds" [timeInterval]="datasetService.timespan"></geomon-timeseries-chart>
|
19
src/common/core/core.module.ts
Normal file
19
src/common/core/core.module.ts
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
|
import { DatasetApiService } from '../../app/services/dataset-api.service';
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [
|
||||||
|
CommonModule
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class CoreModule { }
|
52
src/common/core/time/time.service.ts
Normal file
52
src/common/core/time/time.service.ts
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
import { Timespan, TimeInterval, BufferedTime } from '../../../shared/models/timespan';
|
||||||
|
import moment from 'moment';
|
||||||
|
// import 'moment-duration-format';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TimeService {
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
public getBufferedTimespan(timespan: Timespan, factor: number, maxBufferInMs?: number): Timespan {
|
||||||
|
const durationMillis = this.getDuration(timespan).asMilliseconds();
|
||||||
|
let buffer = durationMillis * factor;
|
||||||
|
if (maxBufferInMs && buffer > maxBufferInMs) {
|
||||||
|
buffer = maxBufferInMs;
|
||||||
|
}
|
||||||
|
const from = timespan.from - buffer;
|
||||||
|
const to = timespan.to + buffer;
|
||||||
|
return new Timespan(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private getDuration(timespan: Timespan): moment.Duration {
|
||||||
|
const from = moment(timespan.from);
|
||||||
|
const to = moment(timespan.to);
|
||||||
|
return moment.duration(to.diff(from));
|
||||||
|
}
|
||||||
|
|
||||||
|
public createByDurationWithEnd(d: moment.Duration, end: number | Date, endOf?: moment.unitOfTime.StartOf): Timespan {
|
||||||
|
const mEnd = moment(end);
|
||||||
|
if (endOf) {
|
||||||
|
mEnd.endOf(endOf);
|
||||||
|
}
|
||||||
|
const mStart = moment(mEnd).subtract(d);
|
||||||
|
return new Timespan(mStart.toDate(), mEnd.toDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public createTimespanOfInterval(timeInterval: TimeInterval): Timespan {
|
||||||
|
|
||||||
|
if(timeInterval instanceof BufferedTime) {
|
||||||
|
const d = moment.duration(timeInterval.bufferInterval / 2);
|
||||||
|
const from = moment(timeInterval.timestamp).subtract(d).unix() * 1000;
|
||||||
|
const to = moment(timeInterval.timestamp).add(d).unix() * 1000;
|
||||||
|
return new Timespan(from, to);
|
||||||
|
} else {
|
||||||
|
return timeInterval as Timespan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
<div #geomon_timeseries>
|
<div class="d3" #geomon_timeseries>
|
||||||
<canvas id="line-chart" width="800" height="450"></canvas>
|
<canvas id="line-chart" width="100%" height="80%"></canvas>
|
||||||
</div>
|
</div>
|
|
@ -1,61 +1,285 @@
|
||||||
import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
|
import { Input, Component, AfterViewInit, ViewChild, ElementRef, SimpleChanges } from '@angular/core';
|
||||||
// import * as d3 from 'd3';
|
// import * as d3 from 'd3';
|
||||||
import { Chart, registerables } from 'chart.js';
|
import { Chart, LogarithmicScale, registerables } from 'chart.js';
|
||||||
|
|
||||||
|
import { GeomonTimeseries, DataConst, GeomonTimeseriesData } from '../../../shared/models/dataset';
|
||||||
|
import { DatasetApiService } from '../../../app/services/dataset-api.service';
|
||||||
|
import { DatasetService } from '../../../app/services/dataset.service';
|
||||||
|
|
||||||
|
import { Timespan } from '../../../shared/models/timespan';
|
||||||
|
import { TimeService } from '../../core/time/time.service';
|
||||||
|
import moment from 'moment';
|
||||||
|
// import 'moment-duration-format';
|
||||||
|
import { TimeValueTuple, Data } from '../../../shared/models/dataset';
|
||||||
|
import 'chartjs-adapter-moment';
|
||||||
|
import { MAT_SELECTION_LIST_VALUE_ACCESSOR } from '@angular/material/list';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'geomon-timeseries-chart',
|
selector: 'geomon-timeseries-chart',
|
||||||
templateUrl: './geomon-timeseries-chart.component.html',
|
templateUrl: './geomon-timeseries-chart.component.html',
|
||||||
styleUrls: ['./geomon-timeseries-chart.component.scss']
|
styleUrls: ['./geomon-timeseries-chart.component.scss']
|
||||||
})
|
})
|
||||||
export class GeomonTimeseriesChartComponent implements OnInit {
|
export class GeomonTimeseriesChartComponent implements AfterViewInit {
|
||||||
|
|
||||||
@ViewChild('geomon_timeseries', { static: true })
|
// @ViewChild('geomon_timeseries', { static: true })
|
||||||
public d3Elem: ElementRef;
|
// public chartElem: ElementRef;
|
||||||
|
|
||||||
|
|
||||||
|
@ViewChild('geomon_timeseries') public chartElem: ElementRef;
|
||||||
|
|
||||||
|
lineChart: Chart;
|
||||||
|
/**
|
||||||
|
* The corresponding dataset options.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public datasetOptions: Map<string, GeomonTimeseries>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of presented dataset ids.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public datasetIds: string[] = [];
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The time interval in which the data should presented.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
public timeInterval: Timespan;
|
||||||
|
|
||||||
|
protected timespan: Timespan;
|
||||||
|
|
||||||
|
// data types
|
||||||
|
protected datasetMap: Map<string, DataConst> = new Map();
|
||||||
|
protected listOfUoms: string[] = [];
|
||||||
|
|
||||||
|
// private loadingData: Set<string> = new Set();
|
||||||
|
|
||||||
|
private width: number;
|
||||||
|
private canvas: HTMLCanvasElement;
|
||||||
|
private margin = {
|
||||||
|
top: 10,
|
||||||
|
right: 10,
|
||||||
|
bottom: 40,
|
||||||
|
left: 10
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected datasetApiService: DatasetApiService,
|
||||||
|
protected timeService: TimeService,
|
||||||
|
public datasetService: DatasetService<GeomonTimeseries>,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
ngAfterViewInit(): void { // this.createSvg();
|
||||||
|
|
||||||
|
this.canvas = document.getElementById("line-chart") as HTMLCanvasElement;
|
||||||
|
|
||||||
constructor() { }
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
|
||||||
// this.createSvg();
|
|
||||||
// this.drawBars(this.data);
|
// this.drawBars(this.data);
|
||||||
Chart.register(...registerables);
|
Chart.register(...registerables);
|
||||||
this.drawBars();
|
this.initChart();
|
||||||
|
|
||||||
|
for (let i = 0; i < this.datasetIds.length; i++) {
|
||||||
|
let datasetId = this.datasetIds[i];
|
||||||
|
let dataset = this.datasetOptions.get(datasetId);
|
||||||
|
this.addDataset(dataset.id, 'https://geomon.geologie.ac.at/52n-sos-webapp/api/');
|
||||||
|
}
|
||||||
|
|
||||||
|
// let firstDatasetId = this.datasetIds[0];
|
||||||
|
// let dataset = this.datasetOptions.get(firstDatasetId);
|
||||||
|
// this.addDataset(dataset.id, 'https://geomon.geologie.ac.at/52n-sos-webapp/api/');
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private drawBars(): void {
|
public ngOnChanges(changes: SimpleChanges): void {
|
||||||
let lineChart = document.getElementById("line-chart") as HTMLCanvasElement;
|
if (changes.timeInterval && this.timeInterval) {
|
||||||
new Chart(lineChart, {
|
this.timespan = this.timeService.createTimespanOfInterval(this.timeInterval);
|
||||||
|
// this.timeIntervalChanges();
|
||||||
|
}
|
||||||
|
// if (changes.reloadForDatasets && this.reloadForDatasets && this.reloadDataForDatasets.length > 0) {
|
||||||
|
// this.reloadDataForDatasets(this.reloadForDatasets);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public getDataset(internalId: string) {
|
||||||
|
return this.datasetMap.get(internalId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected addDataset(id: string, url: string): void {
|
||||||
|
// this.servicesConnector.getDataset({ id, url }, { locale: this.translateService.currentLang, type: DatasetType.Timeseries }).subscribe(
|
||||||
|
// res => this.loadAddedDataset(res),
|
||||||
|
// error => this.errorHandler.handleDatasetLoadError(error)
|
||||||
|
// );
|
||||||
|
this.datasetApiService.getDataset(id, url).subscribe({
|
||||||
|
next: (res: GeomonTimeseries) => this.loadAddedDataset(res),
|
||||||
|
error: (err: any) => console.error('Observer got an error: ' + err),
|
||||||
|
complete: () => console.log('HTTP request completed.')
|
||||||
|
// error => this.errorHandler.handleDatasetLoadError(error)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadAddedDataset(dataset: GeomonTimeseries): void {
|
||||||
|
this.datasetMap.set(dataset.internalId, dataset);
|
||||||
|
this.loadDatasetData(dataset, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// load data of dataset
|
||||||
|
private loadDatasetData(dataset: GeomonTimeseries, fprce: boolean): void {
|
||||||
|
// const datasetOptions = this.datasetOptions.get(dataset.internalId);
|
||||||
|
|
||||||
|
// https://github.com/52North/helgoland-toolbox/blob/9ff9a42b34cd3deb181d56d76d48eba7c101554e/libs/core/src/lib/api-communication/connectors/dataset-api-v3-connector/dataset-api-v3-connector.ts#L270
|
||||||
|
|
||||||
|
const buffer = this.timeService.getBufferedTimespan(this.timespan, 5, moment.duration(1, 'day').asMilliseconds());
|
||||||
|
|
||||||
|
this.datasetApiService.getDatasetData(dataset, buffer, {})
|
||||||
|
.subscribe({
|
||||||
|
next: (result: GeomonTimeseriesData) => {
|
||||||
|
this.prepareData(dataset, result);
|
||||||
|
// this.onCompleteLoadingData(dataset);
|
||||||
|
let test = result;
|
||||||
|
},
|
||||||
|
error: (error) => {
|
||||||
|
// this.errorHandler.handleDataLoadError(error, dataset);
|
||||||
|
// this.onCompleteLoadingData(dataset);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to prepare each dataset for the graph and adding it to an array of datasets.
|
||||||
|
* @param dataset {IDataset} Object of the whole dataset
|
||||||
|
*/
|
||||||
|
private prepareData(dataset: GeomonTimeseries, rawdata: GeomonTimeseriesData): void {
|
||||||
|
|
||||||
|
if (rawdata instanceof GeomonTimeseriesData) {
|
||||||
|
// add surrounding entries to the set
|
||||||
|
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);
|
||||||
|
|
||||||
|
// this.datasetMap.get(dataset.internalId).data = data;
|
||||||
|
this.addData(this.lineChart, dataset, rawdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public generalizeData(data: GeomonTimeseriesData, imageWidth: number, timespan: Timespan): Data<TimeValueTuple> {
|
||||||
|
if (data.values.length > imageWidth && data.values.length > 0) {
|
||||||
|
const duration = timespan.to - timespan.from;
|
||||||
|
const dataduration = data.values[data.values.length - 1][0] - data.values[0][0];
|
||||||
|
const factor = duration / dataduration;
|
||||||
|
const realWidth = imageWidth / factor;
|
||||||
|
const modulo = 1 / (data.values.length / realWidth);
|
||||||
|
const generalizedData = {
|
||||||
|
values: data.values.filter((v, i) => i % Math.round(modulo) === 0),
|
||||||
|
referenceValues: data.referenceValues
|
||||||
|
};
|
||||||
|
console.log(`reduce from ${data.values.length} to ${generalizedData.values.length}`);
|
||||||
|
return generalizedData;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addData(chart: Chart, dataset: GeomonTimeseries, data: GeomonTimeseriesData): void {
|
||||||
|
|
||||||
|
let labels = data.values.map(function (label) {
|
||||||
|
let date = moment(label[0]).format("YYYY-MM-DD HH:mm");
|
||||||
|
return date;
|
||||||
|
});
|
||||||
|
|
||||||
|
let values = data.values.map(function (value) {
|
||||||
|
return value[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
chart.data.labels = labels;
|
||||||
|
// chart.data.datasets.forEach((dataset) => {
|
||||||
|
// dataset.data.push(data);
|
||||||
|
// });
|
||||||
|
let letters = '0123456789ABCDEF'.split('');
|
||||||
|
let color = '#';
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
color += letters[Math.floor(Math.random() * 16)];
|
||||||
|
}
|
||||||
|
var newDataset = {
|
||||||
|
label: dataset.label,
|
||||||
|
// backgroundColor: 'rgba(99, 255, 132, 0.2)',
|
||||||
|
backgroundColor: color,
|
||||||
|
// borderColor: 'rgba(99, 255, 132, 1)',
|
||||||
|
borderWidth: 1,
|
||||||
|
data: values,
|
||||||
|
}
|
||||||
|
// You add the newly created dataset to the list of `data`
|
||||||
|
chart.data.datasets.push(newDataset);
|
||||||
|
chart.update();
|
||||||
|
this.width = this.calculateWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initChart(): void {
|
||||||
|
|
||||||
|
this.lineChart = new Chart(this.canvas, {
|
||||||
type: 'line',
|
type: 'line',
|
||||||
data: {
|
data: {
|
||||||
labels: [1500, 1600, 1700, 1750, 1800, 1850, 1900, 1950, 1999, 2050],
|
// labels: [1500, 1600, 1700, 1750, 1800, 1850, 1900, 1950, 1999, 2050],
|
||||||
datasets: [{
|
labels: [],
|
||||||
data: [86, 114, 106, 106, 107, 111, 133, 221, 783, 2478],
|
datasets: [
|
||||||
label: "Africa",
|
// {
|
||||||
borderColor: "#3e95cd",
|
// data: [86, 114, 106, 106, 107, 111, 133, 221, 783, 2478],
|
||||||
fill: false
|
// label: "Africa",
|
||||||
}, {
|
// borderColor: "#3e95cd",
|
||||||
data: [282, 350, 411, 502, 635, 809, 947, 1402, 3700, 5267],
|
// fill: false
|
||||||
label: "Asia",
|
// }, {
|
||||||
borderColor: "#8e5ea2",
|
// data: [282, 350, 411, 502, 635, 809, 947, 1402, 3700, 5267],
|
||||||
fill: false
|
// label: "Asia",
|
||||||
}, {
|
// borderColor: "#8e5ea2",
|
||||||
data: [168, 170, 178, 190, 203, 276, 408, 547, 675, 734],
|
// fill: false
|
||||||
label: "Europe",
|
// }, {
|
||||||
borderColor: "#3cba9f",
|
// data: [168, 170, 178, 190, 203, 276, 408, 547, 675, 734],
|
||||||
fill: false
|
// label: "Europe",
|
||||||
}, {
|
// borderColor: "#3cba9f",
|
||||||
data: [40, 20, 10, 16, 24, 38, 74, 167, 508, 784],
|
// fill: false
|
||||||
label: "Latin America",
|
// }, {
|
||||||
borderColor: "#e8c3b9",
|
// data: [40, 20, 10, 16, 24, 38, 74, 167, 508, 784],
|
||||||
fill: false
|
// label: "Latin America",
|
||||||
}, {
|
// borderColor: "#e8c3b9",
|
||||||
data: [6, 3, 2, 2, 7, 26, 82, 172, 312, 433],
|
// fill: false
|
||||||
label: "North America",
|
// }, {
|
||||||
borderColor: "#c45850",
|
// data: [6, 3, 2, 2, 7, 26, 82, 172, 312, 433],
|
||||||
fill: false
|
// label: "North America",
|
||||||
}
|
// borderColor: "#c45850",
|
||||||
|
// fill: false
|
||||||
|
// }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
suggestedMin: 0, // minimum will be 0, unless there is a lower value.
|
||||||
|
// OR //
|
||||||
|
beginAtZero: true // minimum value will be 0.
|
||||||
|
},
|
||||||
|
|
||||||
|
x: {
|
||||||
|
type: 'time',
|
||||||
|
|
||||||
|
time: {
|
||||||
|
unit: 'minute',
|
||||||
|
displayFormats: {
|
||||||
|
minute: "DD/MM HH:mm",
|
||||||
|
hour: "DD/MM HH:mm",
|
||||||
|
day: "dd/MM",
|
||||||
|
week: "dd/MM",
|
||||||
|
month: "MMMM yyyy",
|
||||||
|
quarter: 'MMMM yyyy',
|
||||||
|
year: "yyyy",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// ticks: {
|
||||||
|
// labelOffset: 10
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
// options: {
|
// options: {
|
||||||
// title: {
|
// title: {
|
||||||
// display: true,
|
// display: true,
|
||||||
|
@ -63,6 +287,7 @@ export class GeomonTimeseriesChartComponent implements OnInit {
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
});
|
});
|
||||||
|
this.width = this.calculateWidth() - 20; // add buffer to the left to garantee visualization of last date (tick x-axis)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -80,4 +305,13 @@ export class GeomonTimeseriesChartComponent implements OnInit {
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.substring(1);
|
.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that returns the width of the graph diagram.
|
||||||
|
*/
|
||||||
|
private calculateWidth(): number {
|
||||||
|
return this.canvas.width - this.margin.left - this.margin.right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -4,7 +4,9 @@ import { NgModule } from '@angular/core';
|
||||||
import { GeomonTimeseriesChartComponent } from './geomon-timeseries-chart/geomon-timeseries-chart.component';
|
import { GeomonTimeseriesChartComponent } from './geomon-timeseries-chart/geomon-timeseries-chart.component';
|
||||||
// import { ZoomControlComponent } from './zoom-control/zoom.component';
|
// import { ZoomControlComponent } from './zoom-control/zoom.component';
|
||||||
|
|
||||||
|
import { DatasetApiService } from '../../app/services/dataset-api.service';
|
||||||
|
|
||||||
|
import { TimeService } from '../core/time/time.service';
|
||||||
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -19,7 +21,7 @@ import { GeomonTimeseriesChartComponent } from './geomon-timeseries-chart/geomon
|
||||||
|
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
DatasetApiService , TimeService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class GraphjsModule { }
|
export class GraphjsModule { }
|
|
@ -93,4 +93,54 @@ export interface RenderingHints {
|
||||||
properties: {
|
properties: {
|
||||||
color: string;
|
color: string;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DataConst extends GeomonTimeseries {
|
||||||
|
data?: Data<TimeValueTuple>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// export class TimeseriesData {
|
||||||
|
// public id: string;
|
||||||
|
// public url: string;
|
||||||
|
// public data: FirstLastValue[];
|
||||||
|
// }
|
||||||
|
|
||||||
|
export interface IDataEntry { }
|
||||||
|
|
||||||
|
export interface Data<T extends IDataEntry> {
|
||||||
|
values: T[];
|
||||||
|
referenceValues: ReferenceValues<T>;
|
||||||
|
valueBeforeTimespan?: T;
|
||||||
|
valueAfterTimespan?: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ReferenceValues<T extends IDataEntry> {
|
||||||
|
[key: string]: {
|
||||||
|
values: T[];
|
||||||
|
valueBeforeTimespan?: T;
|
||||||
|
valueAfterTimespan?: T;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export type TimeValueTuple = [number, number];
|
||||||
|
export interface GeomonData { }
|
||||||
|
export class GeomonTimeseriesData implements GeomonData {
|
||||||
|
|
||||||
|
referenceValues: ReferenceValues<TimeValueTuple> = {};
|
||||||
|
valueBeforeTimespan: TimeValueTuple;
|
||||||
|
valueAfterTimespan: TimeValueTuple;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public values: TimeValueTuple[],
|
||||||
|
) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HelgolandDataFilter {
|
||||||
|
expanded?: boolean;
|
||||||
|
generalize?: boolean;
|
||||||
}
|
}
|
30
src/shared/models/timespan.ts
Normal file
30
src/shared/models/timespan.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
export abstract class TimeInterval {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Timespan extends TimeInterval{
|
||||||
|
|
||||||
|
public from: number;
|
||||||
|
|
||||||
|
public to: number;
|
||||||
|
|
||||||
|
constructor(from: number | Date, to?: number | Date) {
|
||||||
|
super();
|
||||||
|
this.from = from instanceof Date ? from.valueOf() : from;
|
||||||
|
this.to = to ? (to instanceof Date ? to.valueOf() : to) : this.from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BufferedTime extends TimeInterval {
|
||||||
|
public timestamp: Date;
|
||||||
|
public bufferInterval: number;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
timestamp: Date,
|
||||||
|
bufferInterval: number
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
this.bufferInterval = bufferInterval;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue