Showing
10 changed files
with
223 additions
and
121 deletions
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | 16 | ||
17 | import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models'; | 17 | import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models'; |
18 | import { | 18 | import { |
19 | - AggregationType, | 19 | + AggregationType, calculateIntervalComparisonEndTime, |
20 | calculateIntervalEndTime, | 20 | calculateIntervalEndTime, |
21 | calculateIntervalStartTime, | 21 | calculateIntervalStartTime, |
22 | getCurrentTime, | 22 | getCurrentTime, |
@@ -26,6 +26,7 @@ import { | @@ -26,6 +26,7 @@ import { | ||
26 | import { UtilsService } from '@core/services/utils.service'; | 26 | import { UtilsService } from '@core/services/utils.service'; |
27 | import { deepClone } from '@core/utils'; | 27 | import { deepClone } from '@core/utils'; |
28 | import Timeout = NodeJS.Timeout; | 28 | import Timeout = NodeJS.Timeout; |
29 | +import * as moment_ from 'moment'; | ||
29 | 30 | ||
30 | export declare type onAggregatedData = (data: SubscriptionData, detectChanges: boolean) => void; | 31 | export declare type onAggregatedData = (data: SubscriptionData, detectChanges: boolean) => void; |
31 | 32 | ||
@@ -87,7 +88,7 @@ export class DataAggregator { | @@ -87,7 +88,7 @@ export class DataAggregator { | ||
87 | private intervalTimeoutHandle: Timeout; | 88 | private intervalTimeoutHandle: Timeout; |
88 | private intervalScheduledTime: number; | 89 | private intervalScheduledTime: number; |
89 | 90 | ||
90 | - private startTs = this.subsTw.startTs + this.subsTw.tsOffset; | 91 | + private startTs: number; |
91 | private endTs: number; | 92 | private endTs: number; |
92 | private elapsed: number; | 93 | private elapsed: number; |
93 | 94 | ||
@@ -139,13 +140,7 @@ export class DataAggregator { | @@ -139,13 +140,7 @@ export class DataAggregator { | ||
139 | } | 140 | } |
140 | this.subsTw = subsTw; | 141 | this.subsTw = subsTw; |
141 | this.intervalScheduledTime = this.utils.currentPerfTime(); | 142 | this.intervalScheduledTime = this.utils.currentPerfTime(); |
142 | - this.startTs = this.subsTw.startTs + this.subsTw.tsOffset; | ||
143 | - if (this.subsTw.quickInterval) { | ||
144 | - const currentDate = this.getCurrentTime(); | ||
145 | - this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; | ||
146 | - } else { | ||
147 | - this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; | ||
148 | - } | 143 | + this.calculateStartEndTs(); |
149 | this.elapsed = 0; | 144 | this.elapsed = 0; |
150 | this.aggregationTimeout = Math.max(this.subsTw.aggregation.interval, 1000); | 145 | this.aggregationTimeout = Math.max(this.subsTw.aggregation.interval, 1000); |
151 | this.resetPending = true; | 146 | this.resetPending = true; |
@@ -168,12 +163,7 @@ export class DataAggregator { | @@ -168,12 +163,7 @@ export class DataAggregator { | ||
168 | if (!this.dataReceived) { | 163 | if (!this.dataReceived) { |
169 | this.elapsed = 0; | 164 | this.elapsed = 0; |
170 | this.dataReceived = true; | 165 | this.dataReceived = true; |
171 | - if (this.subsTw.quickInterval) { | ||
172 | - const currentDate = this.getCurrentTime(); | ||
173 | - this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; | ||
174 | - } else { | ||
175 | - this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; | ||
176 | - } | 166 | + this.calculateStartEndTs(); |
177 | } | 167 | } |
178 | if (this.resetPending) { | 168 | if (this.resetPending) { |
179 | this.resetPending = false; | 169 | this.resetPending = false; |
@@ -198,6 +188,21 @@ export class DataAggregator { | @@ -198,6 +188,21 @@ export class DataAggregator { | ||
198 | } | 188 | } |
199 | } | 189 | } |
200 | 190 | ||
191 | + private calculateStartEndTs() { | ||
192 | + this.startTs = this.subsTw.startTs + this.subsTw.tsOffset; | ||
193 | + if (this.subsTw.quickInterval) { | ||
194 | + if (this.subsTw.timeForComparison === 'previousInterval') { | ||
195 | + const currentDate = getCurrentTime(this.subsTw.timezone); | ||
196 | + this.endTs = calculateIntervalComparisonEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; | ||
197 | + } else { | ||
198 | + const currentDate = this.getCurrentTime(); | ||
199 | + this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset; | ||
200 | + } | ||
201 | + } else { | ||
202 | + this.endTs = this.startTs + this.subsTw.aggregation.timeWindow; | ||
203 | + } | ||
204 | + } | ||
205 | + | ||
201 | private onInterval(history?: boolean, detectChanges?: boolean) { | 206 | private onInterval(history?: boolean, detectChanges?: boolean) { |
202 | const now = this.utils.currentPerfTime(); | 207 | const now = this.utils.currentPerfTime(); |
203 | this.elapsed += now - this.intervalScheduledTime; | 208 | this.elapsed += now - this.intervalScheduledTime; |
@@ -362,7 +367,7 @@ export class DataAggregator { | @@ -362,7 +367,7 @@ export class DataAggregator { | ||
362 | 367 | ||
363 | private getCurrentTime() { | 368 | private getCurrentTime() { |
364 | if (this.subsTw.timeForComparison) { | 369 | if (this.subsTw.timeForComparison) { |
365 | - return getCurrentTimeForComparison(this.subsTw.timeForComparison, this.subsTw.timezone); | 370 | + return getCurrentTimeForComparison(this.subsTw.timeForComparison as moment_.unitOfTime.DurationConstructor, this.subsTw.timezone); |
366 | } else { | 371 | } else { |
367 | return getCurrentTime(this.subsTw.timezone); | 372 | return getCurrentTime(this.subsTw.timezone); |
368 | } | 373 | } |
@@ -419,8 +419,8 @@ export class EntityDataSubscription { | @@ -419,8 +419,8 @@ export class EntityDataSubscription { | ||
419 | latestTsOffsetChanged = this.subscriber.setTsOffset(this.latestTsOffset); | 419 | latestTsOffsetChanged = this.subscriber.setTsOffset(this.latestTsOffset); |
420 | } | 420 | } |
421 | if (latestTsOffsetChanged) { | 421 | if (latestTsOffsetChanged) { |
422 | - if (this.listener.initialPageDataChanged) { | ||
423 | - this.listener.initialPageDataChanged(this.pageData); | 422 | + if (this.listener.forceReInit) { |
423 | + this.listener.forceReInit(); | ||
424 | } | 424 | } |
425 | } else if (!this.subsCommand.isEmpty()) { | 425 | } else if (!this.subsCommand.isEmpty()) { |
426 | this.subscriber.subscriptionCommands = [this.subsCommand]; | 426 | this.subscriber.subscriptionCommands = [this.subsCommand]; |
@@ -428,8 +428,8 @@ export class EntityDataSubscription { | @@ -428,8 +428,8 @@ export class EntityDataSubscription { | ||
428 | } | 428 | } |
429 | } else if (this.datasourceType === DatasourceType.entityCount) { | 429 | } else if (this.datasourceType === DatasourceType.entityCount) { |
430 | if (this.subscriber.setTsOffset(this.latestTsOffset)) { | 430 | if (this.subscriber.setTsOffset(this.latestTsOffset)) { |
431 | - if (this.listener.initialPageDataChanged) { | ||
432 | - this.listener.initialPageDataChanged(this.pageData); | 431 | + if (this.listener.forceReInit) { |
432 | + this.listener.forceReInit(); | ||
433 | } | 433 | } |
434 | } | 434 | } |
435 | } else if (this.datasourceType === DatasourceType.function) { | 435 | } else if (this.datasourceType === DatasourceType.function) { |
@@ -40,6 +40,7 @@ export interface EntityDataListener { | @@ -40,6 +40,7 @@ export interface EntityDataListener { | ||
40 | datasourceIndex: number, pageLink: EntityDataPageLink) => void; | 40 | datasourceIndex: number, pageLink: EntityDataPageLink) => void; |
41 | dataUpdated: (data: DataSetHolder, datasourceIndex: number, dataIndex: number, dataKeyIndex: number, detectChanges: boolean) => void; | 41 | dataUpdated: (data: DataSetHolder, datasourceIndex: number, dataIndex: number, dataKeyIndex: number, detectChanges: boolean) => void; |
42 | initialPageDataChanged?: (nextPageData: PageData<EntityData>) => void; | 42 | initialPageDataChanged?: (nextPageData: PageData<EntityData>) => void; |
43 | + forceReInit?: () => void; | ||
43 | updateRealtimeSubscription?: () => SubscriptionTimewindow; | 44 | updateRealtimeSubscription?: () => SubscriptionTimewindow; |
44 | setRealtimeSubscription?: (subscriptionTimewindow: SubscriptionTimewindow) => void; | 45 | setRealtimeSubscription?: (subscriptionTimewindow: SubscriptionTimewindow) => void; |
45 | subscriptionOptions?: EntityDataSubscriptionOptions; | 46 | subscriptionOptions?: EntityDataSubscriptionOptions; |
@@ -209,6 +209,7 @@ export interface WidgetSubscriptionCallbacks { | @@ -209,6 +209,7 @@ export interface WidgetSubscriptionCallbacks { | ||
209 | onDataUpdateError?: (subscription: IWidgetSubscription, e: any) => void; | 209 | onDataUpdateError?: (subscription: IWidgetSubscription, e: any) => void; |
210 | onSubscriptionMessage?: (subscription: IWidgetSubscription, message: SubscriptionMessage) => void; | 210 | onSubscriptionMessage?: (subscription: IWidgetSubscription, message: SubscriptionMessage) => void; |
211 | onInitialPageDataChanged?: (subscription: IWidgetSubscription, nextPageData: PageData<EntityData>) => void; | 211 | onInitialPageDataChanged?: (subscription: IWidgetSubscription, nextPageData: PageData<EntityData>) => void; |
212 | + forceReInit?: () => void; | ||
212 | dataLoading?: (subscription: IWidgetSubscription) => void; | 213 | dataLoading?: (subscription: IWidgetSubscription) => void; |
213 | legendDataUpdated?: (subscription: IWidgetSubscription, detectChanges: boolean) => void; | 214 | legendDataUpdated?: (subscription: IWidgetSubscription, detectChanges: boolean) => void; |
214 | timeWindowUpdated?: (subscription: IWidgetSubscription, timeWindowConfig: Timewindow) => void; | 215 | timeWindowUpdated?: (subscription: IWidgetSubscription, timeWindowConfig: Timewindow) => void; |
@@ -269,6 +270,7 @@ export interface IWidgetSubscription { | @@ -269,6 +270,7 @@ export interface IWidgetSubscription { | ||
269 | hiddenData?: Array<{data: DataSet}>; | 270 | hiddenData?: Array<{data: DataSet}>; |
270 | timeWindowConfig?: Timewindow; | 271 | timeWindowConfig?: Timewindow; |
271 | timeWindow?: WidgetTimewindow; | 272 | timeWindow?: WidgetTimewindow; |
273 | + comparisonEnabled?: boolean; | ||
272 | comparisonTimeWindow?: WidgetTimewindow; | 274 | comparisonTimeWindow?: WidgetTimewindow; |
273 | 275 | ||
274 | alarms?: PageData<AlarmData>; | 276 | alarms?: PageData<AlarmData>; |
@@ -36,6 +36,18 @@ import { | @@ -36,6 +36,18 @@ import { | ||
36 | widgetType | 36 | widgetType |
37 | } from '@app/shared/models/widget.models'; | 37 | } from '@app/shared/models/widget.models'; |
38 | import { HttpErrorResponse } from '@angular/common/http'; | 38 | import { HttpErrorResponse } from '@angular/common/http'; |
39 | +import { | ||
40 | + calculateIntervalEndTime, | ||
41 | + calculateIntervalStartTime, | ||
42 | + calculateTsOffset, ComparisonDuration, | ||
43 | + createSubscriptionTimewindow, | ||
44 | + createTimewindowForComparison, | ||
45 | + getCurrentTime, isHistoryTypeTimewindow, | ||
46 | + SubscriptionTimewindow, | ||
47 | + Timewindow, timewindowTypeChanged, | ||
48 | + toHistoryTimewindow, | ||
49 | + WidgetTimewindow | ||
50 | +} from '@app/shared/models/time/time.models'; | ||
39 | import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'; | 51 | import { forkJoin, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs'; |
40 | import { CancelAnimationFrame } from '@core/services/raf.service'; | 52 | import { CancelAnimationFrame } from '@core/services/raf.service'; |
41 | import { EntityType } from '@shared/models/entity-type.models'; | 53 | import { EntityType } from '@shared/models/entity-type.models'; |
@@ -56,19 +68,6 @@ import { | @@ -56,19 +68,6 @@ import { | ||
56 | } from '@shared/models/query/query.models'; | 68 | } from '@shared/models/query/query.models'; |
57 | import { map } from 'rxjs/operators'; | 69 | import { map } from 'rxjs/operators'; |
58 | import { AlarmDataListener } from '@core/api/alarm-data.service'; | 70 | import { AlarmDataListener } from '@core/api/alarm-data.service'; |
59 | -import { | ||
60 | - calculateIntervalEndTime, | ||
61 | - calculateIntervalStartTime, | ||
62 | - calculateTsOffset, | ||
63 | - createSubscriptionTimewindow, | ||
64 | - createTimewindowForComparison, | ||
65 | - getCurrentTime, | ||
66 | - isHistoryTypeTimewindow, | ||
67 | - SubscriptionTimewindow, | ||
68 | - Timewindow, | ||
69 | - toHistoryTimewindow, | ||
70 | - WidgetTimewindow | ||
71 | -} from '@app/shared/models/time/time.models'; | ||
72 | 71 | ||
73 | const moment = moment_; | 72 | const moment = moment_; |
74 | 73 | ||
@@ -108,7 +107,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -108,7 +107,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
108 | decimals: number; | 107 | decimals: number; |
109 | units: string; | 108 | units: string; |
110 | comparisonEnabled: boolean; | 109 | comparisonEnabled: boolean; |
111 | - timeForComparison: moment_.unitOfTime.DurationConstructor; | 110 | + timeForComparison: ComparisonDuration; |
112 | comparisonTimeWindow: WidgetTimewindow; | 111 | comparisonTimeWindow: WidgetTimewindow; |
113 | timewindowForComparison: SubscriptionTimewindow; | 112 | timewindowForComparison: SubscriptionTimewindow; |
114 | 113 | ||
@@ -199,6 +198,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -199,6 +198,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
199 | this.callbacks.onDataUpdateError = this.callbacks.onDataUpdateError || (() => {}); | 198 | this.callbacks.onDataUpdateError = this.callbacks.onDataUpdateError || (() => {}); |
200 | this.callbacks.onSubscriptionMessage = this.callbacks.onSubscriptionMessage || (() => {}); | 199 | this.callbacks.onSubscriptionMessage = this.callbacks.onSubscriptionMessage || (() => {}); |
201 | this.callbacks.onInitialPageDataChanged = this.callbacks.onInitialPageDataChanged || (() => {}); | 200 | this.callbacks.onInitialPageDataChanged = this.callbacks.onInitialPageDataChanged || (() => {}); |
201 | + this.callbacks.forceReInit = this.callbacks.forceReInit || (() => {}); | ||
202 | this.callbacks.dataLoading = this.callbacks.dataLoading || (() => {}); | 202 | this.callbacks.dataLoading = this.callbacks.dataLoading || (() => {}); |
203 | this.callbacks.legendDataUpdated = this.callbacks.legendDataUpdated || (() => {}); | 203 | this.callbacks.legendDataUpdated = this.callbacks.legendDataUpdated || (() => {}); |
204 | this.callbacks.timeWindowUpdated = this.callbacks.timeWindowUpdated || (() => {}); | 204 | this.callbacks.timeWindowUpdated = this.callbacks.timeWindowUpdated || (() => {}); |
@@ -229,7 +229,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -229,7 +229,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
229 | } | 229 | } |
230 | 230 | ||
231 | this.subscriptionTimewindow = null; | 231 | this.subscriptionTimewindow = null; |
232 | - this.comparisonEnabled = options.comparisonEnabled; | 232 | + this.comparisonEnabled = options.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig); |
233 | if (this.comparisonEnabled) { | 233 | if (this.comparisonEnabled) { |
234 | this.timeForComparison = options.timeForComparison; | 234 | this.timeForComparison = options.timeForComparison; |
235 | 235 | ||
@@ -388,7 +388,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -388,7 +388,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
388 | this.notifyDataLoaded(); | 388 | this.notifyDataLoaded(); |
389 | return of(null); | 389 | return of(null); |
390 | } | 390 | } |
391 | - if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) { | 391 | + if (this.comparisonEnabled) { |
392 | const additionalDatasources: Datasource[] = []; | 392 | const additionalDatasources: Datasource[] = []; |
393 | this.configuredDatasources.forEach((datasource, datasourceIndex) => { | 393 | this.configuredDatasources.forEach((datasource, datasourceIndex) => { |
394 | const additionalDataKeys: DataKey[] = []; | 394 | const additionalDataKeys: DataKey[] = []; |
@@ -419,20 +419,13 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -419,20 +419,13 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
419 | this.dataLoaded(pageData, data1, datasourceIndex, pageLink, true); | 419 | this.dataLoaded(pageData, data1, datasourceIndex, pageLink, true); |
420 | }, | 420 | }, |
421 | initialPageDataChanged: this.initialPageDataChanged.bind(this), | 421 | initialPageDataChanged: this.initialPageDataChanged.bind(this), |
422 | + forceReInit: this.forceReInit.bind(this), | ||
422 | dataUpdated: this.dataUpdated.bind(this), | 423 | dataUpdated: this.dataUpdated.bind(this), |
423 | updateRealtimeSubscription: () => { | 424 | updateRealtimeSubscription: () => { |
424 | - if (this.comparisonEnabled && datasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) { | ||
425 | - return this.updateSubscriptionForComparison(); | ||
426 | - } else { | ||
427 | - return this.updateRealtimeSubscription(); | ||
428 | - } | 425 | + return this.updateRealtimeSubscription(); |
429 | }, | 426 | }, |
430 | setRealtimeSubscription: (subscriptionTimewindow) => { | 427 | setRealtimeSubscription: (subscriptionTimewindow) => { |
431 | - if (this.comparisonEnabled && datasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) { | ||
432 | - this.updateSubscriptionForComparison(subscriptionTimewindow); | ||
433 | - } else { | ||
434 | - this.updateRealtimeSubscription(deepClone(subscriptionTimewindow)); | ||
435 | - } | 428 | + this.updateRealtimeSubscription(deepClone(subscriptionTimewindow)); |
436 | } | 429 | } |
437 | }; | 430 | }; |
438 | this.entityDataListeners.push(listener); | 431 | this.entityDataListeners.push(listener); |
@@ -585,8 +578,9 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -585,8 +578,9 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
585 | if (this.type === widgetType.timeseries || this.type === widgetType.alarm) { | 578 | if (this.type === widgetType.timeseries || this.type === widgetType.alarm) { |
586 | if (this.useDashboardTimewindow) { | 579 | if (this.useDashboardTimewindow) { |
587 | if (!isEqual(this.timeWindowConfig, newDashboardTimewindow) && newDashboardTimewindow) { | 580 | if (!isEqual(this.timeWindowConfig, newDashboardTimewindow) && newDashboardTimewindow) { |
581 | + const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, newDashboardTimewindow); | ||
588 | this.timeWindowConfig = deepClone(newDashboardTimewindow); | 582 | this.timeWindowConfig = deepClone(newDashboardTimewindow); |
589 | - this.update(); | 583 | + this.update(isTimewindowTypeChanged); |
590 | } | 584 | } |
591 | } | 585 | } |
592 | } else if (this.type === widgetType.latest) { | 586 | } else if (this.type === widgetType.latest) { |
@@ -615,8 +609,9 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -615,8 +609,9 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
615 | 609 | ||
616 | updateTimewindowConfig(newTimewindow: Timewindow): void { | 610 | updateTimewindowConfig(newTimewindow: Timewindow): void { |
617 | if (!this.useDashboardTimewindow) { | 611 | if (!this.useDashboardTimewindow) { |
612 | + const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, newTimewindow); | ||
618 | this.timeWindowConfig = newTimewindow; | 613 | this.timeWindowConfig = newTimewindow; |
619 | - this.update(); | 614 | + this.update(isTimewindowTypeChanged); |
620 | } | 615 | } |
621 | } | 616 | } |
622 | 617 | ||
@@ -625,10 +620,11 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -625,10 +620,11 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
625 | this.ctx.dashboardTimewindowApi.onResetTimewindow(); | 620 | this.ctx.dashboardTimewindowApi.onResetTimewindow(); |
626 | } else { | 621 | } else { |
627 | if (this.originalTimewindow) { | 622 | if (this.originalTimewindow) { |
623 | + const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, this.originalTimewindow); | ||
628 | this.timeWindowConfig = deepClone(this.originalTimewindow); | 624 | this.timeWindowConfig = deepClone(this.originalTimewindow); |
629 | this.originalTimewindow = null; | 625 | this.originalTimewindow = null; |
630 | this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); | 626 | this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); |
631 | - this.update(); | 627 | + this.update(isTimewindowTypeChanged); |
632 | } | 628 | } |
633 | } | 629 | } |
634 | } | 630 | } |
@@ -642,7 +638,8 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -642,7 +638,8 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
642 | } | 638 | } |
643 | this.timeWindowConfig = toHistoryTimewindow(this.timeWindowConfig, startTimeMs, endTimeMs, interval, this.ctx.timeService); | 639 | this.timeWindowConfig = toHistoryTimewindow(this.timeWindowConfig, startTimeMs, endTimeMs, interval, this.ctx.timeService); |
644 | this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); | 640 | this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); |
645 | - this.update(); | 641 | + const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, this.originalTimewindow); |
642 | + this.update(isTimewindowTypeChanged); | ||
646 | } | 643 | } |
647 | } | 644 | } |
648 | 645 | ||
@@ -771,16 +768,20 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -771,16 +768,20 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
771 | } | 768 | } |
772 | } | 769 | } |
773 | 770 | ||
774 | - update() { | 771 | + update(isTimewindowTypeChanged = false) { |
775 | if (this.type !== widgetType.rpc) { | 772 | if (this.type !== widgetType.rpc) { |
776 | if (this.type === widgetType.alarm) { | 773 | if (this.type === widgetType.alarm) { |
777 | this.updateAlarmDataSubscription(); | 774 | this.updateAlarmDataSubscription(); |
778 | } else { | 775 | } else { |
779 | - if (this.hasDataPageLink) { | ||
780 | - this.updateDataSubscriptions(); | 776 | + if (this.type === widgetType.timeseries && this.options.comparisonEnabled && isTimewindowTypeChanged) { |
777 | + this.forceReInit(); | ||
781 | } else { | 778 | } else { |
782 | - this.notifyDataLoading(); | ||
783 | - this.dataSubscribe(); | 779 | + if (this.hasDataPageLink) { |
780 | + this.updateDataSubscriptions(); | ||
781 | + } else { | ||
782 | + this.notifyDataLoading(); | ||
783 | + this.dataSubscribe(); | ||
784 | + } | ||
784 | } | 785 | } |
785 | } | 786 | } |
786 | } | 787 | } |
@@ -889,7 +890,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -889,7 +890,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
889 | if (!this.hasDataPageLink) { | 890 | if (!this.hasDataPageLink) { |
890 | if (this.type === widgetType.timeseries && this.timeWindowConfig) { | 891 | if (this.type === widgetType.timeseries && this.timeWindowConfig) { |
891 | this.updateRealtimeSubscription(); | 892 | this.updateRealtimeSubscription(); |
892 | - if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) { | 893 | + if (this.comparisonEnabled) { |
893 | this.updateSubscriptionForComparison(); | 894 | this.updateSubscriptionForComparison(); |
894 | } | 895 | } |
895 | } | 896 | } |
@@ -905,7 +906,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -905,7 +906,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
905 | const forceUpdate = !this.datasources.length; | 906 | const forceUpdate = !this.datasources.length; |
906 | const notifyDataLoaded = !this.entityDataListeners.filter((listener) => listener.subscription ? true : false).length; | 907 | const notifyDataLoaded = !this.entityDataListeners.filter((listener) => listener.subscription ? true : false).length; |
907 | this.entityDataListeners.forEach((listener) => { | 908 | this.entityDataListeners.forEach((listener) => { |
908 | - if (this.comparisonEnabled && listener.configDatasource.isAdditional && isHistoryTypeTimewindow(this.timeWindowConfig)) { | 909 | + if (this.comparisonEnabled && listener.configDatasource.isAdditional) { |
909 | listener.subscriptionTimewindow = this.timewindowForComparison; | 910 | listener.subscriptionTimewindow = this.timewindowForComparison; |
910 | } else { | 911 | } else { |
911 | listener.subscriptionTimewindow = this.subscriptionTimewindow; | 912 | listener.subscriptionTimewindow = this.subscriptionTimewindow; |
@@ -1144,24 +1145,14 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -1144,24 +1145,14 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
1144 | private updateComparisonTimewindow() { | 1145 | private updateComparisonTimewindow() { |
1145 | this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000; | 1146 | this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000; |
1146 | this.comparisonTimeWindow.timezone = this.timewindowForComparison.timezone; | 1147 | this.comparisonTimeWindow.timezone = this.timewindowForComparison.timezone; |
1147 | - if (this.timewindowForComparison.realtimeWindowMs) { | ||
1148 | - this.comparisonTimeWindow.maxTime = moment(this.timeWindow.maxTime).subtract(1, this.timeForComparison).valueOf(); | ||
1149 | - this.comparisonTimeWindow.minTime = moment(this.timeWindow.minTime).subtract(1, this.timeForComparison).valueOf(); | ||
1150 | - } else if (this.timewindowForComparison.fixedWindow) { | ||
1151 | - this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs; | ||
1152 | - this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs; | 1148 | + if (this.timewindowForComparison.fixedWindow) { |
1149 | + this.comparisonTimeWindow.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs + this.timewindowForComparison.tsOffset; | ||
1150 | + this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs + this.timewindowForComparison.tsOffset; | ||
1153 | } | 1151 | } |
1154 | } | 1152 | } |
1155 | 1153 | ||
1156 | - private updateSubscriptionForComparison(subscriptionTimewindow?: SubscriptionTimewindow): SubscriptionTimewindow { | ||
1157 | - if (subscriptionTimewindow) { | ||
1158 | - this.timewindowForComparison = subscriptionTimewindow; | ||
1159 | - } else { | ||
1160 | - if (!this.subscriptionTimewindow) { | ||
1161 | - this.subscriptionTimewindow = this.updateRealtimeSubscription(); | ||
1162 | - } | ||
1163 | - this.timewindowForComparison = createTimewindowForComparison(this.subscriptionTimewindow, this.timeForComparison); | ||
1164 | - } | 1154 | + private updateSubscriptionForComparison(): SubscriptionTimewindow { |
1155 | + this.timewindowForComparison = createTimewindowForComparison(this.subscriptionTimewindow, this.timeForComparison); | ||
1165 | this.updateComparisonTimewindow(); | 1156 | this.updateComparisonTimewindow(); |
1166 | return this.timewindowForComparison; | 1157 | return this.timewindowForComparison; |
1167 | } | 1158 | } |
@@ -1170,6 +1161,10 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -1170,6 +1161,10 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
1170 | this.callbacks.onInitialPageDataChanged(this, nextPageData); | 1161 | this.callbacks.onInitialPageDataChanged(this, nextPageData); |
1171 | } | 1162 | } |
1172 | 1163 | ||
1164 | + private forceReInit() { | ||
1165 | + this.callbacks.forceReInit(); | ||
1166 | + } | ||
1167 | + | ||
1173 | private dataLoaded(pageData: PageData<EntityData>, | 1168 | private dataLoaded(pageData: PageData<EntityData>, |
1174 | data: Array<Array<DataSetHolder>>, | 1169 | data: Array<Array<DataSetHolder>>, |
1175 | datasourceIndex: number, pageLink: EntityDataPageLink, isUpdate: boolean) { | 1170 | datasourceIndex: number, pageLink: EntityDataPageLink, isUpdate: boolean) { |
@@ -1262,7 +1257,7 @@ export class WidgetSubscription implements IWidgetSubscription { | @@ -1262,7 +1257,7 @@ export class WidgetSubscription implements IWidgetSubscription { | ||
1262 | index++; | 1257 | index++; |
1263 | }); | 1258 | }); |
1264 | }); | 1259 | }); |
1265 | - if (this.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig)) { | 1260 | + if (this.comparisonEnabled) { |
1266 | this.datasourcePages.forEach(datasourcePage => { | 1261 | this.datasourcePages.forEach(datasourcePage => { |
1267 | datasourcePage.data.forEach((datasource, dIndex) => { | 1262 | datasourcePage.data.forEach((datasource, dIndex) => { |
1268 | if (datasource.isAdditional) { | 1263 | if (datasource.isAdditional) { |
@@ -20,6 +20,7 @@ | @@ -20,6 +20,7 @@ | ||
20 | import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; | 20 | import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; |
21 | import * as moment_ from 'moment'; | 21 | import * as moment_ from 'moment'; |
22 | import { DataKeyType } from "@shared/models/telemetry/telemetry.models"; | 22 | import { DataKeyType } from "@shared/models/telemetry/telemetry.models"; |
23 | +import { ComparisonDuration } from '@shared/models/time/time.models'; | ||
23 | 24 | ||
24 | export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; | 25 | export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; |
25 | 26 | ||
@@ -142,7 +143,7 @@ export interface TbFlotBaseSettings { | @@ -142,7 +143,7 @@ export interface TbFlotBaseSettings { | ||
142 | 143 | ||
143 | export interface TbFlotComparisonSettings { | 144 | export interface TbFlotComparisonSettings { |
144 | comparisonEnabled: boolean; | 145 | comparisonEnabled: boolean; |
145 | - timeForComparison: moment_.unitOfTime.DurationConstructor; | 146 | + timeForComparison: ComparisonDuration; |
146 | xaxisSecond: TbFlotSecondXAxisSettings; | 147 | xaxisSecond: TbFlotSecondXAxisSettings; |
147 | } | 148 | } |
148 | 149 | ||
@@ -543,7 +544,7 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | @@ -543,7 +544,7 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | ||
543 | timeForComparison: { | 544 | timeForComparison: { |
544 | title: 'Time to show historical data', | 545 | title: 'Time to show historical data', |
545 | type: 'string', | 546 | type: 'string', |
546 | - default: 'months' | 547 | + default: 'previousInterval' |
547 | }, | 548 | }, |
548 | xaxisSecond: { | 549 | xaxisSecond: { |
549 | title: 'Second X axis', | 550 | title: 'Second X axis', |
@@ -577,6 +578,10 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | @@ -577,6 +578,10 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | ||
577 | multiple: false, | 578 | multiple: false, |
578 | items: [ | 579 | items: [ |
579 | { | 580 | { |
581 | + value: 'previousInterval', | ||
582 | + label: 'Previous interval (default)' | ||
583 | + }, | ||
584 | + { | ||
580 | value: 'days', | 585 | value: 'days', |
581 | label: 'Day ago' | 586 | label: 'Day ago' |
582 | }, | 587 | }, |
@@ -586,7 +591,7 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | @@ -586,7 +591,7 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = { | ||
586 | }, | 591 | }, |
587 | { | 592 | { |
588 | value: 'months', | 593 | value: 'months', |
589 | - label: 'Month ago (default)' | 594 | + label: 'Month ago' |
590 | }, | 595 | }, |
591 | { | 596 | { |
592 | value: 'years', | 597 | value: 'years', |
@@ -74,6 +74,7 @@ export class TbFlot { | @@ -74,6 +74,7 @@ export class TbFlot { | ||
74 | private readonly utils: UtilsService; | 74 | private readonly utils: UtilsService; |
75 | 75 | ||
76 | private settings: TbFlotSettings; | 76 | private settings: TbFlotSettings; |
77 | + private comparisonEnabled: boolean; | ||
77 | 78 | ||
78 | private readonly tooltip: JQuery<any>; | 79 | private readonly tooltip: JQuery<any>; |
79 | 80 | ||
@@ -263,29 +264,7 @@ export class TbFlot { | @@ -263,29 +264,7 @@ export class TbFlot { | ||
263 | }; | 264 | }; |
264 | } | 265 | } |
265 | 266 | ||
266 | - if (this.settings.comparisonEnabled) { | ||
267 | - const xaxis = deepClone(this.xaxis); | ||
268 | - xaxis.position = 'top'; | ||
269 | - if (this.settings.xaxisSecond) { | ||
270 | - if (this.settings.xaxisSecond.showLabels === false) { | ||
271 | - xaxis.tickFormatter = () => { | ||
272 | - return ''; | ||
273 | - }; | ||
274 | - } | ||
275 | - xaxis.label = this.utils.customTranslation(this.settings.xaxisSecond.title, this.settings.xaxisSecond.title) || null; | ||
276 | - xaxis.position = this.settings.xaxisSecond.axisPosition; | ||
277 | - } | ||
278 | - xaxis.tickLength = 0; | ||
279 | - this.options.xaxes.push(xaxis); | ||
280 | - | ||
281 | - this.options.series = { | ||
282 | - stack: false | ||
283 | - }; | ||
284 | - } else { | ||
285 | - this.options.series = { | ||
286 | - stack: this.settings.stack === true | ||
287 | - }; | ||
288 | - } | 267 | + this.options.series = {}; |
289 | 268 | ||
290 | this.options.crosshair = { | 269 | this.options.crosshair = { |
291 | mode: 'x' | 270 | mode: 'x' |
@@ -364,7 +343,6 @@ export class TbFlot { | @@ -364,7 +343,6 @@ export class TbFlot { | ||
364 | 343 | ||
365 | // Experimental | 344 | // Experimental |
366 | this.animatedPie = this.settings.animatedPie === true; | 345 | this.animatedPie = this.settings.animatedPie === true; |
367 | - | ||
368 | } | 346 | } |
369 | 347 | ||
370 | if (this.ctx.defaultSubscription) { | 348 | if (this.ctx.defaultSubscription) { |
@@ -372,10 +350,29 @@ export class TbFlot { | @@ -372,10 +350,29 @@ export class TbFlot { | ||
372 | } | 350 | } |
373 | } | 351 | } |
374 | 352 | ||
375 | - | ||
376 | private init($element: JQuery<any>, subscription: IWidgetSubscription) { | 353 | private init($element: JQuery<any>, subscription: IWidgetSubscription) { |
377 | - this.subscription = subscription; | ||
378 | this.$element = $element; | 354 | this.$element = $element; |
355 | + this.subscription = subscription; | ||
356 | + this.comparisonEnabled = this.subscription ? this.subscription.comparisonEnabled : this.settings.comparisonEnabled; | ||
357 | + if (this.comparisonEnabled) { | ||
358 | + const xaxis = deepClone(this.xaxis); | ||
359 | + xaxis.position = 'top'; | ||
360 | + if (this.settings.xaxisSecond) { | ||
361 | + if (this.settings.xaxisSecond.showLabels === false) { | ||
362 | + xaxis.tickFormatter = () => { | ||
363 | + return ''; | ||
364 | + }; | ||
365 | + } | ||
366 | + xaxis.label = this.utils.customTranslation(this.settings.xaxisSecond.title, this.settings.xaxisSecond.title) || null; | ||
367 | + xaxis.position = this.settings.xaxisSecond.axisPosition; | ||
368 | + } | ||
369 | + xaxis.tickLength = 0; | ||
370 | + this.options.xaxes.push(xaxis); | ||
371 | + | ||
372 | + this.options.series.stack = false; | ||
373 | + } else { | ||
374 | + this.options.series.stack = this.settings.stack === true; | ||
375 | + } | ||
379 | const colors: string[] = []; | 376 | const colors: string[] = []; |
380 | this.yaxes = []; | 377 | this.yaxes = []; |
381 | const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; | 378 | const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; |
@@ -387,7 +384,7 @@ export class TbFlot { | @@ -387,7 +384,7 @@ export class TbFlot { | ||
387 | this.settings.dataKeysListForLabels.forEach((item) => { | 384 | this.settings.dataKeysListForLabels.forEach((item) => { |
388 | item.settings = {}; | 385 | item.settings = {}; |
389 | }); | 386 | }); |
390 | - subscription.datasources.forEach((item) => { | 387 | + this.subscription.datasources.forEach((item) => { |
391 | const datasource: Datasource = { | 388 | const datasource: Datasource = { |
392 | type: item.type, | 389 | type: item.type, |
393 | entityType: item.entityType, | 390 | entityType: item.entityType, |
@@ -425,7 +422,7 @@ export class TbFlot { | @@ -425,7 +422,7 @@ export class TbFlot { | ||
425 | fill: keySettings.fillLines === true | 422 | fill: keySettings.fillLines === true |
426 | }; | 423 | }; |
427 | 424 | ||
428 | - if (this.settings.stack && !this.settings.comparisonEnabled) { | 425 | + if (this.settings.stack && !this.comparisonEnabled) { |
429 | series.stack = !keySettings.excludeFromStacking; | 426 | series.stack = !keySettings.excludeFromStacking; |
430 | } else { | 427 | } else { |
431 | series.stack = false; | 428 | series.stack = false; |
@@ -557,7 +554,7 @@ export class TbFlot { | @@ -557,7 +554,7 @@ export class TbFlot { | ||
557 | } | 554 | } |
558 | this.options.xaxes[0].min = this.subscription.timeWindow.minTime; | 555 | this.options.xaxes[0].min = this.subscription.timeWindow.minTime; |
559 | this.options.xaxes[0].max = this.subscription.timeWindow.maxTime; | 556 | this.options.xaxes[0].max = this.subscription.timeWindow.maxTime; |
560 | - if (this.settings.comparisonEnabled) { | 557 | + if (this.comparisonEnabled) { |
561 | this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; | 558 | this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; |
562 | this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; | 559 | this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; |
563 | } | 560 | } |
@@ -636,7 +633,7 @@ export class TbFlot { | @@ -636,7 +633,7 @@ export class TbFlot { | ||
636 | 633 | ||
637 | this.options.xaxes[0].min = this.subscription.timeWindow.minTime; | 634 | this.options.xaxes[0].min = this.subscription.timeWindow.minTime; |
638 | this.options.xaxes[0].max = this.subscription.timeWindow.maxTime; | 635 | this.options.xaxes[0].max = this.subscription.timeWindow.maxTime; |
639 | - if (this.settings.comparisonEnabled) { | 636 | + if (this.comparisonEnabled) { |
640 | this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; | 637 | this.options.xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; |
641 | this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; | 638 | this.options.xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; |
642 | } | 639 | } |
@@ -654,7 +651,7 @@ export class TbFlot { | @@ -654,7 +651,7 @@ export class TbFlot { | ||
654 | } else { | 651 | } else { |
655 | this.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime; | 652 | this.plot.getOptions().xaxes[0].min = this.subscription.timeWindow.minTime; |
656 | this.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime; | 653 | this.plot.getOptions().xaxes[0].max = this.subscription.timeWindow.maxTime; |
657 | - if (this.settings.comparisonEnabled) { | 654 | + if (this.comparisonEnabled) { |
658 | this.plot.getOptions().xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; | 655 | this.plot.getOptions().xaxes[1].min = this.subscription.comparisonTimeWindow.minTime; |
659 | this.plot.getOptions().xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; | 656 | this.plot.getOptions().xaxes[1].max = this.subscription.comparisonTimeWindow.maxTime; |
660 | } | 657 | } |
@@ -1293,7 +1290,7 @@ export class TbFlot { | @@ -1293,7 +1290,7 @@ export class TbFlot { | ||
1293 | const results: TbFlotHoverInfo[] = [{ | 1290 | const results: TbFlotHoverInfo[] = [{ |
1294 | seriesHover: [] | 1291 | seriesHover: [] |
1295 | }]; | 1292 | }]; |
1296 | - if (this.settings.comparisonEnabled) { | 1293 | + if (this.comparisonEnabled) { |
1297 | results.push({ | 1294 | results.push({ |
1298 | seriesHover: [] | 1295 | seriesHover: [] |
1299 | }); | 1296 | }); |
@@ -857,6 +857,9 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI | @@ -857,6 +857,9 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI | ||
857 | onInitialPageDataChanged: (subscription, nextPageData) => { | 857 | onInitialPageDataChanged: (subscription, nextPageData) => { |
858 | this.reInit(); | 858 | this.reInit(); |
859 | }, | 859 | }, |
860 | + forceReInit: () => { | ||
861 | + this.reInit(); | ||
862 | + }, | ||
860 | dataLoading: (subscription) => { | 863 | dataLoading: (subscription) => { |
861 | if (this.loadingData !== subscription.loadingData) { | 864 | if (this.loadingData !== subscription.loadingData) { |
862 | this.loadingData = subscription.loadingData; | 865 | this.loadingData = subscription.loadingData; |
@@ -28,6 +28,8 @@ export const DAY = 24 * HOUR; | @@ -28,6 +28,8 @@ export const DAY = 24 * HOUR; | ||
28 | export const WEEK = 7 * DAY; | 28 | export const WEEK = 7 * DAY; |
29 | export const YEAR = DAY * 365; | 29 | export const YEAR = DAY * 365; |
30 | 30 | ||
31 | +export type ComparisonDuration = moment_.unitOfTime.DurationConstructor | 'previousInterval'; | ||
32 | + | ||
31 | export enum TimewindowType { | 33 | export enum TimewindowType { |
32 | REALTIME, | 34 | REALTIME, |
33 | HISTORY | 35 | HISTORY |
@@ -118,7 +120,7 @@ export interface SubscriptionTimewindow { | @@ -118,7 +120,7 @@ export interface SubscriptionTimewindow { | ||
118 | realtimeWindowMs?: number; | 120 | realtimeWindowMs?: number; |
119 | fixedWindow?: FixedWindow; | 121 | fixedWindow?: FixedWindow; |
120 | aggregation?: SubscriptionAggregation; | 122 | aggregation?: SubscriptionAggregation; |
121 | - timeForComparison?: moment_.unitOfTime.DurationConstructor; | 123 | + timeForComparison?: ComparisonDuration; |
122 | } | 124 | } |
123 | 125 | ||
124 | export interface WidgetTimewindow { | 126 | export interface WidgetTimewindow { |
@@ -319,6 +321,15 @@ export function toHistoryTimewindow(timewindow: Timewindow, startTimeMs: number, | @@ -319,6 +321,15 @@ export function toHistoryTimewindow(timewindow: Timewindow, startTimeMs: number, | ||
319 | return historyTimewindow; | 321 | return historyTimewindow; |
320 | } | 322 | } |
321 | 323 | ||
324 | +export function timewindowTypeChanged(newTimewindow: Timewindow, oldTimewindow: Timewindow): boolean { | ||
325 | + if (!newTimewindow || !oldTimewindow) { | ||
326 | + return false; | ||
327 | + } | ||
328 | + const newType = getTimewindowType(newTimewindow); | ||
329 | + const oldType = getTimewindowType(oldTimewindow); | ||
330 | + return newType !== oldType; | ||
331 | +} | ||
332 | + | ||
322 | export function calculateTsOffset(timezone?: string): number { | 333 | export function calculateTsOffset(timezone?: string): number { |
323 | if (timezone) { | 334 | if (timezone) { |
324 | const tz = getTimezone(timezone); | 335 | const tz = getTimezone(timezone); |
@@ -555,8 +566,78 @@ export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number { | @@ -555,8 +566,78 @@ export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number { | ||
555 | } | 566 | } |
556 | } | 567 | } |
557 | 568 | ||
569 | +export function calculateIntervalComparisonStartTime(interval: QuickTimeInterval, | ||
570 | + currentDate: moment_.Moment): number { | ||
571 | + switch (interval) { | ||
572 | + case QuickTimeInterval.YESTERDAY: | ||
573 | + case QuickTimeInterval.DAY_BEFORE_YESTERDAY: | ||
574 | + case QuickTimeInterval.CURRENT_DAY: | ||
575 | + case QuickTimeInterval.CURRENT_DAY_SO_FAR: | ||
576 | + currentDate.subtract(1, 'days'); | ||
577 | + return currentDate.startOf('day').valueOf(); | ||
578 | + case QuickTimeInterval.THIS_DAY_LAST_WEEK: | ||
579 | + currentDate.subtract(1, 'weeks'); | ||
580 | + return currentDate.startOf('day').valueOf(); | ||
581 | + case QuickTimeInterval.PREVIOUS_WEEK: | ||
582 | + case QuickTimeInterval.CURRENT_WEEK: | ||
583 | + case QuickTimeInterval.CURRENT_WEEK_SO_FAR: | ||
584 | + currentDate.subtract(1, 'weeks'); | ||
585 | + return currentDate.startOf('week').valueOf(); | ||
586 | + case QuickTimeInterval.PREVIOUS_MONTH: | ||
587 | + case QuickTimeInterval.CURRENT_MONTH: | ||
588 | + case QuickTimeInterval.CURRENT_MONTH_SO_FAR: | ||
589 | + currentDate.subtract(1, 'months'); | ||
590 | + return currentDate.startOf('month').valueOf(); | ||
591 | + case QuickTimeInterval.PREVIOUS_YEAR: | ||
592 | + case QuickTimeInterval.CURRENT_YEAR: | ||
593 | + case QuickTimeInterval.CURRENT_YEAR_SO_FAR: | ||
594 | + currentDate.subtract(1, 'years'); | ||
595 | + return currentDate.startOf('year').valueOf(); | ||
596 | + case QuickTimeInterval.CURRENT_HOUR: | ||
597 | + currentDate.subtract(1, 'hour'); | ||
598 | + return currentDate.startOf('hour').valueOf(); | ||
599 | + } | ||
600 | +} | ||
601 | + | ||
602 | +export function calculateIntervalComparisonEndTime(interval: QuickTimeInterval, | ||
603 | + currentDate: moment_.Moment): number { | ||
604 | + switch (interval) { | ||
605 | + case QuickTimeInterval.YESTERDAY: | ||
606 | + case QuickTimeInterval.DAY_BEFORE_YESTERDAY: | ||
607 | + case QuickTimeInterval.CURRENT_DAY: | ||
608 | + currentDate.subtract(1, 'days'); | ||
609 | + return currentDate.endOf('day').valueOf(); | ||
610 | + case QuickTimeInterval.CURRENT_DAY_SO_FAR: | ||
611 | + return currentDate.subtract(1, 'days').valueOf(); | ||
612 | + case QuickTimeInterval.THIS_DAY_LAST_WEEK: | ||
613 | + currentDate.subtract(1, 'weeks'); | ||
614 | + return currentDate.endOf('day').valueOf(); | ||
615 | + case QuickTimeInterval.PREVIOUS_WEEK: | ||
616 | + case QuickTimeInterval.CURRENT_WEEK: | ||
617 | + currentDate.subtract(1, 'weeks'); | ||
618 | + return currentDate.endOf('week').valueOf(); | ||
619 | + case QuickTimeInterval.CURRENT_WEEK_SO_FAR: | ||
620 | + return currentDate.subtract(1, 'week').valueOf(); | ||
621 | + case QuickTimeInterval.PREVIOUS_MONTH: | ||
622 | + case QuickTimeInterval.CURRENT_MONTH: | ||
623 | + currentDate.subtract(1, 'months'); | ||
624 | + return currentDate.endOf('month').valueOf(); | ||
625 | + case QuickTimeInterval.CURRENT_MONTH_SO_FAR: | ||
626 | + return currentDate.subtract(1, 'month').valueOf(); | ||
627 | + case QuickTimeInterval.PREVIOUS_YEAR: | ||
628 | + case QuickTimeInterval.CURRENT_YEAR: | ||
629 | + currentDate.subtract(1, 'years'); | ||
630 | + return currentDate.endOf('year').valueOf(); | ||
631 | + case QuickTimeInterval.CURRENT_YEAR_SO_FAR: | ||
632 | + return currentDate.subtract(1, 'year').valueOf(); | ||
633 | + case QuickTimeInterval.CURRENT_HOUR: | ||
634 | + currentDate.subtract(1, 'hour'); | ||
635 | + return currentDate.endOf('hour').valueOf(); | ||
636 | + } | ||
637 | +} | ||
638 | + | ||
558 | export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow, | 639 | export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow, |
559 | - timeUnit: moment_.unitOfTime.DurationConstructor): SubscriptionTimewindow { | 640 | + timeUnit: ComparisonDuration): SubscriptionTimewindow { |
560 | const timewindowForComparison: SubscriptionTimewindow = { | 641 | const timewindowForComparison: SubscriptionTimewindow = { |
561 | fixedWindow: null, | 642 | fixedWindow: null, |
562 | realtimeWindowMs: null, | 643 | realtimeWindowMs: null, |
@@ -564,18 +645,30 @@ export function createTimewindowForComparison(subscriptionTimewindow: Subscripti | @@ -564,18 +645,30 @@ export function createTimewindowForComparison(subscriptionTimewindow: Subscripti | ||
564 | tsOffset: subscriptionTimewindow.tsOffset | 645 | tsOffset: subscriptionTimewindow.tsOffset |
565 | }; | 646 | }; |
566 | 647 | ||
567 | - if (subscriptionTimewindow.realtimeWindowMs) { | ||
568 | - if (subscriptionTimewindow.quickInterval) { | ||
569 | - timewindowForComparison.quickInterval = subscriptionTimewindow.quickInterval; | ||
570 | - timewindowForComparison.timeForComparison = timeUnit; | 648 | + if (subscriptionTimewindow.fixedWindow) { |
649 | + let startTimeMs; | ||
650 | + let endTimeMs; | ||
651 | + if (timeUnit === 'previousInterval') { | ||
652 | + if (subscriptionTimewindow.quickInterval) { | ||
653 | + const startDate = moment(subscriptionTimewindow.fixedWindow.startTimeMs); | ||
654 | + const endDate = moment(subscriptionTimewindow.fixedWindow.endTimeMs); | ||
655 | + if (subscriptionTimewindow.timezone) { | ||
656 | + startDate.tz(subscriptionTimewindow.timezone); | ||
657 | + endDate.tz(subscriptionTimewindow.timezone); | ||
658 | + } | ||
659 | + startTimeMs = calculateIntervalComparisonStartTime(subscriptionTimewindow.quickInterval, startDate); | ||
660 | + endTimeMs = calculateIntervalComparisonEndTime(subscriptionTimewindow.quickInterval, endDate); | ||
661 | + } else { | ||
662 | + const timeInterval = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs; | ||
663 | + endTimeMs = subscriptionTimewindow.fixedWindow.startTimeMs; | ||
664 | + startTimeMs = endTimeMs - timeInterval; | ||
665 | + } | ||
666 | + } else { | ||
667 | + const timeInterval = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs; | ||
668 | + endTimeMs = moment(subscriptionTimewindow.fixedWindow.endTimeMs).subtract(1, timeUnit).valueOf(); | ||
669 | + startTimeMs = endTimeMs - timeInterval; | ||
571 | } | 670 | } |
572 | - timewindowForComparison.startTs = moment(subscriptionTimewindow.startTs).subtract(1, timeUnit).valueOf(); | ||
573 | - timewindowForComparison.realtimeWindowMs = subscriptionTimewindow.realtimeWindowMs; | ||
574 | - } else if (subscriptionTimewindow.fixedWindow) { | ||
575 | - const timeInterval = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs; | ||
576 | - const endTimeMs = moment(subscriptionTimewindow.fixedWindow.endTimeMs).subtract(1, timeUnit).valueOf(); | ||
577 | - | ||
578 | - timewindowForComparison.startTs = endTimeMs - timeInterval; | 671 | + timewindowForComparison.startTs = startTimeMs; |
579 | timewindowForComparison.fixedWindow = { | 672 | timewindowForComparison.fixedWindow = { |
580 | startTimeMs: timewindowForComparison.startTs, | 673 | startTimeMs: timewindowForComparison.startTs, |
581 | endTimeMs | 674 | endTimeMs |
@@ -1798,6 +1798,7 @@ | @@ -1798,6 +1798,7 @@ | ||
1798 | "avg": "avg", | 1798 | "avg": "avg", |
1799 | "total": "total", | 1799 | "total": "total", |
1800 | "comparison-time-ago": { | 1800 | "comparison-time-ago": { |
1801 | + "previousInterval": "(previous interval)", | ||
1801 | "days": "(day ago)", | 1802 | "days": "(day ago)", |
1802 | "weeks": "(week ago)", | 1803 | "weeks": "(week ago)", |
1803 | "months": "(month ago)", | 1804 | "months": "(month ago)", |