From d2ba3d2d841d085371671b97d9c825f698152d69 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 12 Jan 2024 18:03:40 +0200 Subject: [PATCH] UI: Calculate correct interval length for echarts axis pointer. --- ui-ngx/src/app/core/api/data-aggregator.ts | 6 +-- .../bar-chart-with-labels-widget.component.ts | 4 +- .../widget/lib/chart/echarts-widget.models.ts | 51 ++++++++++++++++--- .../src/app/shared/models/time/time.models.ts | 34 ++++++++----- 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/ui-ngx/src/app/core/api/data-aggregator.ts b/ui-ngx/src/app/core/api/data-aggregator.ts index a16c4baa5b..c11c08ad2b 100644 --- a/ui-ngx/src/app/core/api/data-aggregator.ts +++ b/ui-ngx/src/app/core/api/data-aggregator.ts @@ -19,7 +19,7 @@ import { IndexedSubscriptionData, } from '@app/shared/models/telemetry/telemetry.models'; import { - AggregationType, calculateAggInterval, + AggregationType, calculateAggIntervalWithSubscriptionTimeWindow, calculateIntervalComparisonEndTime, calculateIntervalEndTime, calculateIntervalStartEndTime, @@ -79,7 +79,7 @@ class AggDataMap { } calculateAggInterval(timestamp: number): [number, number] { - return calculateAggInterval(this.subsTw, this.endTs, timestamp); + return calculateAggIntervalWithSubscriptionTimeWindow(this.subsTw, this.endTs, timestamp); } updateLastInterval(endTs: number) { @@ -88,7 +88,7 @@ class AggDataMap { const lastTs = this.map.maxKey(); if (lastTs) { const data = this.map.get(lastTs); - const interval = calculateAggInterval(this.subsTw, endTs, data.ts); + const interval = calculateAggIntervalWithSubscriptionTimeWindow(this.subsTw, endTs, data.ts); data.interval = interval; data.ts = interval[0] + Math.floor((interval[1] - interval[0]) / 2); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.ts index ea8c46880e..57dbf908dd 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.ts @@ -306,7 +306,7 @@ export class BarChartWithLabelsWidgetComponent implements OnInit, OnDestroy, Aft if (this.barChart) { (this.barChartOptions.xAxis as any).min = this.ctx.defaultSubscription.timeWindow.minTime; (this.barChartOptions.xAxis as any).max = this.ctx.defaultSubscription.timeWindow.maxTime; - (this.barChartOptions.xAxis as any).tbTimewindowInterval = this.ctx.defaultSubscription.timeWindow.interval; + (this.barChartOptions.xAxis as any).tbTimeWindow = this.ctx.defaultSubscription.timeWindow; this.barChartOptions.series = this.updateSeries(); this.barChart.setOption(this.barChartOptions); } @@ -417,7 +417,7 @@ export class BarChartWithLabelsWidgetComponent implements OnInit, OnDestroy, Aft } }; - (this.barChartOptions.xAxis as any).tbTimewindowInterval = this.ctx.defaultSubscription.timeWindow.interval; + (this.barChartOptions.xAxis as any).tbTimeWindow = this.ctx.defaultSubscription.timeWindow; this.barChartOptions.series = this.updateSeries(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts index 8bf2254a66..515e47559d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts @@ -37,7 +37,12 @@ import { import { LabelLayout } from 'echarts/features'; import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'; import { DataEntry, DataSet } from '@shared/models/widget.models'; -import { Interval, IntervalMath } from '@shared/models/time/time.models'; +import { + calculateAggIntervalWithWidgetTimeWindow, + Interval, + IntervalMath, + WidgetTimewindow +} from '@shared/models/time/time.models'; import { CallbackDataParams } from 'echarts/types/dist/shared'; import { Renderer2 } from '@angular/core'; import { DateFormatProcessor, DateFormatSettings, Font } from '@shared/models/widget-settings.models'; @@ -52,13 +57,43 @@ class EChartsModule { Axis.prototype.getBandWidth = function(){ const model: AxisModel = this.model; const axisOption = model.option; - const tbTimewindowInterval: Interval = (axisOption as any).tbTimewindowInterval; - if (this.scale.type === 'time' && (isNumber(tbTimewindowInterval) || isString(tbTimewindowInterval))) { - const timeScale: TimeScale = this.scale; - const axisExtent: [number, number] = this._extent; - const dataExtent = timeScale.getExtent(); - const size = Math.abs(axisExtent[1] - axisExtent[0]); - return IntervalMath.numberValue(tbTimewindowInterval) * (size / (dataExtent[1] - dataExtent[0])); + if (this.scale.type === 'time') { + let interval: number; + const seriesDataIndices = axisOption.axisPointer?.seriesDataIndices; + if (seriesDataIndices?.length) { + const seriesDataIndex = seriesDataIndices[0]; + const series = model.ecModel.getSeriesByIndex(seriesDataIndex.seriesIndex); + if (series) { + const values = series.getData().getValues(seriesDataIndex.dataIndex); + const start = values[2]; + const end = values[3]; + if (typeof start === 'number' && typeof end === 'number') { + interval = Math.max(end - start, 1); + } + } + } + if (!interval) { + const tbTimeWindow: WidgetTimewindow = (axisOption as any).tbTimeWindow; + if (isDefinedAndNotNull(tbTimeWindow)) { + if (axisOption.axisPointer?.value && typeof axisOption.axisPointer?.value === 'number') { + const intervalArray = calculateAggIntervalWithWidgetTimeWindow(tbTimeWindow, axisOption.axisPointer.value); + const start = intervalArray[0]; + const end = intervalArray[1]; + interval = Math.max(end - start, 1); + } else { + interval = IntervalMath.numberValue(tbTimeWindow.interval); + } + } + } + if (interval) { + const timeScale: TimeScale = this.scale; + const axisExtent: [number, number] = this._extent; + const dataExtent = timeScale.getExtent(); + const size = Math.abs(axisExtent[1] - axisExtent[0]); + return interval * (size / (dataExtent[1] - dataExtent[0])); + } else { + return axisGetBandWidth.call(this); + } } else { return axisGetBandWidth.call(this); } 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 c16b109984..8d821b6689 100644 --- a/ui-ngx/src/app/shared/models/time/time.models.ts +++ b/ui-ngx/src/app/shared/models/time/time.models.ts @@ -1115,25 +1115,35 @@ export const endIntervalDate = (current: moment_.Moment, interval: IntervalType) } }; -export const calculateAggInterval = (subsTw: SubscriptionTimewindow, endTs: number, timestamp: number): [number, number] => { +export const calculateAggIntervalWithSubscriptionTimeWindow + = (subsTw: SubscriptionTimewindow, endTs: number, timestamp: number): [number, number] => + calculateInterval(subsTw.startTs, endTs, subsTw.aggregation.interval, subsTw.tsOffset, subsTw.timezone, timestamp); + +export const calculateAggIntervalWithWidgetTimeWindow + = (widgetTimeWindow: WidgetTimewindow, timestamp: number): [number, number] => + calculateInterval(widgetTimeWindow.minTime - widgetTimeWindow.tsOffset, + widgetTimeWindow.maxTime, widgetTimeWindow.interval, widgetTimeWindow.tsOffset, widgetTimeWindow.timezone, timestamp); + +export const calculateInterval = (startTime: number, endTime: number, + interval: Interval, tsOffset: number, timezone: string, timestamp: number): [number, number] => { let startIntervalTs: number; let endIntervalTs: number; - if (typeof subsTw.aggregation.interval === 'number') { - const startTs = subsTw.startTs + subsTw.tsOffset; - startIntervalTs = startTs + Math.floor((timestamp - startTs) / subsTw.aggregation.interval) * subsTw.aggregation.interval; - endIntervalTs = startIntervalTs + subsTw.aggregation.interval; + if (typeof interval === 'number') { + const startTs = startTime + tsOffset; + startIntervalTs = startTs + Math.floor((timestamp - startTs) / interval) * interval; + endIntervalTs = startIntervalTs + interval; } else { - const time = getTime(timestamp, subsTw.timezone); - let startInterval = startIntervalDate(time, subsTw.aggregation.interval); - const start = getTime(subsTw.startTs, subsTw.timezone); + const time = getTime(timestamp, timezone); + let startInterval = startIntervalDate(time, interval); + const start = getTime(startTime, timezone); if (start.isAfter(startInterval)) { startInterval = start; } - const endInterval = endIntervalDate(time, subsTw.aggregation.interval).add(1, 'milliseconds'); - startIntervalTs = startInterval.valueOf() + subsTw.tsOffset; - endIntervalTs = endInterval.valueOf() + subsTw.tsOffset; + const endInterval = endIntervalDate(time, interval).add(1, 'milliseconds'); + startIntervalTs = startInterval.valueOf() + tsOffset; + endIntervalTs = endInterval.valueOf() + tsOffset; } - endIntervalTs = Math.min(endIntervalTs, endTs); + endIntervalTs = Math.min(endIntervalTs, endTime); return [startIntervalTs, endIntervalTs]; };