2019-08-09 19:13:18 +03:00
|
|
|
///
|
|
|
|
|
/// Copyright © 2016-2019 The Thingsboard Authors
|
|
|
|
|
///
|
|
|
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
/// you may not use this file except in compliance with the License.
|
|
|
|
|
/// You may obtain a copy of the License at
|
|
|
|
|
///
|
|
|
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
///
|
|
|
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
/// See the License for the specific language governing permissions and
|
|
|
|
|
/// limitations under the License.
|
|
|
|
|
///
|
|
|
|
|
|
|
|
|
|
import { Injectable } from '@angular/core';
|
2019-09-03 19:31:16 +03:00
|
|
|
import { DAY, defaultTimeIntervals, MINUTE, SECOND, Timewindow } from '@shared/models/time/time.models';
|
2019-08-09 19:13:18 +03:00
|
|
|
import {HttpClient} from '@angular/common/http';
|
|
|
|
|
import {Observable} from 'rxjs';
|
|
|
|
|
import {defaultHttpOptions} from '@core/http/http-utils';
|
|
|
|
|
import {map} from 'rxjs/operators';
|
|
|
|
|
|
|
|
|
|
export interface TimeInterval {
|
|
|
|
|
name: string;
|
|
|
|
|
translateParams: {[key: string]: any};
|
|
|
|
|
value: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const MIN_INTERVAL = SECOND;
|
|
|
|
|
const MAX_INTERVAL = 365 * 20 * DAY;
|
|
|
|
|
|
|
|
|
|
const MIN_LIMIT = 10;
|
|
|
|
|
|
|
|
|
|
const MAX_DATAPOINTS_LIMIT = 500;
|
|
|
|
|
|
|
|
|
|
@Injectable({
|
|
|
|
|
providedIn: 'root'
|
|
|
|
|
})
|
|
|
|
|
export class TimeService {
|
|
|
|
|
|
|
|
|
|
private maxDatapointsLimit = MAX_DATAPOINTS_LIMIT;
|
|
|
|
|
|
|
|
|
|
constructor(
|
|
|
|
|
private http: HttpClient
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
public loadMaxDatapointsLimit(): Observable<number> {
|
|
|
|
|
return this.http.get<number>('/api/dashboard/maxDatapointsLimit',
|
|
|
|
|
defaultHttpOptions(true)).pipe(
|
|
|
|
|
map( (limit) => {
|
|
|
|
|
this.maxDatapointsLimit = limit;
|
|
|
|
|
if (!this.maxDatapointsLimit || this.maxDatapointsLimit <= MIN_LIMIT) {
|
|
|
|
|
this.maxDatapointsLimit = MIN_LIMIT + 1;
|
|
|
|
|
}
|
|
|
|
|
return this.maxDatapointsLimit;
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public matchesExistingInterval(min: number, max: number, intervalMs: number): boolean {
|
|
|
|
|
const intervals = this.getIntervals(min, max);
|
|
|
|
|
return intervals.findIndex(interval => interval.value === intervalMs) > -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getIntervals(min: number, max: number): Array<TimeInterval> {
|
|
|
|
|
min = this.boundMinInterval(min);
|
|
|
|
|
max = this.boundMaxInterval(max);
|
|
|
|
|
return defaultTimeIntervals.filter((interval) => interval.value >= min && interval.value <= max);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boundMinInterval(min: number): number {
|
|
|
|
|
return this.toBound(min, MIN_INTERVAL, MAX_INTERVAL, MIN_INTERVAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boundMaxInterval(max: number): number {
|
|
|
|
|
return this.toBound(max, MIN_INTERVAL, MAX_INTERVAL, MAX_INTERVAL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boundToPredefinedInterval(min: number, max: number, intervalMs: number): number {
|
|
|
|
|
const intervals = this.getIntervals(min, max);
|
|
|
|
|
let minDelta = MAX_INTERVAL;
|
|
|
|
|
const boundedInterval = intervalMs || min;
|
2019-09-03 19:31:16 +03:00
|
|
|
if (!intervals.length) {
|
|
|
|
|
return boundedInterval;
|
|
|
|
|
}
|
2019-08-09 19:13:18 +03:00
|
|
|
let matchedInterval: TimeInterval = intervals[0];
|
|
|
|
|
intervals.forEach((interval) => {
|
|
|
|
|
const delta = Math.abs(interval.value - boundedInterval);
|
|
|
|
|
if (delta < minDelta) {
|
|
|
|
|
matchedInterval = interval;
|
|
|
|
|
minDelta = delta;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return matchedInterval.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getMaxDatapointsLimit(): number {
|
|
|
|
|
return this.maxDatapointsLimit;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public getMinDatapointsLimit(): number {
|
|
|
|
|
return MIN_LIMIT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public minIntervalLimit(timewindowMs: number): number {
|
|
|
|
|
const min = timewindowMs / 500;
|
|
|
|
|
return this.boundMinInterval(min);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public maxIntervalLimit(timewindowMs: number): number {
|
|
|
|
|
const max = timewindowMs / MIN_LIMIT;
|
|
|
|
|
return this.boundMaxInterval(max);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-03 19:31:16 +03:00
|
|
|
public defaultTimewindow(): Timewindow {
|
|
|
|
|
return Timewindow.defaultTimewindow(this);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-09 19:13:18 +03:00
|
|
|
private toBound(value: number, min: number, max: number, defValue: number): number {
|
|
|
|
|
if (typeof value !== 'undefined') {
|
|
|
|
|
value = Math.max(value, min);
|
|
|
|
|
value = Math.min(value, max);
|
|
|
|
|
return value;
|
|
|
|
|
} else {
|
|
|
|
|
return defValue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|