Browse Source

Merge branch 'vvlladd28-improvement/comparison-flot'

pull/4275/head
Igor Kulikov 6 years ago
parent
commit
b5444e6c27
  1. 49
      ui-ngx/src/app/core/api/data-aggregator.ts
  2. 8
      ui-ngx/src/app/core/api/entity-data-subscription.ts
  3. 1
      ui-ngx/src/app/core/api/entity-data.service.ts
  4. 2
      ui-ngx/src/app/core/api/widget-api.models.ts
  5. 70
      ui-ngx/src/app/core/api/widget-subscription.ts
  6. 11
      ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts
  7. 61
      ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts
  8. 3
      ui-ngx/src/app/modules/home/components/widget/widget.component.ts
  9. 150
      ui-ngx/src/app/shared/models/time/time.models.ts
  10. 1
      ui-ngx/src/assets/locale/locale.constant-en_US.json

49
ui-ngx/src/app/core/api/data-aggregator.ts

@ -16,14 +16,17 @@
import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models'; import { SubscriptionData, SubscriptionDataHolder } from '@app/shared/models/telemetry/telemetry.models';
import { import {
AggregationType, AggregationType, calculateIntervalComparisonEndTime,
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';
import Timeout = NodeJS.Timeout; import Timeout = NodeJS.Timeout;
import * as moment_ from 'moment';
export declare type onAggregatedData = (data: SubscriptionData, detectChanges: boolean) => void; export declare type onAggregatedData = (data: SubscriptionData, detectChanges: boolean) => void;
@ -85,7 +88,7 @@ export class DataAggregator {
private intervalTimeoutHandle: Timeout; private intervalTimeoutHandle: Timeout;
private intervalScheduledTime: number; private intervalScheduledTime: number;
private startTs = this.subsTw.startTs + this.subsTw.tsOffset; private startTs: number;
private endTs: number; private endTs: number;
private elapsed: number; private elapsed: number;
@ -137,12 +140,7 @@ export class DataAggregator {
} }
this.subsTw = subsTw; this.subsTw = subsTw;
this.intervalScheduledTime = this.utils.currentPerfTime(); this.intervalScheduledTime = this.utils.currentPerfTime();
this.startTs = this.subsTw.startTs + this.subsTw.tsOffset; this.calculateStartEndTs();
if (this.subsTw.quickInterval) {
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, null, this.subsTw.timezone) + this.subsTw.tsOffset;
} else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
}
this.elapsed = 0; this.elapsed = 0;
this.aggregationTimeout = Math.max(this.subsTw.aggregation.interval, 1000); this.aggregationTimeout = Math.max(this.subsTw.aggregation.interval, 1000);
this.resetPending = true; this.resetPending = true;
@ -165,11 +163,7 @@ export class DataAggregator {
if (!this.dataReceived) { if (!this.dataReceived) {
this.elapsed = 0; this.elapsed = 0;
this.dataReceived = true; this.dataReceived = true;
if (this.subsTw.quickInterval) { this.calculateStartEndTs();
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, null, this.subsTw.timezone) + this.subsTw.tsOffset;
} else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
}
} }
if (this.resetPending) { if (this.resetPending) {
this.resetPending = false; this.resetPending = false;
@ -194,6 +188,21 @@ export class DataAggregator {
} }
} }
private calculateStartEndTs() {
this.startTs = this.subsTw.startTs + this.subsTw.tsOffset;
if (this.subsTw.quickInterval) {
if (this.subsTw.timeForComparison === 'previousInterval') {
const currentDate = getCurrentTime(this.subsTw.timezone);
this.endTs = calculateIntervalComparisonEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
} else {
const currentDate = this.getCurrentTime();
this.endTs = calculateIntervalEndTime(this.subsTw.quickInterval, currentDate) + this.subsTw.tsOffset;
}
} else {
this.endTs = this.startTs + this.subsTw.aggregation.timeWindow;
}
}
private onInterval(history?: boolean, detectChanges?: boolean) { private onInterval(history?: boolean, detectChanges?: boolean) {
const now = this.utils.currentPerfTime(); const now = this.utils.currentPerfTime();
this.elapsed += now - this.intervalScheduledTime; this.elapsed += now - this.intervalScheduledTime;
@ -207,7 +216,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 +365,13 @@ export class DataAggregator {
} }
} }
private getCurrentTime() {
if (this.subsTw.timeForComparison) {
return getCurrentTimeForComparison(this.subsTw.timeForComparison as moment_.unitOfTime.DurationConstructor, this.subsTw.timezone);
} else {
return getCurrentTime(this.subsTw.timezone);
}
}
} }

8
ui-ngx/src/app/core/api/entity-data-subscription.ts

@ -419,8 +419,8 @@ export class EntityDataSubscription {
latestTsOffsetChanged = this.subscriber.setTsOffset(this.latestTsOffset); latestTsOffsetChanged = this.subscriber.setTsOffset(this.latestTsOffset);
} }
if (latestTsOffsetChanged) { if (latestTsOffsetChanged) {
if (this.listener.initialPageDataChanged) { if (this.listener.forceReInit) {
this.listener.initialPageDataChanged(this.pageData); this.listener.forceReInit();
} }
} else if (!this.subsCommand.isEmpty()) { } else if (!this.subsCommand.isEmpty()) {
this.subscriber.subscriptionCommands = [this.subsCommand]; this.subscriber.subscriptionCommands = [this.subsCommand];
@ -428,8 +428,8 @@ export class EntityDataSubscription {
} }
} else if (this.datasourceType === DatasourceType.entityCount) { } else if (this.datasourceType === DatasourceType.entityCount) {
if (this.subscriber.setTsOffset(this.latestTsOffset)) { if (this.subscriber.setTsOffset(this.latestTsOffset)) {
if (this.listener.initialPageDataChanged) { if (this.listener.forceReInit) {
this.listener.initialPageDataChanged(this.pageData); this.listener.forceReInit();
} }
} }
} else if (this.datasourceType === DatasourceType.function) { } else if (this.datasourceType === DatasourceType.function) {

1
ui-ngx/src/app/core/api/entity-data.service.ts

@ -40,6 +40,7 @@ export interface EntityDataListener {
datasourceIndex: number, pageLink: EntityDataPageLink) => void; datasourceIndex: number, pageLink: EntityDataPageLink) => void;
dataUpdated: (data: DataSetHolder, datasourceIndex: number, dataIndex: number, dataKeyIndex: number, detectChanges: boolean) => void; dataUpdated: (data: DataSetHolder, datasourceIndex: number, dataIndex: number, dataKeyIndex: number, detectChanges: boolean) => void;
initialPageDataChanged?: (nextPageData: PageData<EntityData>) => void; initialPageDataChanged?: (nextPageData: PageData<EntityData>) => void;
forceReInit?: () => void;
updateRealtimeSubscription?: () => SubscriptionTimewindow; updateRealtimeSubscription?: () => SubscriptionTimewindow;
setRealtimeSubscription?: (subscriptionTimewindow: SubscriptionTimewindow) => void; setRealtimeSubscription?: (subscriptionTimewindow: SubscriptionTimewindow) => void;
subscriptionOptions?: EntityDataSubscriptionOptions; subscriptionOptions?: EntityDataSubscriptionOptions;

2
ui-ngx/src/app/core/api/widget-api.models.ts

@ -209,6 +209,7 @@ export interface WidgetSubscriptionCallbacks {
onDataUpdateError?: (subscription: IWidgetSubscription, e: any) => void; onDataUpdateError?: (subscription: IWidgetSubscription, e: any) => void;
onSubscriptionMessage?: (subscription: IWidgetSubscription, message: SubscriptionMessage) => void; onSubscriptionMessage?: (subscription: IWidgetSubscription, message: SubscriptionMessage) => void;
onInitialPageDataChanged?: (subscription: IWidgetSubscription, nextPageData: PageData<EntityData>) => void; onInitialPageDataChanged?: (subscription: IWidgetSubscription, nextPageData: PageData<EntityData>) => void;
forceReInit?: () => void;
dataLoading?: (subscription: IWidgetSubscription) => void; dataLoading?: (subscription: IWidgetSubscription) => void;
legendDataUpdated?: (subscription: IWidgetSubscription, detectChanges: boolean) => void; legendDataUpdated?: (subscription: IWidgetSubscription, detectChanges: boolean) => void;
timeWindowUpdated?: (subscription: IWidgetSubscription, timeWindowConfig: Timewindow) => void; timeWindowUpdated?: (subscription: IWidgetSubscription, timeWindowConfig: Timewindow) => void;
@ -269,6 +270,7 @@ export interface IWidgetSubscription {
hiddenData?: Array<{data: DataSet}>; hiddenData?: Array<{data: DataSet}>;
timeWindowConfig?: Timewindow; timeWindowConfig?: Timewindow;
timeWindow?: WidgetTimewindow; timeWindow?: WidgetTimewindow;
comparisonEnabled?: boolean;
comparisonTimeWindow?: WidgetTimewindow; comparisonTimeWindow?: WidgetTimewindow;
alarms?: PageData<AlarmData>; alarms?: PageData<AlarmData>;

70
ui-ngx/src/app/core/api/widget-subscription.ts

@ -39,12 +39,12 @@ import { HttpErrorResponse } from '@angular/common/http';
import { import {
calculateIntervalEndTime, calculateIntervalEndTime,
calculateIntervalStartTime, calculateIntervalStartTime,
calculateTsOffset, calculateTsOffset, ComparisonDuration,
createSubscriptionTimewindow, createSubscriptionTimewindow,
createTimewindowForComparison, createTimewindowForComparison,
getCurrentTime, getCurrentTime, isHistoryTypeTimewindow,
SubscriptionTimewindow, SubscriptionTimewindow,
Timewindow, Timewindow, timewindowTypeChanged,
toHistoryTimewindow, toHistoryTimewindow,
WidgetTimewindow WidgetTimewindow
} from '@app/shared/models/time/time.models'; } from '@app/shared/models/time/time.models';
@ -107,7 +107,7 @@ export class WidgetSubscription implements IWidgetSubscription {
decimals: number; decimals: number;
units: string; units: string;
comparisonEnabled: boolean; comparisonEnabled: boolean;
timeForComparison: moment_.unitOfTime.DurationConstructor; timeForComparison: ComparisonDuration;
comparisonTimeWindow: WidgetTimewindow; comparisonTimeWindow: WidgetTimewindow;
timewindowForComparison: SubscriptionTimewindow; timewindowForComparison: SubscriptionTimewindow;
@ -198,6 +198,7 @@ export class WidgetSubscription implements IWidgetSubscription {
this.callbacks.onDataUpdateError = this.callbacks.onDataUpdateError || (() => {}); this.callbacks.onDataUpdateError = this.callbacks.onDataUpdateError || (() => {});
this.callbacks.onSubscriptionMessage = this.callbacks.onSubscriptionMessage || (() => {}); this.callbacks.onSubscriptionMessage = this.callbacks.onSubscriptionMessage || (() => {});
this.callbacks.onInitialPageDataChanged = this.callbacks.onInitialPageDataChanged || (() => {}); this.callbacks.onInitialPageDataChanged = this.callbacks.onInitialPageDataChanged || (() => {});
this.callbacks.forceReInit = this.callbacks.forceReInit || (() => {});
this.callbacks.dataLoading = this.callbacks.dataLoading || (() => {}); this.callbacks.dataLoading = this.callbacks.dataLoading || (() => {});
this.callbacks.legendDataUpdated = this.callbacks.legendDataUpdated || (() => {}); this.callbacks.legendDataUpdated = this.callbacks.legendDataUpdated || (() => {});
this.callbacks.timeWindowUpdated = this.callbacks.timeWindowUpdated || (() => {}); this.callbacks.timeWindowUpdated = this.callbacks.timeWindowUpdated || (() => {});
@ -228,7 +229,7 @@ export class WidgetSubscription implements IWidgetSubscription {
} }
this.subscriptionTimewindow = null; this.subscriptionTimewindow = null;
this.comparisonEnabled = options.comparisonEnabled; this.comparisonEnabled = options.comparisonEnabled && isHistoryTypeTimewindow(this.timeWindowConfig);
if (this.comparisonEnabled) { if (this.comparisonEnabled) {
this.timeForComparison = options.timeForComparison; this.timeForComparison = options.timeForComparison;
@ -418,20 +419,13 @@ export class WidgetSubscription implements IWidgetSubscription {
this.dataLoaded(pageData, data1, datasourceIndex, pageLink, true); this.dataLoaded(pageData, data1, datasourceIndex, pageLink, true);
}, },
initialPageDataChanged: this.initialPageDataChanged.bind(this), initialPageDataChanged: this.initialPageDataChanged.bind(this),
forceReInit: this.forceReInit.bind(this),
dataUpdated: this.dataUpdated.bind(this), dataUpdated: this.dataUpdated.bind(this),
updateRealtimeSubscription: () => { updateRealtimeSubscription: () => {
if (this.comparisonEnabled && datasource.isAdditional) { return this.updateRealtimeSubscription();
return this.updateSubscriptionForComparison();
} else {
return this.updateRealtimeSubscription();
}
}, },
setRealtimeSubscription: (subscriptionTimewindow) => { setRealtimeSubscription: (subscriptionTimewindow) => {
if (this.comparisonEnabled && datasource.isAdditional) { this.updateRealtimeSubscription(deepClone(subscriptionTimewindow));
this.updateSubscriptionForComparison(subscriptionTimewindow);
} else {
this.updateRealtimeSubscription(deepClone(subscriptionTimewindow));
}
} }
}; };
this.entityDataListeners.push(listener); this.entityDataListeners.push(listener);
@ -584,8 +578,9 @@ export class WidgetSubscription implements IWidgetSubscription {
if (this.type === widgetType.timeseries || this.type === widgetType.alarm) { if (this.type === widgetType.timeseries || this.type === widgetType.alarm) {
if (this.useDashboardTimewindow) { if (this.useDashboardTimewindow) {
if (!isEqual(this.timeWindowConfig, newDashboardTimewindow) && newDashboardTimewindow) { if (!isEqual(this.timeWindowConfig, newDashboardTimewindow) && newDashboardTimewindow) {
const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, newDashboardTimewindow);
this.timeWindowConfig = deepClone(newDashboardTimewindow); this.timeWindowConfig = deepClone(newDashboardTimewindow);
this.update(); this.update(isTimewindowTypeChanged);
} }
} }
} else if (this.type === widgetType.latest) { } else if (this.type === widgetType.latest) {
@ -614,8 +609,9 @@ export class WidgetSubscription implements IWidgetSubscription {
updateTimewindowConfig(newTimewindow: Timewindow): void { updateTimewindowConfig(newTimewindow: Timewindow): void {
if (!this.useDashboardTimewindow) { if (!this.useDashboardTimewindow) {
const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, newTimewindow);
this.timeWindowConfig = newTimewindow; this.timeWindowConfig = newTimewindow;
this.update(); this.update(isTimewindowTypeChanged);
} }
} }
@ -624,10 +620,11 @@ export class WidgetSubscription implements IWidgetSubscription {
this.ctx.dashboardTimewindowApi.onResetTimewindow(); this.ctx.dashboardTimewindowApi.onResetTimewindow();
} else { } else {
if (this.originalTimewindow) { if (this.originalTimewindow) {
const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, this.originalTimewindow);
this.timeWindowConfig = deepClone(this.originalTimewindow); this.timeWindowConfig = deepClone(this.originalTimewindow);
this.originalTimewindow = null; this.originalTimewindow = null;
this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); this.callbacks.timeWindowUpdated(this, this.timeWindowConfig);
this.update(); this.update(isTimewindowTypeChanged);
} }
} }
} }
@ -641,7 +638,8 @@ export class WidgetSubscription implements IWidgetSubscription {
} }
this.timeWindowConfig = toHistoryTimewindow(this.timeWindowConfig, startTimeMs, endTimeMs, interval, this.ctx.timeService); this.timeWindowConfig = toHistoryTimewindow(this.timeWindowConfig, startTimeMs, endTimeMs, interval, this.ctx.timeService);
this.callbacks.timeWindowUpdated(this, this.timeWindowConfig); this.callbacks.timeWindowUpdated(this, this.timeWindowConfig);
this.update(); const isTimewindowTypeChanged = timewindowTypeChanged(this.timeWindowConfig, this.originalTimewindow);
this.update(isTimewindowTypeChanged);
} }
} }
@ -770,16 +768,20 @@ export class WidgetSubscription implements IWidgetSubscription {
} }
} }
update() { update(isTimewindowTypeChanged = false) {
if (this.type !== widgetType.rpc) { if (this.type !== widgetType.rpc) {
if (this.type === widgetType.alarm) { if (this.type === widgetType.alarm) {
this.updateAlarmDataSubscription(); this.updateAlarmDataSubscription();
} else { } else {
if (this.hasDataPageLink) { if (this.type === widgetType.timeseries && this.options.comparisonEnabled && isTimewindowTypeChanged) {
this.updateDataSubscriptions(); this.forceReInit();
} else { } else {
this.notifyDataLoading(); if (this.hasDataPageLink) {
this.dataSubscribe(); this.updateDataSubscriptions();
} else {
this.notifyDataLoading();
this.dataSubscribe();
}
} }
} }
} }
@ -1143,24 +1145,14 @@ export class WidgetSubscription implements IWidgetSubscription {
private updateComparisonTimewindow() { private updateComparisonTimewindow() {
this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000; this.comparisonTimeWindow.interval = this.timewindowForComparison.aggregation.interval || 1000;
this.comparisonTimeWindow.timezone = this.timewindowForComparison.timezone; this.comparisonTimeWindow.timezone = this.timewindowForComparison.timezone;
if (this.timewindowForComparison.realtimeWindowMs) { if (this.timewindowForComparison.fixedWindow) {
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.maxTime = this.timewindowForComparison.fixedWindow.endTimeMs + this.timewindowForComparison.tsOffset;
this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs + this.timewindowForComparison.tsOffset; this.comparisonTimeWindow.minTime = this.timewindowForComparison.fixedWindow.startTimeMs + this.timewindowForComparison.tsOffset;
} }
} }
private updateSubscriptionForComparison(subscriptionTimewindow?: SubscriptionTimewindow): SubscriptionTimewindow { private updateSubscriptionForComparison(): SubscriptionTimewindow {
if (subscriptionTimewindow) { this.timewindowForComparison = createTimewindowForComparison(this.subscriptionTimewindow, this.timeForComparison);
this.timewindowForComparison = subscriptionTimewindow;
} else {
if (!this.subscriptionTimewindow) {
this.subscriptionTimewindow = this.updateRealtimeSubscription();
}
this.timewindowForComparison = createTimewindowForComparison(this.subscriptionTimewindow, this.timeForComparison);
}
this.updateComparisonTimewindow(); this.updateComparisonTimewindow();
return this.timewindowForComparison; return this.timewindowForComparison;
} }
@ -1169,6 +1161,10 @@ export class WidgetSubscription implements IWidgetSubscription {
this.callbacks.onInitialPageDataChanged(this, nextPageData); this.callbacks.onInitialPageDataChanged(this, nextPageData);
} }
private forceReInit() {
this.callbacks.forceReInit();
}
private dataLoaded(pageData: PageData<EntityData>, private dataLoaded(pageData: PageData<EntityData>,
data: Array<Array<DataSetHolder>>, data: Array<Array<DataSetHolder>>,
datasourceIndex: number, pageLink: EntityDataPageLink, isUpdate: boolean) { datasourceIndex: number, pageLink: EntityDataPageLink, isUpdate: boolean) {

11
ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.models.ts

@ -20,6 +20,7 @@
import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models'; import { DataKey, Datasource, DatasourceData, JsonSettingsSchema } from '@shared/models/widget.models';
import * as moment_ from 'moment'; import * as moment_ from 'moment';
import { DataKeyType } from "@shared/models/telemetry/telemetry.models"; import { DataKeyType } from "@shared/models/telemetry/telemetry.models";
import { ComparisonDuration } from '@shared/models/time/time.models';
export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph'; export declare type ChartType = 'line' | 'pie' | 'bar' | 'state' | 'graph';
@ -142,7 +143,7 @@ export interface TbFlotBaseSettings {
export interface TbFlotComparisonSettings { export interface TbFlotComparisonSettings {
comparisonEnabled: boolean; comparisonEnabled: boolean;
timeForComparison: moment_.unitOfTime.DurationConstructor; timeForComparison: ComparisonDuration;
xaxisSecond: TbFlotSecondXAxisSettings; xaxisSecond: TbFlotSecondXAxisSettings;
} }
@ -543,7 +544,7 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = {
timeForComparison: { timeForComparison: {
title: 'Time to show historical data', title: 'Time to show historical data',
type: 'string', type: 'string',
default: 'months' default: 'previousInterval'
}, },
xaxisSecond: { xaxisSecond: {
title: 'Second X axis', title: 'Second X axis',
@ -576,6 +577,10 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = {
type: 'rc-select', type: 'rc-select',
multiple: false, multiple: false,
items: [ items: [
{
value: 'previousInterval',
label: 'Previous interval (default)'
},
{ {
value: 'days', value: 'days',
label: 'Day ago' label: 'Day ago'
@ -586,7 +591,7 @@ const chartSettingsSchemaForComparison: JsonSettingsSchema = {
}, },
{ {
value: 'months', value: 'months',
label: 'Month ago (default)' label: 'Month ago'
}, },
{ {
value: 'years', value: 'years',

61
ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts

@ -74,6 +74,7 @@ export class TbFlot {
private readonly utils: UtilsService; private readonly utils: UtilsService;
private settings: TbFlotSettings; private settings: TbFlotSettings;
private comparisonEnabled: boolean;
private readonly tooltip: JQuery<any>; private readonly tooltip: JQuery<any>;
@ -263,29 +264,7 @@ export class TbFlot {
}; };
} }
if (this.settings.comparisonEnabled) { this.options.series = {};
const xaxis = deepClone(this.xaxis);
xaxis.position = 'top';
if (this.settings.xaxisSecond) {
if (this.settings.xaxisSecond.showLabels === false) {
xaxis.tickFormatter = () => {
return '';
};
}
xaxis.label = this.utils.customTranslation(this.settings.xaxisSecond.title, this.settings.xaxisSecond.title) || null;
xaxis.position = this.settings.xaxisSecond.axisPosition;
}
xaxis.tickLength = 0;
this.options.xaxes.push(xaxis);
this.options.series = {
stack: false
};
} else {
this.options.series = {
stack: this.settings.stack === true
};
}
this.options.crosshair = { this.options.crosshair = {
mode: 'x' mode: 'x'
@ -364,7 +343,6 @@ export class TbFlot {
// Experimental // Experimental
this.animatedPie = this.settings.animatedPie === true; this.animatedPie = this.settings.animatedPie === true;
} }
if (this.ctx.defaultSubscription) { if (this.ctx.defaultSubscription) {
@ -372,10 +350,29 @@ export class TbFlot {
} }
} }
private init($element: JQuery<any>, subscription: IWidgetSubscription) { private init($element: JQuery<any>, subscription: IWidgetSubscription) {
this.subscription = subscription;
this.$element = $element; this.$element = $element;
this.subscription = subscription;
this.comparisonEnabled = this.subscription ? this.subscription.comparisonEnabled : this.settings.comparisonEnabled;
if (this.comparisonEnabled) {
const xaxis = deepClone(this.xaxis);
xaxis.position = 'top';
if (this.settings.xaxisSecond) {
if (this.settings.xaxisSecond.showLabels === false) {
xaxis.tickFormatter = () => {
return '';
};
}
xaxis.label = this.utils.customTranslation(this.settings.xaxisSecond.title, this.settings.xaxisSecond.title) || null;
xaxis.position = this.settings.xaxisSecond.axisPosition;
}
xaxis.tickLength = 0;
this.options.xaxes.push(xaxis);
this.options.series.stack = false;
} else {
this.options.series.stack = this.settings.stack === true;
}
const colors: string[] = []; const colors: string[] = [];
this.yaxes = []; this.yaxes = [];
const yaxesMap: {[units: string]: TbFlotAxisOptions} = {}; const yaxesMap: {[units: string]: TbFlotAxisOptions} = {};
@ -387,7 +384,7 @@ export class TbFlot {
this.settings.dataKeysListForLabels.forEach((item) => { this.settings.dataKeysListForLabels.forEach((item) => {
item.settings = {}; item.settings = {};
}); });
subscription.datasources.forEach((item) => { this.subscription.datasources.forEach((item) => {
const datasource: Datasource = { const datasource: Datasource = {
type: item.type, type: item.type,
entityType: item.entityType, entityType: item.entityType,
@ -425,7 +422,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 +554,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 +633,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 +651,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 +1290,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: []
}); });

3
ui-ngx/src/app/modules/home/components/widget/widget.component.ts

@ -857,6 +857,9 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
onInitialPageDataChanged: (subscription, nextPageData) => { onInitialPageDataChanged: (subscription, nextPageData) => {
this.reInit(); this.reInit();
}, },
forceReInit: () => {
this.reInit();
},
dataLoading: (subscription) => { dataLoading: (subscription) => {
if (this.loadingData !== subscription.loadingData) { if (this.loadingData !== subscription.loadingData) {
this.loadingData = subscription.loadingData; this.loadingData = subscription.loadingData;

150
ui-ngx/src/app/shared/models/time/time.models.ts

@ -28,6 +28,8 @@ export const DAY = 24 * HOUR;
export const WEEK = 7 * DAY; export const WEEK = 7 * DAY;
export const YEAR = DAY * 365; export const YEAR = DAY * 365;
export type ComparisonDuration = moment_.unitOfTime.DurationConstructor | 'previousInterval';
export enum TimewindowType { export enum TimewindowType {
REALTIME, REALTIME,
HISTORY HISTORY
@ -118,6 +120,7 @@ export interface SubscriptionTimewindow {
realtimeWindowMs?: number; realtimeWindowMs?: number;
fixedWindow?: FixedWindow; fixedWindow?: FixedWindow;
aggregation?: SubscriptionAggregation; aggregation?: SubscriptionAggregation;
timeForComparison?: ComparisonDuration;
} }
export interface WidgetTimewindow { export interface WidgetTimewindow {
@ -208,6 +211,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 +226,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;
@ -318,6 +321,15 @@ export function toHistoryTimewindow(timewindow: Timewindow, startTimeMs: number,
return historyTimewindow; return historyTimewindow;
} }
export function timewindowTypeChanged(newTimewindow: Timewindow, oldTimewindow: Timewindow): boolean {
if (!newTimewindow || !oldTimewindow) {
return false;
}
const newType = getTimewindowType(newTimewindow);
const oldType = getTimewindowType(oldTimewindow);
return newType !== oldType;
}
export function calculateTsOffset(timezone?: string): number { export function calculateTsOffset(timezone?: string): number {
if (timezone) { if (timezone) {
const tz = getTimezone(timezone); const tz = getTimezone(timezone);
@ -328,6 +340,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 +368,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)) {
@ -553,22 +566,109 @@ export function quickTimeIntervalPeriod(interval: QuickTimeInterval): number {
} }
} }
export function calculateIntervalComparisonStartTime(interval: QuickTimeInterval,
currentDate: moment_.Moment): number {
switch (interval) {
case QuickTimeInterval.YESTERDAY:
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
case QuickTimeInterval.CURRENT_DAY:
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
currentDate.subtract(1, 'days');
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.startOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
case QuickTimeInterval.CURRENT_WEEK:
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
currentDate.subtract(1, 'weeks');
return currentDate.startOf('week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
case QuickTimeInterval.CURRENT_MONTH:
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
currentDate.subtract(1, 'months');
return currentDate.startOf('month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
case QuickTimeInterval.CURRENT_YEAR:
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
currentDate.subtract(1, 'years');
return currentDate.startOf('year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
currentDate.subtract(1, 'hour');
return currentDate.startOf('hour').valueOf();
}
}
export function calculateIntervalComparisonEndTime(interval: QuickTimeInterval,
currentDate: moment_.Moment): number {
switch (interval) {
case QuickTimeInterval.YESTERDAY:
case QuickTimeInterval.DAY_BEFORE_YESTERDAY:
case QuickTimeInterval.CURRENT_DAY:
currentDate.subtract(1, 'days');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.CURRENT_DAY_SO_FAR:
return currentDate.subtract(1, 'days').valueOf();
case QuickTimeInterval.THIS_DAY_LAST_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('day').valueOf();
case QuickTimeInterval.PREVIOUS_WEEK:
case QuickTimeInterval.CURRENT_WEEK:
currentDate.subtract(1, 'weeks');
return currentDate.endOf('week').valueOf();
case QuickTimeInterval.CURRENT_WEEK_SO_FAR:
return currentDate.subtract(1, 'week').valueOf();
case QuickTimeInterval.PREVIOUS_MONTH:
case QuickTimeInterval.CURRENT_MONTH:
currentDate.subtract(1, 'months');
return currentDate.endOf('month').valueOf();
case QuickTimeInterval.CURRENT_MONTH_SO_FAR:
return currentDate.subtract(1, 'month').valueOf();
case QuickTimeInterval.PREVIOUS_YEAR:
case QuickTimeInterval.CURRENT_YEAR:
currentDate.subtract(1, 'years');
return currentDate.endOf('year').valueOf();
case QuickTimeInterval.CURRENT_YEAR_SO_FAR:
return currentDate.subtract(1, 'year').valueOf();
case QuickTimeInterval.CURRENT_HOUR:
currentDate.subtract(1, 'hour');
return currentDate.endOf('hour').valueOf();
}
}
export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow, export function createTimewindowForComparison(subscriptionTimewindow: SubscriptionTimewindow,
timeUnit: moment_.unitOfTime.DurationConstructor): SubscriptionTimewindow { timeUnit: ComparisonDuration): SubscriptionTimewindow {
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.fixedWindow) {
timewindowForComparison.startTs = moment(subscriptionTimewindow.startTs).subtract(1, timeUnit).valueOf(); let startTimeMs;
timewindowForComparison.realtimeWindowMs = subscriptionTimewindow.realtimeWindowMs; let endTimeMs;
} else if (subscriptionTimewindow.fixedWindow) { if (timeUnit === 'previousInterval') {
const timeInterval = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs; if (subscriptionTimewindow.quickInterval) {
const endTimeMs = moment(subscriptionTimewindow.fixedWindow.endTimeMs).subtract(1, timeUnit).valueOf(); const startDate = moment(subscriptionTimewindow.fixedWindow.startTimeMs);
const endDate = moment(subscriptionTimewindow.fixedWindow.endTimeMs);
timewindowForComparison.startTs = endTimeMs - timeInterval; if (subscriptionTimewindow.timezone) {
startDate.tz(subscriptionTimewindow.timezone);
endDate.tz(subscriptionTimewindow.timezone);
}
startTimeMs = calculateIntervalComparisonStartTime(subscriptionTimewindow.quickInterval, startDate);
endTimeMs = calculateIntervalComparisonEndTime(subscriptionTimewindow.quickInterval, endDate);
} else {
const timeInterval = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
endTimeMs = subscriptionTimewindow.fixedWindow.startTimeMs;
startTimeMs = endTimeMs - timeInterval;
}
} else {
const timeInterval = subscriptionTimewindow.fixedWindow.endTimeMs - subscriptionTimewindow.fixedWindow.startTimeMs;
endTimeMs = moment(subscriptionTimewindow.fixedWindow.endTimeMs).subtract(1, timeUnit).valueOf();
startTimeMs = endTimeMs - timeInterval;
}
timewindowForComparison.startTs = startTimeMs;
timewindowForComparison.fixedWindow = { timewindowForComparison.fixedWindow = {
startTimeMs: timewindowForComparison.startTs, startTimeMs: timewindowForComparison.startTs,
endTimeMs endTimeMs
@ -797,3 +897,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);
}

1
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -1798,6 +1798,7 @@
"avg": "avg", "avg": "avg",
"total": "total", "total": "total",
"comparison-time-ago": { "comparison-time-ago": {
"previousInterval": "(previous interval)",
"days": "(day ago)", "days": "(day ago)",
"weeks": "(week ago)", "weeks": "(week ago)",
"months": "(month ago)", "months": "(month ago)",

Loading…
Cancel
Save