UI: Added comparison support timezone

This commit is contained in:
Vladyslav_Prykhodko 2021-03-18 15:56:07 +02:00
parent 0a27101e1f
commit f4b6798a16
4 changed files with 75 additions and 46 deletions

View File

@ -18,8 +18,10 @@ import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/tel
import { import {
AggregationType, AggregationType,
calculateIntervalEndTime, calculateIntervalEndTime,
calculateIntervalStartTime, getCurrentTime, calculateIntervalStartTime,
QuickTimeInterval, SubscriptionTimewindow getCurrentTime,
getCurrentTimeForComparison,
SubscriptionTimewindow
} from '@shared/models/time/time.models'; } from '@shared/models/time/time.models';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import { deepClone } from '@core/utils'; import { deepClone } from '@core/utils';
@ -139,7 +141,8 @@ export class DataAggregator {
this.intervalScheduledTime = this.utils.currentPerfTime(); this.intervalScheduledTime = this.utils.currentPerfTime();
this.startTs = this.subsTw.startTs + this.subsTw.tsOffset; this.startTs = this.subsTw.startTs + this.subsTw.tsOffset;
if (this.subsTw.quickInterval) { if (this.subsTw.quickInterval) {
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, null, this.subsTw.timezone) + this.subsTw.tsOffset; const currentDate = this.getCurrentTime();
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
} else { } else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
} }
@ -166,7 +169,8 @@ export class DataAggregator {
this.elapsed = 0; this.elapsed = 0;
this.dataReceived = true; this.dataReceived = true;
if (this.subsTw.quickInterval) { if (this.subsTw.quickInterval) {
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, null, this.subsTw.timezone) + this.subsTw.tsOffset; const currentDate = this.getCurrentTime();
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
} else { } else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
} }
@ -207,7 +211,7 @@ export class DataAggregator {
if (delta || !this.data) { if (delta || !this.data) {
const tickTs = delta * this.subsTw.aggregation.interval; const tickTs = delta * this.subsTw.aggregation.interval;
if (this.subsTw.quickInterval) { if (this.subsTw.quickInterval) {
const currentDate = getCurrentTime(this.subsTw.timezone); const currentDate = this.getCurrentTime();
this.startTs = calculateIntervalStartTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; this.startTs = calculateIntervalStartTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
} else { } else {
@ -356,5 +360,13 @@ export class DataAggregator {
} }
} }
private getCurrentTime() {
if (this.subsTw.timeForComparison) {
return getCurrentTimeForComparison(this.subsTw.timeForComparison, this.subsTw.timezone);
} else {
return getCurrentTime(this.subsTw.timezone);
}
}
} }

View File

@ -36,18 +36,6 @@ import {
widgetType widgetType
} from '@app/shared/models/widget.models'; } from '@app/shared/models/widget.models';
import { HttpErrorResponse } from '@angular/common/http'; import { HttpErrorResponse } from '@angular/common/http';
import {
calculateIntervalEndTime,
calculateIntervalStartTime,
calculateTsOffset,
createSubscriptionTimewindow,
createTimewindowForComparison,
getCurrentTime,
SubscriptionTimewindow,
Timewindow,
toHistoryTimewindow,
WidgetTimewindow
} from '@app/shared/models/time/time.models';
import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'; import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs';
import { CancelAnimationFrame } from '@core/services/raf.service'; import { CancelAnimationFrame } from '@core/services/raf.service';
import { EntityType } from '@shared/models/entity-type.models'; import { EntityType } from '@shared/models/entity-type.models';
@ -68,6 +56,19 @@ import {
} from '@shared/models/query/query.models'; } from '@shared/models/query/query.models';
import { map } from 'rxjs/operators'; import { map } from 'rxjs/operators';
import { AlarmDataListener } from '@core/api/alarm-data.service'; import { AlarmDataListener } from '@core/api/alarm-data.service';
import {
calculateIntervalEndTime,
calculateIntervalStartTime,
calculateTsOffset,
createSubscriptionTimewindow,
createTimewindowForComparison,
getCurrentTime,
isHistoryTypeTimewindow,
SubscriptionTimewindow,
Timewindow,
toHistoryTimewindow,
WidgetTimewindow
} from '@app/shared/models/time/time.models';
const moment = moment_; const moment = moment_;
@ -387,7 +388,7 @@ export class WidgetSubscription implements IWidgetSubscription {
this.notifyDataLoaded(); this.notifyDataLoaded();
return of(null); return of(null);
} }
if (this.comparisonEnabled) { if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) {
const additionalDatasources: Datasource[] = []; const additionalDatasources: Datasource[] = [];
this.configuredDatasources.forEach((datasource, datasourceIndex) => { this.configuredDatasources.forEach((datasource, datasourceIndex) => {
const additionalDataKeys: DataKey[] = []; const additionalDataKeys: DataKey[] = [];
@ -420,14 +421,14 @@ export class WidgetSubscription implements IWidgetSubscription {
initialPageDataChanged: this.initialPageDataChanged.bind(this), initialPageDataChanged: this.initialPageDataChanged.bind(this),
dataUpdated: this.dataUpdated.bind(this), dataUpdated: this.dataUpdated.bind(this),
updateRealtimeSubscription: () => { updateRealtimeSubscription: () => {
if (this.comparisonEnabled && datasource.isAdditional) { if (this.comparisonEnabled && datasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) {
return this.updateSubscriptionForComparison(); return this.updateSubscriptionForComparison();
} else { } else {
return this.updateRealtimeSubscription(); return this.updateRealtimeSubscription();
} }
}, },
setRealtimeSubscription: (subscriptionTimewindow) => { setRealtimeSubscription: (subscriptionTimewindow) => {
if (this.comparisonEnabled && datasource.isAdditional) { if (this.comparisonEnabled && datasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) {
this.updateSubscriptionForComparison(subscriptionTimewindow); this.updateSubscriptionForComparison(subscriptionTimewindow);
} else { } else {
this.updateRealtimeSubscription(deepClone(subscriptionTimewindow)); this.updateRealtimeSubscription(deepClone(subscriptionTimewindow));
@ -888,7 +889,7 @@ export class WidgetSubscription implements IWidgetSubscription {
if (!this.hasDataPageLink) { if (!this.hasDataPageLink) {
if (this.type === widgetType.timeseries && this.timeWindowConfig) { if (this.type === widgetType.timeseries && this.timeWindowConfig) {
this.updateRealtimeSubscription(); this.updateRealtimeSubscription();
if (this.comparisonEnabled) { if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) {
this.updateSubscriptionForComparison(); this.updateSubscriptionForComparison();
} }
} }
@ -904,7 +905,7 @@ export class WidgetSubscription implements IWidgetSubscription {
const forceUpdate = !this.datasources.length; const forceUpdate = !this.datasources.length;
const notifyDataLoaded = !this.entityDataListeners.filter((listener) => listener.subscription ? true : false).length; const notifyDataLoaded = !this.entityDataListeners.filter((listener) => listener.subscription ? true : false).length;
this.entityDataListeners.forEach((listener) => { this.entityDataListeners.forEach((listener) => {
if (this.comparisonEnabled && listener.configDatasource.isAdditional) { if (this.comparisonEnabled && listener.configDatasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) {
listener.subscriptionTimewindow = this.timewindowForComparison; listener.subscriptionTimewindow = this.timewindowForComparison;
} else { } else {
listener.subscriptionTimewindow = this.subscriptionTimewindow; listener.subscriptionTimewindow = this.subscriptionTimewindow;
@ -1147,8 +1148,8 @@ export class WidgetSubscription implements IWidgetSubscription {
this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf(); this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf();
this.comparisonTimeWindow.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf(); this.comparisonTimeWindow.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf();
} else if (this.timewindowForComparison.fixedWindow) { } else if (this.timewindowForComparison.fixedWindow) {
this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs + this.timewindowForComparison.tsOffset; this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs;
this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs + this.timewindowForComparison.tsOffset; this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs;
} }
} }
@ -1261,7 +1262,7 @@ export class WidgetSubscription implements IWidgetSubscription {
index++; index++;
}); });
}); });
if (this.comparisonEnabled) { if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) {
this.datasourcePages.forEach(datasourcePage => { this.datasourcePages.forEach(datasourcePage => {
datasourcePage.data.forEach((datasource, dIndex) => { datasourcePage.data.forEach((datasource, dIndex) => {
if (datasource.isAdditional) { if (datasource.isAdditional) {

View File

@ -57,7 +57,7 @@ import {
} from './flot-widget.models'; } from './flot-widget.models';
import * as moment_ from 'moment'; import * as moment_ from 'moment';
import * as tinycolor_ from 'tinycolor2'; import * as tinycolor_ from 'tinycolor2';
import { AggregationType } from '@shared/models/time/time.models'; import { AggregationType, isHistoryTypeTimewindow } from '@shared/models/time/time.models';
import { CancelAnimationFrame } from '@core/services/raf.service'; import { CancelAnimationFrame } from '@core/services/raf.service';
import { UtilsService } from '@core/services/utils.service'; import { UtilsService } from '@core/services/utils.service';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
@ -92,6 +92,8 @@ export class TbFlot {
private readonly tooltipCumulative: boolean; private readonly tooltipCumulative: boolean;
private readonly hideZeros: boolean; private readonly hideZeros: boolean;
private comparisonEnabled: boolean;
private readonly defaultBarWidth: number; private readonly defaultBarWidth: number;
private thresholdsSourcesSubscription: IWidgetSubscription; private thresholdsSourcesSubscription: IWidgetSubscription;
@ -158,6 +160,9 @@ export class TbFlot {
this.tooltipCumulative = isDefined(this.settings.tooltipCumulative) ? this.settings.tooltipCumulative : false; this.tooltipCumulative = isDefined(this.settings.tooltipCumulative) ? this.settings.tooltipCumulative : false;
this.hideZeros = isDefined(this.settings.hideZeros) ? this.settings.hideZeros : false; this.hideZeros = isDefined(this.settings.hideZeros) ? this.settings.hideZeros : false;
this.comparisonEnabled = this.settings.comparisonEnabled &&
isHistoryTypeTimewindow(this.ctx.defaultSubscription.timeWindowConfig);
const font = { const font = {
color: this.settings.fontColor || '#545454', color: this.settings.fontColor || '#545454',
size: this.settings.fontSize || 10, size: this.settings.fontSize || 10,
@ -263,7 +268,7 @@ export class TbFlot {
}; };
} }
if (this.settings.comparisonEnabled) { if (this.comparisonEnabled) {
const xaxis = deepClone(this.xaxis); const xaxis = deepClone(this.xaxis);
xaxis.position = 'top'; xaxis.position = 'top';
if (this.settings.xaxisSecond) { if (this.settings.xaxisSecond) {
@ -425,7 +430,7 @@ export class TbFlot {
fill: keySettings.fillLines === true fill: keySettings.fillLines === true
}; };
if (this.settings.stack && !this.settings.comparisonEnabled) { if (this.settings.stack && !this.comparisonEnabled) {
series.stack = !keySettings.excludeFromStacking; series.stack = !keySettings.excludeFromStacking;
} else { } else {
series.stack = false; series.stack = false;
@ -557,7 +562,7 @@ export class TbFlot {
} }
this.options.xaxes[0].min = this.subscription.timeWindow.minTime; this.options.xaxes[0].min = this.subscription.timeWindow.minTime;
this.options.xaxes[0].max = this.subscription.timeWindow.maxTime; this.options.xaxes[0].max = this.subscription.timeWindow.maxTime;
if (this.settings.comparisonEnabled) { if (this.comparisonEnabled) {
this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime;
this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime;
} }
@ -636,7 +641,7 @@ export class TbFlot {
this.options.xaxes[0].min = this.subscription.timeWindow.minTime; this.options.xaxes[0].min = this.subscription.timeWindow.minTime;
this.options.xaxes[0].max = this.subscription.timeWindow.maxTime; this.options.xaxes[0].max = this.subscription.timeWindow.maxTime;
if (this.settings.comparisonEnabled) { if (this.comparisonEnabled) {
this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime;
this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime;
} }
@ -654,7 +659,7 @@ export class TbFlot {
} else { } else {
this.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime; this.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime;
this.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime; this.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime;
if (this.settings.comparisonEnabled) { if (this.comparisonEnabled) {
this.plot.getOptions().xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; this.plot.getOptions().xaxes[1].min = this.subscription.comparisonTimeWindow.minTime;
this.plot.getOptions().xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; this.plot.getOptions().xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime;
} }
@ -1293,7 +1298,7 @@ export class TbFlot {
const results: TbFlotHoverInfo[] = [{ const results: TbFlotHoverInfo[] = [{
seriesHover: [] seriesHover: []
}]; }];
if (this.settings.comparisonEnabled) { if (this.comparisonEnabled) {
results.push({ results.push({
seriesHover: [] seriesHover: []
}); });

View File

@ -118,6 +118,7 @@ export interface SubscriptionTimewindow {
realtimeWindowMs?: number; realtimeWindowMs?: number;
fixedWindow?: FixedWindow; fixedWindow?: FixedWindow;
aggregation?: SubscriptionAggregation; aggregation?: SubscriptionAggregation;
timeForComparison?: moment_.unitOfTime.DurationConstructor;
} }
export interface WidgetTimewindow { export interface WidgetTimewindow {
@ -208,6 +209,14 @@ export function defaultTimewindow(timeService: TimeService): Timewindow {
return timewindow; return timewindow;
} }
function getTimewindowType(timewindow: Timewindow): TimewindowType {
if (isUndefined(timewindow.selectedTab)) {
return isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY;
} else {
return timewindow.selectedTab;
}
}
export function initModelFromDefaultTimewindow(value: Timewindow, timeService: TimeService): Timewindow { export function initModelFromDefaultTimewindow(value: Timewindow, timeService: TimeService): Timewindow {
const model = defaultTimewindow(timeService); const model = defaultTimewindow(timeService);
if (value) { if (value) {
@ -215,15 +224,7 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T
model.hideAggregation = value.hideAggregation; model.hideAggregation = value.hideAggregation;
model.hideAggInterval = value.hideAggInterval; model.hideAggInterval = value.hideAggInterval;
model.hideTimezone = value.hideTimezone; model.hideTimezone = value.hideTimezone;
if (isUndefined(value.selectedTab)) { model.selectedTab = getTimewindowType(value);
if (value.realtime) {
model.selectedTab = TimewindowType.REALTIME;
} else {
model.selectedTab = TimewindowType.HISTORY;
}
} else {
model.selectedTab = value.selectedTab;
}
if (model.selectedTab === TimewindowType.REALTIME) { if (model.selectedTab === TimewindowType.REALTIME) {
if (isDefined(value.realtime.interval)) { if (isDefined(value.realtime.interval)) {
model.realtime.interval = value.realtime.interval; model.realtime.interval = value.realtime.interval;
@ -328,6 +329,10 @@ export function calculateTsOffset(timezone?: string): number {
} }
} }
export function isHistoryTypeTimewindow(timewindow: Timewindow): boolean {
return getTimewindowType(timewindow) === TimewindowType.HISTORY;
}
export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: number, stateData: boolean, export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: number, stateData: boolean,
timeService: TimeService): SubscriptionTimewindow { timeService: TimeService): SubscriptionTimewindow {
const subscriptionTimewindow: SubscriptionTimewindow = { const subscriptionTimewindow: SubscriptionTimewindow = {
@ -352,10 +357,7 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num
limit: timewindow.aggregation.limit || timeService.getMaxDatapointsLimit() limit: timewindow.aggregation.limit || timeService.getMaxDatapointsLimit()
}; };
} }
let selectedTab = timewindow.selectedTab; const selectedTab = getTimewindowType(timewindow);
if (isUndefined(selectedTab)) {
selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY;
}
if (selectedTab === TimewindowType.REALTIME) { if (selectedTab === TimewindowType.REALTIME) {
let realtimeType = timewindow.realtime.realtimeType; let realtimeType = timewindow.realtime.realtimeType;
if (isUndefined(realtimeType)) { if (isUndefined(realtimeType)) {
@ -558,10 +560,15 @@ export function createTimewindowForComparison(subscriptionTimewindow: Subscripti
const timewindowForComparison: SubscriptionTimewindow = { const timewindowForComparison: SubscriptionTimewindow = {
fixedWindow: null, fixedWindow: null,
realtimeWindowMs: null, realtimeWindowMs: null,
aggregation: subscriptionTimewindow.aggregation aggregation: subscriptionTimewindow.aggregation,
tsOffset: subscriptionTimewindow.tsOffset
}; };
if (subscriptionTimewindow.realtimeWindowMs) { if (subscriptionTimewindow.realtimeWindowMs) {
if (subscriptionTimewindow.quickInterval) {
timewindowForComparison.quickInterval = subscriptionTimewindow.quickInterval;
timewindowForComparison.timeForComparison = timeUnit;
}
timewindowForComparison.startTs = moment(subscriptionTimewindow.startTs).subtract(1, timeUnit).valueOf(); timewindowForComparison.startTs = moment(subscriptionTimewindow.startTs).subtract(1, timeUnit).valueOf();
timewindowForComparison.realtimeWindowMs = subscriptionTimewindow.realtimeWindowMs; timewindowForComparison.realtimeWindowMs = subscriptionTimewindow.realtimeWindowMs;
} else if (subscriptionTimewindow.fixedWindow) { } else if (subscriptionTimewindow.fixedWindow) {
@ -797,3 +804,7 @@ export function getCurrentTime(tz?: string): moment_.Moment {
export function getTimezone(tz: string): moment_.Moment { export function getTimezone(tz: string): moment_.Moment {
return moment.tz(tz); return moment.tz(tz);
} }
export function getCurrentTimeForComparison(timeForComparison: moment_.unitOfTime.DurationConstructor, tz?: string): moment_.Moment {
return getCurrentTime(tz).subtract(1, timeForComparison);
}