diff --git a/ui-ngx/src/app/core/api/data-aggregator.ts b/ui-ngx/src/app/core/api/data-aggregator.ts index e31d821efd..4a73c6dafd 100644 --- a/ui-ngx/src/app/core/api/data-aggregator.ts +++ b/ui-ngx/src/app/core/api/data-aggregator.ts @@ -18,8 +18,10 @@ import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/tel import { AggregationType, calculateIntervalEndTime, - calculateIntervalStartTime, getCurrentTime, - QuickTimeInterval, SubscriptionTimewindow + calculateIntervalStartTime, + getCurrentTime, + getCurrentTimeForComparison, + SubscriptionTimewindow } from '@shared/models/time/time.models'; import { UtilsService } from '@core/services/utils.service'; import { deepClone } from '@core/utils'; @@ -139,7 +141,8 @@ export class DataAggregator { this.intervalScheduledTime = this.utils.currentPerfTime(); this.startTs = this.subsTw.startTs + this.subsTw.tsOffset; 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 { this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; } @@ -166,7 +169,8 @@ export class DataAggregator { this.elapsed = 0; this.dataReceived = true; 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 { this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; } @@ -207,7 +211,7 @@ export class DataAggregator { if (delta || !this.data) { const tickTs = delta * this.subsTw.aggregation.interval; 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.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; } 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); + } + } + } diff --git a/ui-ngx/src/app/core/api/widget-subscription.ts b/ui-ngx/src/app/core/api/widget-subscription.ts index ba79e8f09a..11ab462bdc 100644 --- a/ui-ngx/src/app/core/api/widget-subscription.ts +++ b/ui-ngx/src/app/core/api/widget-subscription.ts @@ -36,18 +36,6 @@ import { widgetType } from '@app/shared/models/widget.models'; 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 { CancelAnimationFrame } from '@core/services/raf.service'; import { EntityType } from '@shared/models/entity-type.models'; @@ -68,6 +56,19 @@ import { } from '@shared/models/query/query.models'; import { map } from 'rxjs/operators'; 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_; @@ -387,7 +388,7 @@ export class WidgetSubscription implements IWidgetSubscription { this.notifyDataLoaded(); return of(null); } - if (this.comparisonEnabled) { + if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) { const additionalDatasources: Datasource[] = []; this.configuredDatasources.forEach((datasource, datasourceIndex) => { const additionalDataKeys: DataKey[] = []; @@ -420,14 +421,14 @@ export class WidgetSubscription implements IWidgetSubscription { initialPageDataChanged: this.initialPageDataChanged.bind(this), dataUpdated: this.dataUpdated.bind(this), updateRealtimeSubscription: () => { - if (this.comparisonEnabled && datasource.isAdditional) { + if (this.comparisonEnabled && datasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) { return this.updateSubscriptionForComparison(); } else { return this.updateRealtimeSubscription(); } }, setRealtimeSubscription: (subscriptionTimewindow) => { - if (this.comparisonEnabled && datasource.isAdditional) { + if (this.comparisonEnabled && datasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) { this.updateSubscriptionForComparison(subscriptionTimewindow); } else { this.updateRealtimeSubscription(deepClone(subscriptionTimewindow)); @@ -888,7 +889,7 @@ export class WidgetSubscription implements IWidgetSubscription { if (!this.hasDataPageLink) { if (this.type === widgetType.timeseries && this.timeWindowConfig) { this.updateRealtimeSubscription(); - if (this.comparisonEnabled) { + if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) { this.updateSubscriptionForComparison(); } } @@ -904,7 +905,7 @@ export class WidgetSubscription implements IWidgetSubscription { const forceUpdate = !this.datasources.length; const notifyDataLoaded = !this.entityDataListeners.filter((listener) => listener.subscription ? true : false).length; this.entityDataListeners.forEach((listener) => { - if (this.comparisonEnabled && listener.configDatasource.isAdditional) { + if (this.comparisonEnabled && listener.configDatasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) { listener.subscriptionTimewindow = this.timewindowForComparison; } else { 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.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf(); } else if (this.timewindowForComparison.fixedWindow) { - this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs + this.timewindowForComparison.tsOffset; - this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs + this.timewindowForComparison.tsOffset; + this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs; + this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs; } } @@ -1261,7 +1262,7 @@ export class WidgetSubscription implements IWidgetSubscription { index++; }); }); - if (this.comparisonEnabled) { + if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) { this.datasourcePages.forEach(datasourcePage => { datasourcePage.data.forEach((datasource, dIndex) => { if (datasource.isAdditional) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 4850d08723..468708d12e 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -57,7 +57,7 @@ import { } from './flot-widget.models'; import * as moment_ from 'moment'; 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 { UtilsService } from '@core/services/utils.service'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; @@ -92,6 +92,8 @@ export class TbFlot { private readonly tooltipCumulative: boolean; private readonly hideZeros: boolean; + private comparisonEnabled: boolean; + private readonly defaultBarWidth: number; private thresholdsSourcesSubscription: IWidgetSubscription; @@ -158,6 +160,9 @@ export class TbFlot { this.tooltipCumulative = isDefined(this.settings.tooltipCumulative) ? this.settings.tooltipCumulative : false; this.hideZeros = isDefined(this.settings.hideZeros) ? this.settings.hideZeros : false; + this.comparisonEnabled = this.settings.comparisonEnabled && + isHistoryTypeTimewindow(this.ctx.defaultSubscription.timeWindowConfig); + const font = { color: this.settings.fontColor || '#545454', size: this.settings.fontSize || 10, @@ -263,7 +268,7 @@ export class TbFlot { }; } - if (this.settings.comparisonEnabled) { + if (this.comparisonEnabled) { const xaxis = deepClone(this.xaxis); xaxis.position = 'top'; if (this.settings.xaxisSecond) { @@ -425,7 +430,7 @@ export class TbFlot { fill: keySettings.fillLines === true }; - if (this.settings.stack && !this.settings.comparisonEnabled) { + if (this.settings.stack && !this.comparisonEnabled) { series.stack = !keySettings.excludeFromStacking; } else { series.stack = false; @@ -557,7 +562,7 @@ export class TbFlot { } this.options.xaxes[0].min = this.subscription.timeWindow.minTime; 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].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].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].max = this.subscription.comparisonTimeWindow.maxTime; } @@ -654,7 +659,7 @@ export class TbFlot { } else { this.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime; 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].max = this.subscription.comparisonTimeWindow.maxTime; } @@ -1293,7 +1298,7 @@ export class TbFlot { const results: TbFlotHoverInfo[] = [{ seriesHover: [] }]; - if (this.settings.comparisonEnabled) { + if (this.comparisonEnabled) { results.push({ seriesHover: [] }); diff --git a/ui-ngx/src/app/shared/models/time/time.models.ts b/ui-ngx/src/app/shared/models/time/time.models.ts index 0c6a2c4ac6..6c127f6232 100644 --- a/ui-ngx/src/app/shared/models/time/time.models.ts +++ b/ui-ngx/src/app/shared/models/time/time.models.ts @@ -118,6 +118,7 @@ export interface SubscriptionTimewindow { realtimeWindowMs?: number; fixedWindow?: FixedWindow; aggregation?: SubscriptionAggregation; + timeForComparison?: moment_.unitOfTime.DurationConstructor; } export interface WidgetTimewindow { @@ -208,6 +209,14 @@ export function defaultTimewindow(timeService: TimeService): 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 { const model = defaultTimewindow(timeService); if (value) { @@ -215,15 +224,7 @@ export function initModelFromDefaultTimewindow(value: Timewindow, timeService: T model.hideAggregation = value.hideAggregation; model.hideAggInterval = value.hideAggInterval; model.hideTimezone = value.hideTimezone; - if (isUndefined(value.selectedTab)) { - if (value.realtime) { - model.selectedTab = TimewindowType.REALTIME; - } else { - model.selectedTab = TimewindowType.HISTORY; - } - } else { - model.selectedTab = value.selectedTab; - } + model.selectedTab = getTimewindowType(value); if (model.selectedTab === TimewindowType.REALTIME) { if (isDefined(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, timeService: TimeService): SubscriptionTimewindow { const subscriptionTimewindow: SubscriptionTimewindow = { @@ -352,10 +357,7 @@ export function createSubscriptionTimewindow(timewindow: Timewindow, stDiff: num limit: timewindow.aggregation.limit || timeService.getMaxDatapointsLimit() }; } - let selectedTab = timewindow.selectedTab; - if (isUndefined(selectedTab)) { - selectedTab = isDefined(timewindow.realtime) ? TimewindowType.REALTIME : TimewindowType.HISTORY; - } + const selectedTab = getTimewindowType(timewindow); if (selectedTab === TimewindowType.REALTIME) { let realtimeType = timewindow.realtime.realtimeType; if (isUndefined(realtimeType)) { @@ -558,10 +560,15 @@ export function createTimewindowForComparison(subscriptionTimewindow: Subscripti const timewindowForComparison: SubscriptionTimewindow = { fixedWindow: null, realtimeWindowMs: null, - aggregation: subscriptionTimewindow.aggregation + aggregation: subscriptionTimewindow.aggregation, + tsOffset: subscriptionTimewindow.tsOffset }; if (subscriptionTimewindow.realtimeWindowMs) { + if (subscriptionTimewindow.quickInterval) { + timewindowForComparison.quickInterval = subscriptionTimewindow.quickInterval; + timewindowForComparison.timeForComparison = timeUnit; + } timewindowForComparison.startTs = moment(subscriptionTimewindow.startTs).subtract(1, timeUnit).valueOf(); timewindowForComparison.realtimeWindowMs = subscriptionTimewindow.realtimeWindowMs; } else if (subscriptionTimewindow.fixedWindow) { @@ -797,3 +804,7 @@ export function getCurrentTime(tz?: string): moment_.Moment { export function getTimezone(tz: string): moment_.Moment { return moment.tz(tz); } + +export function getCurrentTimeForComparison(timeForComparison: moment_.unitOfTime.DurationConstructor, tz?: string): moment_.Moment { + return getCurrentTime(tz).subtract(1, timeForComparison); +}