- 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
|
@ -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
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpHeaders } from '@angular/common/http';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, Observer, forkJoin } from 'rxjs';
|
||||
import { Phenomenon } from '../../shared/models/phenomenon';
|
||||
import { Station } from '../../shared/models/station';
|
||||
|
||||
|
@ -15,12 +15,64 @@ import { GeomonPlatform } from '../../shared/models/platform';
|
|||
import { Dataset, GeomonTimeseries } from '../../shared/models/dataset';
|
||||
|
||||
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 moment from "moment";
|
||||
import { Timespan } from '../../shared/models/timespan';
|
||||
import { GeomonDataset } from '../../shared/models/dataset';
|
||||
|
||||
import { GeomonTimeseriesData, Data, HelgolandDataFilter } from '../../shared/models/dataset';
|
||||
// @Injectable({
|
||||
// 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()
|
||||
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))));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public getPlatform(
|
||||
id: string,
|
||||
|
@ -70,20 +122,157 @@ export class DatasetApiService {
|
|||
): Observable<GeomonPlatform> {
|
||||
// const url = this.createRequestUrl(apiUrl, 'platforms', id);
|
||||
// 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> {
|
||||
const url = this.createRequestUrl(apiUrl, 'datasets', id);
|
||||
return this.requestApi<GeomonTimeseries>(url, params, options)
|
||||
.pipe(
|
||||
map((res) => this.prepareDataset(res, apiUrl))
|
||||
.pipe(
|
||||
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));
|
||||
dataset.url = apiUrl;
|
||||
this.internalDatasetId.generateInternalId(dataset);
|
||||
|
@ -97,12 +286,12 @@ export class DatasetApiService {
|
|||
protected createGeomonPlatform(feature: Station): GeomonPlatform {
|
||||
const datasetIds = [];
|
||||
for (const key in feature.properties.datasets) {
|
||||
if (feature.properties.datasets.hasOwnProperty(key)) {
|
||||
datasetIds.push(key);
|
||||
}
|
||||
if (feature.properties.datasets.hasOwnProperty(key)) {
|
||||
datasetIds.push(key);
|
||||
}
|
||||
}
|
||||
return new GeomonPlatform(feature.id, feature.properties.label, datasetIds, feature.geometry);
|
||||
}
|
||||
}
|
||||
|
||||
protected createRequestUrl(apiUrl: string, endpoint: string, id?: string) {
|
||||
// TODO Check whether apiUrl ends with slash
|
||||
|
@ -111,6 +300,12 @@ export class DatasetApiService {
|
|||
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 = {}
|
||||
): Observable<T> {
|
||||
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 {
|
||||
const headers = new HttpHeaders();
|
||||
if (token) { return headers.set('Authorization', token); }
|
||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue