- ;
overlayStyle: ComponentStyle = {};
+ overlayEnabled: boolean;
+ padding: string;
- legendItems: BarChartLegendItem[];
+ legendKeys: DataKey[];
legendLabelStyle: ComponentStyle;
disabledLegendLabelStyle: ComponentStyle;
- private get noAggregation(): boolean {
- return this.ctx.defaultSubscription.timeWindowConfig?.aggregation?.type === AggregationType.NONE;
- }
-
- private shapeResize$: ResizeObserver;
-
- private decimals = 0;
- private units = '';
-
- private dataItems: BarChartDataItem[] = [];
-
- private drawChartPending = false;
- private barChart: ECharts;
- private barChartOptions: EChartsOption;
-
- private tooltipDateFormat: DateFormatProcessor;
-
- private barRenderItem: CustomSeriesRenderItem;
- private barLabelLayoutCallback: LabelLayoutOptionCallback;
+ private timeSeriesChart: TbTimeSeriesChart;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
@@ -127,356 +84,64 @@ export class BarChartWithLabelsWidgetComponent implements OnInit, OnDestroy, Aft
this.ctx.$scope.barChartWidget = this;
this.settings = {...barChartWithLabelsDefaultSettings, ...this.ctx.settings};
- this.decimals = this.ctx.decimals;
- this.units = this.ctx.units;
-
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
+ this.overlayEnabled = this.settings.background.overlay.enabled;
+ this.padding = this.overlayEnabled ? undefined : this.settings.padding;
this.showLegend = this.settings.showLegend;
if (this.showLegend) {
- this.legendItems = [];
+ this.legendKeys = [];
this.legendClass = `legend-${this.settings.legendPosition}`;
this.legendLabelStyle = textStyle(this.settings.legendLabelFont);
this.disabledLegendLabelStyle = textStyle(this.settings.legendLabelFont);
this.legendLabelStyle.color = this.settings.legendLabelColor;
}
- let counter = 0;
- if (this.ctx.datasources.length) {
- for (const datasource of this.ctx.datasources) {
- const dataKeys = datasource.dataKeys;
- for (const dataKey of dataKeys) {
- const id = counter++;
- const datasourceData = this.ctx.data ? this.ctx.data.find(d => d.dataKey === dataKey) : null;
- const namedData = datasourceData?.data ? toNamedData(datasourceData.data) : [];
- this.dataItems.push({
- id: id+'',
- dataKey,
- data: namedData,
- enabled: true
- });
- if (this.showLegend) {
- this.legendItems.push(
- {
- id: id+'',
- label: dataKey.label,
- color: dataKey.color,
- enabled: true
- }
- );
- }
+ const barSettings = barChartWithLabelsTimeSeriesKeySettings(this.settings, this.ctx.decimals);
+ for (const datasource of this.ctx.datasources) {
+ const dataKeys = datasource.dataKeys;
+ for (const dataKey of dataKeys) {
+ dataKey.settings = barSettings;
+ if (this.showLegend) {
+ this.legendKeys.push(dataKey);
}
}
}
-
- if (this.settings.showTooltip && this.settings.tooltipShowDate) {
- this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.tooltipDateFormat);
- }
-
- const barValueStyle: ComponentStyle = textStyle(this.settings.barValueFont);
- delete barValueStyle.lineHeight;
- barValueStyle.fontSize = this.settings.barValueFont.size;
- barValueStyle.fill = this.settings.barValueColor;
-
- const barLabelStyle: ComponentStyle = textStyle(this.settings.barLabelFont);
- delete barLabelStyle.lineHeight;
- barLabelStyle.fontSize = this.settings.barLabelFont.size;
- barLabelStyle.fill = this.settings.barLabelColor;
-
- this.barRenderItem = (params, api) => {
-
- const time = api.value(0) as number;
- let start = api.value(2) as number;
- const end = api.value(3) as number;
- let interval = end - start;
- if (!start || !end || !interval) {
- interval = IntervalMath.numberValue(this.ctx.timeWindow.interval);
- start = time - interval / 2;
- }
- const enabledDataItems = this.dataItems.filter(d => d.enabled);
- const barInterval = interval / (enabledDataItems.length + 1);
- const intervalGap = barInterval / 2;
-
- const index = enabledDataItems.findIndex(d => d.id === params.seriesId);
- const value = api.value(1);
- const startTime = start + intervalGap + barInterval * index;
- const delta = barInterval;
- const lowerLeft = api.coord([startTime, value >= 0 ? value : 0]);
- const height = api.size([delta, value])[1];
- const width = api.size([delta, 10])[0];
-
- const coordSys: {x: number; y: number; width: number; height: number} = params.coordSys as any;
-
- const rectShape = echarts.graphic.clipRectByRect({
- x: lowerLeft[0],
- y: lowerLeft[1],
- width,
- height
- }, {
- x: coordSys.x,
- y: coordSys.y,
- width: coordSys.width,
- height: coordSys.height
- });
-
- const zeroPos = api.coord([0, 0]);
- const labelParts: string[] = [];
- if (this.settings.showBarValue) {
- const labelValue = formatValue(value, this.decimals, '', false);
- labelParts.push(`{value|${labelValue}}`);
- }
- if (this.settings.showBarLabel) {
- labelParts.push(`{label|${params.seriesName}}`);
- }
- const barLabel = labelParts.join(' ');
- return rectShape && {
- type: 'rect',
- id: time + '',
- shape: rectShape,
- style: {
- fill: api.visual('color'),
- text: barLabel,
- textPosition: 'insideBottom',
- textRotation: Math.PI / 2,
- textDistance: 15,
- textStrokeWidth: 0,
- textAlign: 'left',
- textVerticalAlign: 'middle',
- rich: {
- value: barValueStyle,
- label: barLabelStyle
- }
- },
- focus: 'series',
- transition: 'all',
- enterFrom: {
- style: { opacity: 0 },
- shape: { height: 0, y: zeroPos[1] }
- }
- };
- };
-
- this.barLabelLayoutCallback = (params) => {
- if (params.rect.width - params.labelRect.width < 2) {
- return {
- y: '100000%',
- };
- } else {
- return {
- hideOverlap: true
- };
- }
- };
}
ngAfterViewInit() {
- if (this.drawChartPending) {
- this.drawChart();
- }
+ const settings = barChartWithLabelsTimeSeriesSettings(this.settings);
+ this.timeSeriesChart = new TbTimeSeriesChart(this.ctx, settings, this.chartShape.nativeElement, this.renderer);
}
ngOnDestroy() {
- if (this.shapeResize$) {
- this.shapeResize$.disconnect();
- }
- if (this.barChart) {
- this.barChart.dispose();
+ if (this.timeSeriesChart) {
+ this.timeSeriesChart.destroy();
}
}
public onInit() {
const borderRadius = this.ctx.$widgetElement.css('borderRadius');
this.overlayStyle = {...this.overlayStyle, ...{borderRadius}};
- if (this.chartShape) {
- this.drawChart();
- } else {
- this.drawChartPending = true;
- }
this.cd.detectChanges();
}
public onDataUpdated() {
- for (const item of this.dataItems) {
- const datasourceData = this.ctx.data ? this.ctx.data.find(d => d.dataKey === item.dataKey) : null;
- item.data = datasourceData?.data ? toNamedData(datasourceData.data) : [];
- }
- 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).tbTimeWindow = this.ctx.defaultSubscription.timeWindow;
- this.barChartOptions.series = this.updateSeries();
- this.barChart.setOption(this.barChartOptions);
+ if (this.timeSeriesChart) {
+ this.timeSeriesChart.update();
}
}
- private updateSeries(): Array {
- const series: Array = [];
- for (const item of this.dataItems) {
- if (item.enabled) {
- const seriesOption: CustomSeriesOption = {
- type: 'custom',
- id: item.id,
- name: item.dataKey.label,
- color: item.dataKey.color,
- data: item.data,
- renderItem: this.barRenderItem,
- labelLayout: this.barLabelLayoutCallback,
- dimensions: [
- {name: 'intervalStart', type: 'number'},
- {name: 'intervalEnd', type: 'number'}
- ],
- encode: {
- intervalStart: 2,
- intervalEnd: 3
- }
- };
- series.push(seriesOption);
- }
- }
- return series;
+ public onLegendKeyEnter(key: DataKey) {
+ this.timeSeriesChart.keyEnter(key);
}
-
- public onLegendItemEnter(item: BarChartLegendItem) {
- this.barChart.dispatchAction({
- type: 'highlight',
- seriesId: item.id
- });
- }
-
- public onLegendItemLeave(item: BarChartLegendItem) {
- this.barChart.dispatchAction({
- type: 'downplay',
- seriesId: item.id
- });
- }
-
- public toggleLegendItem(item: BarChartLegendItem) {
- const enable = !item.enabled;
- const dataItem = this.dataItems.find(d => d.id === item.id);
- if (dataItem) {
- dataItem.enabled = enable;
- if (!enable) {
- this.barChart.dispatchAction({
- type: 'downplay',
- seriesId: item.id
- });
- }
- this.barChartOptions.series = this.updateSeries();
- this.barChart.setOption(this.barChartOptions, {replaceMerge: ['series']});
- item.enabled = enable;
- if (enable) {
- this.barChart.dispatchAction({
- type: 'highlight',
- seriesId: item.id
- });
- }
- }
+ public onLegendKeyLeave(key: DataKey) {
+ this.timeSeriesChart.keyLeave(key);
}
- private drawChart() {
- echartsModule.init();
- this.barChart = echarts.init(this.chartShape.nativeElement, null, {
- renderer: 'canvas',
- });
- this.barChartOptions = {
- tooltip: {
- trigger: 'axis',
- confine: true,
- appendTo: 'body',
- axisPointer: {
- type: 'shadow'
- },
- formatter: (params: CallbackDataParams[]) => {
- if (this.settings.showTooltip) {
- const focusedSeriesIndex = this.focusedSeriesIndex();
- return echartsTooltipFormatter(this.renderer, this.tooltipDateFormat,
- this.settings, params, this.decimals, this.units, focusedSeriesIndex, null,
- this.noAggregation ? null : this.ctx.timeWindow.interval);
- } else {
- return undefined;
- }
- },
- padding: [8, 12],
- backgroundColor: this.settings.tooltipBackgroundColor,
- borderWidth: 0,
- extraCssText: `line-height: 1; backdrop-filter: blur(${this.settings.tooltipBackgroundBlur}px);`
- },
- grid: {
- containLabel: true,
- top: '30',
- left: 0,
- right: 0,
- bottom: 0
- },
- xAxis: {
- type: 'time',
- scale: true,
- axisTick: {
- show: false
- },
- axisLabel: {
- hideOverlap: true,
- fontSize: 10
- },
- axisLine: {
- onZero: false
- },
- min: this.ctx.defaultSubscription.timeWindow.minTime,
- max: this.ctx.defaultSubscription.timeWindow.maxTime,
- bandWidthCalculator: timeAxisBandWidthCalculator
- },
- yAxis: {
- type: 'value',
- axisLabel: {
- formatter: (value: any) => formatValue(value, this.decimals, this.units, false)
- }
- }
- };
-
- (this.barChartOptions.xAxis as any).tbTimeWindow = this.ctx.defaultSubscription.timeWindow;
-
- this.barChartOptions.series = this.updateSeries();
-
- this.barChart.setOption(this.barChartOptions);
-
- this.shapeResize$ = new ResizeObserver(() => {
- this.onResize();
- });
- this.shapeResize$.observe(this.chartShape.nativeElement);
- this.onResize();
- }
-
- private focusedSeriesIndex(): number {
- let index = - 1;
- const views: any[] = (this.barChart as any)._chartsViews;
- if (views) {
- const hasBlurredView = !!views.find(view => {
- const graphicEls: any[] = view._data._graphicEls;
- return !!graphicEls.find(el => el?.currentStates.includes('blur'));
- });
- if (hasBlurredView) {
- const focusedView = views.find(view => {
- const graphicEls: any[] = view._data._graphicEls;
- return !!graphicEls.find(el => !el?.currentStates.includes('blur'));
- });
- if (focusedView) {
- index = !!focusedView._model ?
- focusedView._model.seriesIndex : (!!focusedView.__model ? focusedView.__model.seriesIndex : -1);
- }
- }
- }
- return index;
- }
-
- private onResize() {
- const width = this.barChart.getWidth();
- const height = this.barChart.getHeight();
- const shapeWidth = this.chartShape.nativeElement.offsetWidth;
- const shapeHeight = this.chartShape.nativeElement.offsetHeight;
- if (width !== shapeWidth || height !== shapeHeight) {
- this.barChart.resize();
- }
+ public toggleLegendKey(key: DataKey) {
+ this.timeSeriesChart.toggleKey(key);
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.models.ts
index 99ea088c92..73ecad5264 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.models.ts
@@ -14,25 +14,64 @@
/// limitations under the License.
///
-import { BackgroundSettings, BackgroundType, customDateFormat, Font } from '@shared/models/widget-settings.models';
+import {
+ BackgroundSettings,
+ BackgroundType,
+ ComponentStyle,
+ customDateFormat,
+ Font,
+ textStyle
+} from '@shared/models/widget-settings.models';
import { LegendPosition } from '@shared/models/widget.models';
import { EChartsTooltipWidgetSettings } from '@home/components/widget/lib/chart/echarts-widget.models';
+import { DeepPartial } from '@shared/models/common';
+import {
+ defaultTimeSeriesChartXAxisSettings,
+ defaultTimeSeriesChartYAxisSettings,
+ SeriesFillSettings,
+ SeriesFillType,
+ timeSeriesChartAnimationDefaultSettings,
+ TimeSeriesChartAnimationSettings,
+ TimeSeriesChartKeySettings,
+ timeSeriesChartNoAggregationBarWidthDefaultSettings,
+ TimeSeriesChartNoAggregationBarWidthSettings,
+ TimeSeriesChartSeriesType,
+ TimeSeriesChartSettings,
+ TimeSeriesChartThreshold,
+ TimeSeriesChartXAxisSettings,
+ TimeSeriesChartYAxisSettings
+} from '@home/components/widget/lib/chart/time-series-chart.models';
+import { CallbackDataParams, LabelLayoutOptionCallbackParams } from 'echarts/types/dist/shared';
+import { formatValue, mergeDeep } from '@core/utils';
+import { LabelLayoutOption } from 'echarts/types/src/util/types';
export interface BarChartWithLabelsWidgetSettings extends EChartsTooltipWidgetSettings {
+ dataZoom: boolean;
showBarLabel: boolean;
barLabelFont: Font;
barLabelColor: string;
showBarValue: boolean;
barValueFont: Font;
barValueColor: string;
+ showBarBorder: boolean;
+ barBorderWidth: number;
+ barBorderRadius: number;
+ barBackgroundSettings: SeriesFillSettings;
+ noAggregationBarWidthSettings: TimeSeriesChartNoAggregationBarWidthSettings;
+ yAxis: TimeSeriesChartYAxisSettings;
+ xAxis: TimeSeriesChartXAxisSettings;
+ animation: TimeSeriesChartAnimationSettings;
+ thresholds: TimeSeriesChartThreshold[];
showLegend: boolean;
legendPosition: LegendPosition;
legendLabelFont: Font;
legendLabelColor: string;
background: BackgroundSettings;
+ padding: string;
}
export const barChartWithLabelsDefaultSettings: BarChartWithLabelsWidgetSettings = {
+ dataZoom: false,
showBarLabel: true,
barLabelFont: {
family: 'Roboto',
@@ -53,6 +92,28 @@ export const barChartWithLabelsDefaultSettings: BarChartWithLabelsWidgetSettings
lineHeight: '12px'
},
barValueColor: 'rgba(0, 0, 0, 0.76)',
+ showBarBorder: false,
+ barBorderWidth: 2,
+ barBorderRadius: 0,
+ barBackgroundSettings: {
+ type: SeriesFillType.none,
+ opacity: 0.4,
+ gradient: {
+ start: 100,
+ end: 0
+ }
+ },
+ noAggregationBarWidthSettings: mergeDeep({} as TimeSeriesChartNoAggregationBarWidthSettings,
+ timeSeriesChartNoAggregationBarWidthDefaultSettings),
+ yAxis: mergeDeep({} as TimeSeriesChartYAxisSettings,
+ defaultTimeSeriesChartYAxisSettings,
+ { id: 'default', order: 0, showLine: false, showTicks: false } as TimeSeriesChartYAxisSettings),
+ xAxis: mergeDeep({} as TimeSeriesChartXAxisSettings,
+ defaultTimeSeriesChartXAxisSettings,
+ {showTicks: false, showSplitLines: false} as TimeSeriesChartXAxisSettings),
+ animation: mergeDeep({} as TimeSeriesChartAnimationSettings,
+ timeSeriesChartAnimationDefaultSettings),
+ thresholds: [],
showLegend: true,
legendPosition: LegendPosition.top,
legendLabelFont: {
@@ -96,5 +157,89 @@ export const barChartWithLabelsDefaultSettings: BarChartWithLabelsWidgetSettings
color: 'rgba(255,255,255,0.72)',
blur: 3
}
- }
+ },
+ padding: '12px'
+};
+
+export const barChartWithLabelsTimeSeriesSettings = (settings: BarChartWithLabelsWidgetSettings): DeepPartial => ({
+ dataZoom: settings.dataZoom,
+ yAxes: {
+ default: settings.yAxis
+ },
+ xAxis: settings.xAxis,
+ barWidthSettings: {
+ barGap: 0,
+ intervalGap: 0.5
+ },
+ noAggregationBarWidthSettings: settings.noAggregationBarWidthSettings,
+ animation: settings.animation,
+ thresholds: settings.thresholds,
+ showTooltip: settings.showTooltip,
+ tooltipValueFont: settings.tooltipValueFont,
+ tooltipValueColor: settings.tooltipValueColor,
+ tooltipShowDate: settings.tooltipShowDate,
+ tooltipDateInterval: settings.tooltipDateInterval,
+ tooltipDateFormat: settings.tooltipDateFormat,
+ tooltipDateFont: settings.tooltipDateFont,
+ tooltipDateColor: settings.tooltipDateColor,
+ tooltipBackgroundColor: settings.tooltipBackgroundColor,
+ tooltipBackgroundBlur: settings.tooltipBackgroundBlur,
+ tooltipShowFocusedSeries: true
+});
+
+export const barChartWithLabelsTimeSeriesKeySettings = (settings: BarChartWithLabelsWidgetSettings,
+ decimals: number): DeepPartial => {
+ const barValueStyle: ComponentStyle = textStyle(settings.barValueFont);
+ delete barValueStyle.lineHeight;
+ barValueStyle.fontSize = settings.barValueFont.size;
+ barValueStyle.fill = settings.barValueColor;
+
+ const barLabelStyle: ComponentStyle = textStyle(settings.barLabelFont);
+ delete barLabelStyle.lineHeight;
+ barLabelStyle.fontSize = settings.barLabelFont.size;
+ barLabelStyle.fill = settings.barLabelColor;
+ return {
+ type: TimeSeriesChartSeriesType.bar,
+ barSettings: {
+ showBorder: settings.showBarBorder,
+ borderWidth: settings.barBorderWidth,
+ borderRadius: settings.barBorderRadius,
+ backgroundSettings: settings.barBackgroundSettings,
+ showLabel: settings.showBarLabel || settings.showBarValue,
+ labelPosition: 'insideBottom',
+ labelFormatter: (params: CallbackDataParams): string => {
+ const labelParts: string[] = [];
+ if (settings.showBarValue) {
+ const labelValue = formatValue(params.value[1], decimals, '', false);
+ labelParts.push(`{value|${labelValue}}`);
+ }
+ if (settings.showBarLabel) {
+ labelParts.push(`{label|${params.seriesName}}`);
+ }
+ return labelParts.join(' ');
+ },
+ labelLayout: (params: LabelLayoutOptionCallbackParams): LabelLayoutOption => {
+ if (params.rect.width - params.labelRect.width < 2) {
+ return {
+ y: '100000%',
+ };
+ } else {
+ return {
+ hideOverlap: true
+ };
+ }
+ },
+ additionalLabelOption: {
+ textRotation: Math.PI / 2,
+ textDistance: 15,
+ textStrokeWidth: 0,
+ textAlign: 'left',
+ textVerticalAlign: 'middle',
+ rich: {
+ value: barValueStyle,
+ label: barLabelStyle
+ }
+ }
+ }
+ };
};
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 816f45a7e8..81ffb457b9 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
@@ -17,7 +17,7 @@
import * as echarts from 'echarts/core';
import AxisModel from 'echarts/types/src/coord/cartesian/AxisModel';
import { estimateLabelUnionRect } from 'echarts/lib/coord/axisHelper';
-import { formatValue, isDefinedAndNotNull } from '@core/utils';
+import { formatValue, isDefinedAndNotNull, isNumber } from '@core/utils';
import {
DataZoomComponent,
DataZoomComponentOption,
@@ -55,6 +55,7 @@ import { DateFormatProcessor, DateFormatSettings, Font } from '@shared/models/wi
import GlobalModel from 'echarts/types/src/model/Global';
import Axis2D from 'echarts/types/src/coord/cartesian/Axis2D';
import SeriesModel from 'echarts/types/src/model/Series';
+import { MarkLine2DDataItemOption } from 'echarts/types/src/component/marker/MarkLineModel';
class EChartsModule {
private initialized = false;
@@ -110,6 +111,51 @@ export type EChartsSeriesItem = {
decimals?: number;
};
+export enum EChartsShape {
+ emptyCircle = 'emptyCircle',
+ circle = 'circle',
+ rect = 'rect',
+ roundRect = 'roundRect',
+ triangle = 'triangle',
+ diamond = 'diamond',
+ pin = 'pin',
+ arrow = 'arrow',
+ none = 'none'
+}
+
+export const echartsShapes = Object.keys(EChartsShape) as EChartsShape[];
+
+export const echartsShapeTranslations = new Map(
+ [
+ [EChartsShape.emptyCircle, 'widgets.time-series-chart.shape-empty-circle'],
+ [EChartsShape.circle, 'widgets.time-series-chart.shape-circle'],
+ [EChartsShape.rect, 'widgets.time-series-chart.shape-rect'],
+ [EChartsShape.roundRect, 'widgets.time-series-chart.shape-round-rect'],
+ [EChartsShape.triangle, 'widgets.time-series-chart.shape-triangle'],
+ [EChartsShape.diamond, 'widgets.time-series-chart.shape-diamond'],
+ [EChartsShape.pin, 'widgets.time-series-chart.shape-pin'],
+ [EChartsShape.arrow, 'widgets.time-series-chart.shape-arrow'],
+ [EChartsShape.none, 'widgets.time-series-chart.shape-none']
+ ]
+);
+
+type EChartsShapeOffsetFunction = (size: number) => number;
+
+export const timeSeriesChartShapeOffsetFunctions = new Map(
+ [
+ [EChartsShape.emptyCircle, size => size / 2 + 1],
+ [EChartsShape.circle, size => size / 2],
+ [EChartsShape.rect, size => size / 2],
+ [EChartsShape.roundRect, size => size / 2],
+ [EChartsShape.triangle, size => size / 2],
+ [EChartsShape.diamond, size => size / 2],
+ [EChartsShape.pin, size => size],
+ [EChartsShape.arrow, () => 0],
+ [EChartsShape.none, () => 0],
+ ]
+);
+
+
export const timeAxisBandWidthCalculator: TimeAxisBandWidthCalculator = (model) => {
let interval: number;
const axisOption = model.option;
@@ -211,7 +257,23 @@ export const measureXAxisNameHeight = (chart: ECharts, name: string): number =>
return 0;
};
-export const measureThresholdLabelOffset = (chart: ECharts, axisId: string, thresholdId: string, value: any): [number, number] => {
+const measureSymbolOffset = (symbol: string, symbolSize: any): number => {
+ if (isNumber(symbolSize)) {
+ if (symbol) {
+ const offsetFunction = timeSeriesChartShapeOffsetFunctions.get(symbol as EChartsShape);
+ if (offsetFunction) {
+ return offsetFunction(symbolSize);
+ } else {
+ return symbolSize / 2;
+ }
+ }
+ } else {
+ return 0;
+ }
+}
+
+export const measureThresholdOffset = (chart: ECharts, axisId: string, thresholdId: string, value: any): [number, number] => {
+ const offset: [number, number] = [0,0];
const axis = getYAxis(chart, axisId);
if (axis && !axis.scale.isBlank()) {
const extent = axis.scale.getExtent();
@@ -220,6 +282,16 @@ export const measureThresholdLabelOffset = (chart: ECharts, axisId: string, thre
if (models?.length) {
const lineSeriesModel = models[0] as SeriesModel;
const markLineModel = lineSeriesModel.getModel('markLine');
+ const dataOption = markLineModel.get('data');
+ for (const dataItemOption of dataOption) {
+ const dataItem = dataItemOption as MarkLine2DDataItemOption;
+ const start = dataItem[0];
+ const startOffset = measureSymbolOffset(start.symbol, start.symbolSize);
+ offset[0] = Math.max(offset[0], startOffset);
+ const end = dataItem[1];
+ const endOffset = measureSymbolOffset(end.symbol, end.symbolSize);
+ offset[1] = Math.max(offset[1], endOffset);
+ }
const labelPosition = markLineModel.get(['label', 'position']);
if (labelPosition === 'start' || labelPosition === 'end') {
const labelModel = markLineModel.getModel('label');
@@ -239,23 +311,38 @@ export const measureThresholdLabelOffset = (chart: ECharts, axisId: string, thre
}
}
if (!textWidth) {
- return [0,0];
+ return offset;
}
const distanceOpt = markLineModel.get(['label', 'distance']);
let distance = 5;
if (distanceOpt) {
distance = typeof distanceOpt === 'number' ? distanceOpt : distanceOpt[0];
}
- const offset = distance + textWidth;
+ const paddingOpt = markLineModel.get(['label', 'padding']);
+ let leftPadding = 0;
+ let rightPadding = 0;
+ if (paddingOpt) {
+ if (Array.isArray(paddingOpt)) {
+ if (paddingOpt.length === 4) {
+ leftPadding = paddingOpt[3];
+ rightPadding = paddingOpt[1];
+ } else if (paddingOpt.length === 2) {
+ leftPadding = rightPadding = paddingOpt[1];
+ }
+ } else {
+ leftPadding = rightPadding = paddingOpt;
+ }
+ }
+ const textOffset = distance + textWidth + leftPadding + rightPadding;
if (labelPosition === 'start') {
- return [offset, 0];
+ offset[0] = Math.max(offset[0], textOffset);
} else {
- return [0, offset];
+ offset[1] = Math.max(offset[1], textOffset);
}
}
}
}
- return [0,0];
+ return offset;
};
export const getAxisExtent = (chart: ECharts, axisId: string): [number, number] => {
@@ -266,6 +353,48 @@ export const getAxisExtent = (chart: ECharts, axisId: string): [number, number]
return [0,0];
};
+let componentBlurredKey: string;
+
+const isBlurred = (model: SeriesModel): boolean => {
+ if (!componentBlurredKey) {
+ const innerKeys = Object.keys(model).filter(k => k.startsWith('__ec_inner_'));
+ for (const k of innerKeys) {
+ const obj = model[k];
+ if (obj.hasOwnProperty('isBlured')) {
+ componentBlurredKey = k;
+ break;
+ }
+ }
+ }
+ if (componentBlurredKey) {
+ const obj = model[componentBlurredKey];
+ return !!obj?.isBlured;
+ } else {
+ return false;
+ }
+};
+
+export const getFocusedSeriesIndex = (chart: ECharts): number => {
+ const model: GlobalModel = (chart as any).getModel();
+ const models = model.queryComponents({mainType: 'series'});
+ if (models) {
+ let hasBlurred = false;
+ let notBlurredIndex = -1;
+ for (const _model of models) {
+ const seriesModel = _model as SeriesModel;
+ const blurred = isBlurred(seriesModel);
+ if (!blurred) {
+ notBlurredIndex = seriesModel.seriesIndex;
+ }
+ hasBlurred = blurred || hasBlurred;
+ }
+ if (hasBlurred) {
+ return notBlurredIndex;
+ }
+ }
+ return -1;
+};
+
export const toNamedData = (data: DataSet): NamedDataSet => {
if (!data?.length) {
return [];
@@ -304,6 +433,7 @@ export const tooltipTriggerTranslationMap = new Map
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.scss
index feb65353f6..ac7229672e 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/bar-chart-with-labels-widget.component.scss
@@ -19,8 +19,10 @@
position: relative;
display: flex;
flex-direction: column;
- gap: 16px;
- padding: 20px 24px 24px 24px;
+ gap: 8px;
+ &.overlay {
+ padding: 20px 24px 24px 24px;
+ }
> div:not(.tb-bar-chart-overlay) {
z-index: 1;
}
@@ -40,7 +42,7 @@
min-height: 0;
display: flex;
flex-direction: column;
- gap: 16px;
+ gap: 8px;
&.legend-top {
flex-direction: column-reverse;
}
@@ -88,8 +90,9 @@
}
}
&.legend-right, &.legend-left {
- gap: 24px;
+ gap: 16px;
.tb-bar-chart-legend {
+ padding-top: 8px;
flex-direction: column-reverse;
justify-content: flex-end;
align-items: stretch;
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 e2779f2821..b840f49e3b 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
@@ -28,45 +28,18 @@ import {
ViewEncapsulation
} from '@angular/core';
import { WidgetContext } from '@home/models/widget-component.models';
-import {
- backgroundStyle,
- ComponentStyle,
- DateFormatProcessor,
- overlayStyle,
- textStyle
-} from '@shared/models/widget-settings.models';
-import { ResizeObserver } from '@juggle/resize-observer';
-import { formatValue } from '@core/utils';
+import { backgroundStyle, ComponentStyle, overlayStyle, textStyle } from '@shared/models/widget-settings.models';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
import {
barChartWithLabelsDefaultSettings,
+ barChartWithLabelsTimeSeriesKeySettings,
+ barChartWithLabelsTimeSeriesSettings,
BarChartWithLabelsWidgetSettings
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models';
-
-import * as echarts from 'echarts/core';
-import { CustomSeriesOption } from 'echarts/charts';
-import { CallbackDataParams, CustomSeriesRenderItem, LabelLayoutOptionCallback } from 'echarts/types/dist/shared';
-
-import {
- ECharts,
- echartsModule,
- EChartsOption,
- EChartsSeriesItem,
- echartsTooltipFormatter, timeAxisBandWidthCalculator,
- toNamedData
-} from '@home/components/widget/lib/chart/echarts-widget.models';
-import { AggregationType, IntervalMath } from '@shared/models/time/time.models';
-
-type BarChartDataItem = EChartsSeriesItem;
-
-interface BarChartLegendItem {
- id: string;
- color: string;
- label: string;
- enabled: boolean;
-}
+import { TbTimeSeriesChart } from '@home/components/widget/lib/chart/time-series-chart';
+import { DataKey } from '@shared/models/widget.models';
@Component({
selector: 'tb-bar-chart-with-labels-widget',
@@ -92,30 +65,14 @@ export class BarChartWithLabelsWidgetComponent implements OnInit, OnDestroy, Aft
backgroundStyle$: Observable
-
-
{{ legendItem.label }}
+
+ {{ legendKey.label }}
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.scss
index de2ca546fc..d956173281 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.scss
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.scss
@@ -19,8 +19,10 @@
position: relative;
display: flex;
flex-direction: column;
- gap: 16px;
- padding: 20px 24px 24px 24px;
+ gap: 8px;
+ &.overlay {
+ padding: 20px 24px 24px 24px;
+ }
> div:not(.tb-range-chart-overlay) {
z-index: 1;
}
@@ -40,7 +42,7 @@
min-height: 0;
display: flex;
flex-direction: column;
- gap: 16px;
+ gap: 8px;
&.legend-top {
flex-direction: column-reverse;
}
@@ -88,8 +90,9 @@
}
}
&.legend-right, &.legend-left {
- gap: 24px;
+ gap: 16px;
.tb-range-chart-legend {
+ padding-top: 8px;
flex-direction: column-reverse;
justify-content: flex-end;
align-items: stretch;
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.ts
index 1ef756f1f7..9d89154111 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.component.ts
@@ -30,144 +30,24 @@ import {
import { WidgetContext } from '@home/models/widget-component.models';
import {
backgroundStyle,
- ColorRange,
ComponentStyle,
- DateFormatProcessor,
- filterIncludingColorRanges,
getDataKey,
overlayStyle,
- sortedColorRange,
textStyle
} from '@shared/models/widget-settings.models';
-import { ResizeObserver } from '@juggle/resize-observer';
-import * as echarts from 'echarts/core';
-import { formatValue, isDefinedAndNotNull, isNumber } from '@core/utils';
-import { rangeChartDefaultSettings, RangeChartWidgetSettings } from './range-chart-widget.models';
+import { isDefinedAndNotNull } from '@core/utils';
+import {
+ rangeChartDefaultSettings,
+ rangeChartTimeSeriesKeySettings,
+ rangeChartTimeSeriesSettings,
+ RangeChartWidgetSettings,
+ RangeItem,
+ toRangeItems
+} from './range-chart-widget.models';
import { Observable } from 'rxjs';
import { ImagePipe } from '@shared/pipe/image.pipe';
import { DomSanitizer } from '@angular/platform-browser';
-import {
- ECharts,
- echartsModule,
- EChartsOption,
- echartsTooltipFormatter, timeAxisBandWidthCalculator,
- toNamedData
-} from '@home/components/widget/lib/chart/echarts-widget.models';
-import { CallbackDataParams } from 'echarts/types/dist/shared';
-import { AggregationType } from '@shared/models/time/time.models';
-
-interface VisualPiece {
- lt?: number;
- gt?: number;
- lte?: number;
- gte?: number;
- value?: number;
- color?: string;
-}
-
-interface RangeItem {
- index: number;
- from?: number;
- to?: number;
- piece: VisualPiece;
- color: string;
- label: string;
- visible: boolean;
- enabled: boolean;
-}
-
-const rangeItemLabel = (from?: number, to?: number): string => {
- if (isNumber(from) && isNumber(to)) {
- if (from === to) {
- return `${from}`;
- } else {
- return `${from} - ${to}`;
- }
- } else if (isNumber(from)) {
- return `≥ ${from}`;
- } else if (isNumber(to)) {
- return `< ${to}`;
- } else {
- return null;
- }
-};
-
-const toVisualPiece = (color: string, from?: number, to?: number): VisualPiece => {
- const piece: VisualPiece = {
- color
- };
- if (isNumber(from) && isNumber(to)) {
- if (from === to) {
- piece.value = from;
- } else {
- piece.gte = from;
- piece.lt = to;
- }
- } else if (isNumber(from)) {
- piece.gte = from;
- } else if (isNumber(to)) {
- piece.lt = to;
- }
- return piece;
-};
-
-const toRangeItems = (colorRanges: Array): RangeItem[] => {
- const rangeItems: RangeItem[] = [];
- let counter = 0;
- const ranges = sortedColorRange(filterIncludingColorRanges(colorRanges)).filter(r => isNumber(r.from) || isNumber(r.to));
- for (let i = 0; i < ranges.length; i++) {
- const range = ranges[i];
- let from = range.from;
- const to = range.to;
- if (i > 0) {
- const prevRange = ranges[i - 1];
- if (isNumber(prevRange.to) && isNumber(from) && from < prevRange.to) {
- from = prevRange.to;
- }
- }
- rangeItems.push(
- {
- index: counter++,
- color: range.color,
- enabled: true,
- visible: true,
- from,
- to,
- label: rangeItemLabel(from, to),
- piece: toVisualPiece(range.color, from, to)
- }
- );
- if (!isNumber(from) || !isNumber(to)) {
- const value = !isNumber(from) ? to : from;
- rangeItems.push(
- {
- index: counter++,
- color: 'transparent',
- enabled: true,
- visible: false,
- label: '',
- piece: { gt: value - 0.000000001, lt: value + 0.000000001, color: 'transparent'}
- }
- );
- }
- }
- return rangeItems;
-};
-
-const getMarkPoints = (ranges: Array): number[] => {
- const points = new Set();
- for (const range of ranges) {
- if (range.visible) {
- if (isNumber(range.from)) {
- points.add(range.from);
- }
- if (isNumber(range.to)) {
- points.add(range.to);
- }
- }
- }
- return Array.from(points).sort();
-};
+import { TbTimeSeriesChart } from '@home/components/widget/lib/chart/time-series-chart';
@Component({
selector: 'tb-range-chart-widget',
@@ -193,28 +73,19 @@ export class RangeChartWidgetComponent implements OnInit, OnDestroy, AfterViewIn
backgroundStyle$: Observable;
overlayStyle: ComponentStyle = {};
+ overlayEnabled: boolean;
+ padding: string;
legendLabelStyle: ComponentStyle;
disabledLegendLabelStyle: ComponentStyle;
visibleRangeItems: RangeItem[];
- private get noAggregation(): boolean {
- return this.ctx.defaultSubscription.timeWindowConfig?.aggregation?.type === AggregationType.NONE;
- }
-
- private rangeItems: RangeItem[];
-
- private shapeResize$: ResizeObserver;
-
private decimals = 0;
private units = '';
- private drawChartPending = false;
- private rangeChart: ECharts;
- private rangeChartOptions: EChartsOption;
- private selectedRanges: {[key: number]: boolean} = {};
+ private rangeItems: RangeItem[];
- private tooltipDateFormat: DateFormatProcessor;
+ private timeSeriesChart: TbTimeSeriesChart;
constructor(private imagePipe: ImagePipe,
private sanitizer: DomSanitizer,
@@ -235,16 +106,17 @@ export class RangeChartWidgetComponent implements OnInit, OnDestroy, AfterViewIn
if (dataKey?.units) {
this.units = dataKey.units;
}
-
+ if (dataKey) {
+ dataKey.settings = rangeChartTimeSeriesKeySettings(this.settings);
+ }
this.backgroundStyle$ = backgroundStyle(this.settings.background, this.imagePipe, this.sanitizer);
this.overlayStyle = overlayStyle(this.settings.background.overlay);
+ this.overlayEnabled = this.settings.background.overlay.enabled;
+ this.padding = this.overlayEnabled ? undefined : this.settings.padding;
this.rangeItems = toRangeItems(this.settings.rangeColors);
this.visibleRangeItems = this.rangeItems.filter(item => item.visible);
- for (const range of this.rangeItems) {
- this.selectedRanges[range.index] = true;
- }
this.showLegend = this.settings.showLegend && !!this.rangeItems.length;
@@ -254,193 +126,33 @@ export class RangeChartWidgetComponent implements OnInit, OnDestroy, AfterViewIn
this.disabledLegendLabelStyle = textStyle(this.settings.legendLabelFont);
this.legendLabelStyle.color = this.settings.legendLabelColor;
}
-
- if (this.settings.showTooltip && this.settings.tooltipShowDate) {
- this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.tooltipDateFormat);
- }
}
ngAfterViewInit() {
- if (this.drawChartPending) {
- this.drawChart();
- }
+ const settings = rangeChartTimeSeriesSettings(this.settings, this.rangeItems, this.decimals, this.units);
+ this.timeSeriesChart = new TbTimeSeriesChart(this.ctx, settings, this.chartShape.nativeElement, this.renderer);
}
ngOnDestroy() {
- if (this.shapeResize$) {
- this.shapeResize$.disconnect();
- }
- if (this.rangeChart) {
- this.rangeChart.dispose();
+ if (this.timeSeriesChart) {
+ this.timeSeriesChart.destroy();
}
}
public onInit() {
const borderRadius = this.ctx.$widgetElement.css('borderRadius');
this.overlayStyle = {...this.overlayStyle, ...{borderRadius}};
- if (this.chartShape) {
- this.drawChart();
- } else {
- this.drawChartPending = true;
- }
this.cd.detectChanges();
}
public onDataUpdated() {
- if (this.rangeChart) {
- this.rangeChart.setOption({
- xAxis: {
- min: this.ctx.defaultSubscription.timeWindow.minTime,
- max: this.ctx.defaultSubscription.timeWindow.maxTime,
- tbTimeWindow: this.ctx.defaultSubscription.timeWindow
- },
- series: [
- {data: this.ctx.data?.length ? toNamedData(this.ctx.data[0].data) : []}
- ],
- visualMap: {
- selected: this.selectedRanges
- }
- });
+ if (this.timeSeriesChart) {
+ this.timeSeriesChart.update();
}
}
public toggleRangeItem(item: RangeItem) {
item.enabled = !item.enabled;
- this.selectedRanges[item.index] = item.enabled;
- this.rangeChart.dispatchAction({
- type: 'selectDataRange',
- selected: this.selectedRanges
- });
- }
-
- private drawChart() {
- echartsModule.init();
- const dataKey = getDataKey(this.ctx.datasources);
- this.rangeChart = echarts.init(this.chartShape.nativeElement, null, {
- renderer: 'canvas',
- });
- this.rangeChartOptions = {
- tooltip: {
- trigger: 'axis',
- confine: true,
- appendTo: 'body',
- axisPointer: {
- type: 'shadow'
- },
- formatter: (params: CallbackDataParams[]) =>
- this.settings.showTooltip ? echartsTooltipFormatter(this.renderer, this.tooltipDateFormat,
- this.settings, params, this.decimals, this.units, 0, null,
- this.noAggregation ? null : this.ctx.timeWindow.interval) : undefined,
- padding: [8, 12],
- backgroundColor: this.settings.tooltipBackgroundColor,
- borderWidth: 0,
- extraCssText: `line-height: 1; backdrop-filter: blur(${this.settings.tooltipBackgroundBlur}px);`
- },
- grid: {
- containLabel: true,
- top: '30',
- left: 0,
- right: 0,
- bottom: this.settings.dataZoom ? 60 : 0
- },
- xAxis: {
- type: 'time',
- axisTick: {
- show: true
- },
- axisLabel: {
- hideOverlap: true,
- fontSize: 10
- },
- axisLine: {
- onZero: false
- },
- min: this.ctx.defaultSubscription.timeWindow.minTime,
- max: this.ctx.defaultSubscription.timeWindow.maxTime,
- bandWidthCalculator: timeAxisBandWidthCalculator
- },
- yAxis: {
- type: 'value',
- axisLabel: {
- formatter: (value: any) => formatValue(value, this.decimals, this.units, false)
- }
- },
- series: [{
- type: 'line',
- name: dataKey?.label,
- smooth: false,
- showSymbol: false,
- animation: true,
- areaStyle: this.settings.fillArea ? {} : undefined,
- data: this.ctx.data?.length ? toNamedData(this.ctx.data[0].data) : [],
- markLine: this.rangeItems.length ? {
- animation: true,
- symbol: ['circle', 'arrow'],
- symbolSize: [5, 7],
- lineStyle: {
- width: 1,
- type: [3, 3],
- color: '#37383b'
- },
- label: {
- position: 'insideEndTop',
- color: '#37383b',
- backgroundColor: 'rgba(255,255,255,0.56)',
- padding: [4, 5],
- borderRadius: 4,
- formatter: params => formatValue(params.value, this.decimals, this.units, false)
- },
- emphasis: {
- disabled: true
- },
- data: getMarkPoints(this.rangeItems).map(point => ({ yAxis: point }))
- } : undefined
- }],
- dataZoom: [
- {
- type: 'inside',
- disabled: !this.settings.dataZoom
- },
- {
- type: 'slider',
- show: this.settings.dataZoom,
- showDetail: false,
- right: 10
- }
- ],
- visualMap: {
- show: false,
- type: 'piecewise',
- selected: this.selectedRanges,
- dimension: 1,
- pieces: this.rangeItems.map(item => item.piece),
- outOfRange: {
- color: this.settings.outOfRangeColor
- },
- inRange: !this.rangeItems.length ? {
- color: this.settings.outOfRangeColor
- } : undefined
- }
- };
-
- (this.rangeChartOptions.xAxis as any).tbTimeWindow = this.ctx.defaultSubscription.timeWindow;
-
- this.rangeChart.setOption(this.rangeChartOptions);
-
- this.shapeResize$ = new ResizeObserver(() => {
- this.onResize();
- });
- this.shapeResize$.observe(this.chartShape.nativeElement);
- this.onResize();
- }
-
- private onResize() {
- const width = this.rangeChart.getWidth();
- const height = this.rangeChart.getHeight();
- const shapeWidth = this.chartShape.nativeElement.offsetWidth;
- const shapeHeight = this.chartShape.nativeElement.offsetHeight;
- if (width !== shapeWidth || height !== shapeHeight) {
- this.rangeChart.resize();
- }
+ this.timeSeriesChart.toggleVisualMapRange(item.index);
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts
index 31905e70ba..e04dccf74d 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts
@@ -18,22 +18,79 @@ import {
BackgroundSettings,
BackgroundType,
ColorRange,
+ filterIncludingColorRanges,
Font,
- simpleDateFormat
+ simpleDateFormat,
+ sortedColorRange
} from '@shared/models/widget-settings.models';
import { LegendPosition } from '@shared/models/widget.models';
-import { EChartsTooltipWidgetSettings } from '@home/components/widget/lib/chart/echarts-widget.models';
+import { EChartsShape, EChartsTooltipWidgetSettings } from '@home/components/widget/lib/chart/echarts-widget.models';
+import {
+ createTimeSeriesChartVisualMapPiece,
+ defaultTimeSeriesChartXAxisSettings,
+ defaultTimeSeriesChartYAxisSettings,
+ LineSeriesStepType,
+ SeriesFillType,
+ SeriesLabelPosition, ThresholdLabelPosition, timeSeriesChartAnimationDefaultSettings,
+ TimeSeriesChartAnimationSettings,
+ timeSeriesChartColorScheme,
+ TimeSeriesChartKeySettings,
+ TimeSeriesChartLineType,
+ TimeSeriesChartSeriesType,
+ TimeSeriesChartSettings,
+ TimeSeriesChartThreshold, timeSeriesChartThresholdDefaultSettings,
+ TimeSeriesChartThresholdType,
+ TimeSeriesChartVisualMapPiece,
+ TimeSeriesChartXAxisSettings,
+ TimeSeriesChartYAxisSettings
+} from '@home/components/widget/lib/chart/time-series-chart.models';
+import { isNumber, mergeDeep } from '@core/utils';
+import { DeepPartial } from '@shared/models/common';
+
+export interface RangeItem {
+ index: number;
+ from?: number;
+ to?: number;
+ color: string;
+ label: string;
+ visible: boolean;
+ enabled: boolean;
+ piece: TimeSeriesChartVisualMapPiece;
+}
export interface RangeChartWidgetSettings extends EChartsTooltipWidgetSettings {
dataZoom: boolean;
rangeColors: Array;
outOfRangeColor: string;
+ showRangeThresholds: boolean;
+ rangeThreshold: Partial;
fillArea: boolean;
+ fillAreaOpacity: number;
+ showLine: boolean;
+ step: boolean;
+ stepType: LineSeriesStepType;
+ smooth: boolean;
+ lineType: TimeSeriesChartLineType;
+ lineWidth: number;
+ showPoints: boolean;
+ showPointLabel: boolean;
+ pointLabelPosition: SeriesLabelPosition;
+ pointLabelFont: Font;
+ pointLabelColor: string;
+ enablePointLabelBackground: boolean;
+ pointLabelBackground: string;
+ pointShape: EChartsShape;
+ pointSize: number;
+ yAxis: TimeSeriesChartYAxisSettings;
+ xAxis: TimeSeriesChartXAxisSettings;
+ animation: TimeSeriesChartAnimationSettings;
+ thresholds: TimeSeriesChartThreshold[];
showLegend: boolean;
legendPosition: LegendPosition;
legendLabelFont: Font;
legendLabelColor: string;
background: BackgroundSettings;
+ padding: string;
}
export const rangeChartDefaultSettings: RangeChartWidgetSettings = {
@@ -48,7 +105,51 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = {
{from: 40, color: '#D81838'}
],
outOfRangeColor: '#ccc',
+ showRangeThresholds: true,
+ rangeThreshold: mergeDeep({} as Partial,
+ timeSeriesChartThresholdDefaultSettings,
+ { lineColor: '#37383b',
+ lineType: TimeSeriesChartLineType.dashed,
+ startSymbol: EChartsShape.circle,
+ startSymbolSize: 5,
+ endSymbol: EChartsShape.arrow,
+ endSymbolSize: 7,
+ labelPosition: ThresholdLabelPosition.insideEndTop,
+ labelColor: '#37383b',
+ enableLabelBackground: true}),
fillArea: true,
+ fillAreaOpacity: 0.7,
+ showLine: true,
+ step: false,
+ stepType: LineSeriesStepType.start,
+ smooth: false,
+ lineType: TimeSeriesChartLineType.solid,
+ lineWidth: 2,
+ showPoints: false,
+ showPointLabel: false,
+ pointLabelPosition: SeriesLabelPosition.top,
+ pointLabelFont: {
+ family: 'Roboto',
+ size: 11,
+ sizeUnit: 'px',
+ style: 'normal',
+ weight: '400',
+ lineHeight: '1'
+ },
+ pointLabelColor: timeSeriesChartColorScheme['series.label'].light,
+ enablePointLabelBackground: false,
+ pointLabelBackground: 'rgba(255,255,255,0.56)',
+ pointShape: EChartsShape.emptyCircle,
+ pointSize: 4,
+ yAxis: mergeDeep({} as TimeSeriesChartYAxisSettings,
+ defaultTimeSeriesChartYAxisSettings,
+ { id: 'default', order: 0, showLine: false, showTicks: false } as TimeSeriesChartYAxisSettings),
+ xAxis: mergeDeep({} as TimeSeriesChartXAxisSettings,
+ defaultTimeSeriesChartXAxisSettings,
+ {showSplitLines: false} as TimeSeriesChartXAxisSettings),
+ animation: mergeDeep({} as TimeSeriesChartAnimationSettings,
+ timeSeriesChartAnimationDefaultSettings),
+ thresholds: [],
showLegend: true,
legendPosition: LegendPosition.top,
legendLabelFont: {
@@ -92,5 +193,149 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = {
color: 'rgba(255,255,255,0.72)',
blur: 3
}
+ },
+ padding: '12px'
+};
+
+export const rangeChartTimeSeriesSettings = (settings: RangeChartWidgetSettings, rangeItems: RangeItem[],
+ decimals: number, units: string): DeepPartial => {
+ let thresholds: DeepPartial[] = settings.showRangeThresholds ? getMarkPoints(rangeItems).map(item => ({
+ ...{type: TimeSeriesChartThresholdType.constant,
+ yAxisId: 'default',
+ units,
+ decimals,
+ value: item},
+ ...settings.rangeThreshold
+ } as DeepPartial)) : [];
+ if (settings.thresholds?.length) {
+ thresholds = thresholds.concat(settings.thresholds);
+ }
+ return {
+ dataZoom: settings.dataZoom,
+ thresholds,
+ yAxes: {
+ default: {
+ ...settings.yAxis,
+ ...{
+ decimals,
+ units
+ }
+ }
+ },
+ xAxis: settings.xAxis,
+ animation: settings.animation,
+ visualMapSettings: {
+ outOfRangeColor: settings.outOfRangeColor,
+ pieces: rangeItems.map(item => item.piece)
+ },
+ showTooltip: settings.showTooltip,
+ tooltipValueFont: settings.tooltipValueFont,
+ tooltipValueColor: settings.tooltipValueColor,
+ tooltipShowDate: settings.tooltipShowDate,
+ tooltipDateInterval: settings.tooltipDateInterval,
+ tooltipDateFormat: settings.tooltipDateFormat,
+ tooltipDateFont: settings.tooltipDateFont,
+ tooltipDateColor: settings.tooltipDateColor,
+ tooltipBackgroundColor: settings.tooltipBackgroundColor,
+ tooltipBackgroundBlur: settings.tooltipBackgroundBlur,
+ };
+};
+
+export const rangeChartTimeSeriesKeySettings = (settings: RangeChartWidgetSettings): DeepPartial => ({
+ type: TimeSeriesChartSeriesType.line,
+ lineSettings: {
+ showLine: settings.showLine,
+ step: settings.step,
+ stepType: settings.stepType,
+ smooth: settings.smooth,
+ lineType: settings.lineType,
+ lineWidth: settings.lineWidth,
+ showPoints: settings.showPoints,
+ showPointLabel: settings.showPointLabel,
+ pointLabelPosition: settings.pointLabelPosition,
+ pointLabelFont: settings.pointLabelFont,
+ pointLabelColor: settings.pointLabelColor,
+ enablePointLabelBackground: settings.enablePointLabelBackground,
+ pointLabelBackground: settings.pointLabelBackground,
+ pointShape: settings.pointShape,
+ pointSize: settings.pointSize,
+ fillAreaSettings: {
+ type: settings.fillArea ? SeriesFillType.opacity : SeriesFillType.none,
+ opacity: settings.fillAreaOpacity
+ }
+ }
+ });
+
+export const toRangeItems = (colorRanges: Array): RangeItem[] => {
+ const rangeItems: RangeItem[] = [];
+ let counter = 0;
+ const ranges = sortedColorRange(filterIncludingColorRanges(colorRanges)).filter(r => isNumber(r.from) || isNumber(r.to));
+ for (let i = 0; i < ranges.length; i++) {
+ const range = ranges[i];
+ let from = range.from;
+ const to = range.to;
+ if (i > 0) {
+ const prevRange = ranges[i - 1];
+ if (isNumber(prevRange.to) && isNumber(from) && from < prevRange.to) {
+ from = prevRange.to;
+ }
+ }
+ rangeItems.push(
+ {
+ index: counter++,
+ color: range.color,
+ enabled: true,
+ visible: true,
+ from,
+ to,
+ label: rangeItemLabel(from, to),
+ piece: createTimeSeriesChartVisualMapPiece(range.color, from, to)
+ }
+ );
+ if (!isNumber(from) || !isNumber(to)) {
+ const value = !isNumber(from) ? to : from;
+ rangeItems.push(
+ {
+ index: counter++,
+ color: 'transparent',
+ enabled: true,
+ visible: false,
+ label: '',
+ piece: { gt: value - 0.000000001, lt: value + 0.000000001, color: 'transparent'}
+ }
+ );
+ }
+ }
+ return rangeItems;
+};
+
+const rangeItemLabel = (from?: number, to?: number): string => {
+ if (isNumber(from) && isNumber(to)) {
+ if (from === to) {
+ return `${from}`;
+ } else {
+ return `${from} - ${to}`;
+ }
+ } else if (isNumber(from)) {
+ return `≥ ${from}`;
+ } else if (isNumber(to)) {
+ return `< ${to}`;
+ } else {
+ return null;
+ }
+};
+
+const getMarkPoints = (ranges: Array): number[] => {
+ const points = new Set();
+ for (const range of ranges) {
+ if (range.visible) {
+ if (isNumber(range.from)) {
+ points.add(range.from);
+ }
+ if (isNumber(range.to)) {
+ points.add(range.to);
+ }
+ }
}
+ return Array.from(points).sort();
};
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts
index c00a078b2f..ee3c703a17 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts
@@ -22,7 +22,7 @@ import {
TimeSeriesChartNoAggregationBarWidthStrategy
} from '@home/components/widget/lib/chart/time-series-chart.models';
import { CustomSeriesRenderItemParams } from 'echarts';
-import { CustomSeriesRenderItemAPI, CustomSeriesRenderItemReturn } from 'echarts/types/dist/shared';
+import { CallbackDataParams, CustomSeriesRenderItemAPI, CustomSeriesRenderItemReturn } from 'echarts/types/dist/shared';
import { isNumeric } from '@core/utils';
import * as echarts from 'echarts/core';
@@ -34,6 +34,8 @@ export interface BarVisualSettings {
}
export interface BarRenderSharedContext {
+ barGap: number;
+ intervalGap: number;
timeInterval: Interval;
noAggregationBarWidthStrategy: TimeSeriesChartNoAggregationBarWidthStrategy;
noAggregationWidthRelative: boolean;
@@ -47,6 +49,7 @@ export interface BarRenderContext {
noAggregation?: boolean;
visualSettings?: BarVisualSettings;
labelOption?: SeriesLabelOption;
+ additionalLabelOption?: {[key: string]: any};
barStackIndex?: number;
currentStackItems?: TimeSeriesChartDataItem[];
}
@@ -77,10 +80,13 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
start = time - interval / 2;
}
- const gap = 0.3;
- const barInterval = separateBar ? interval : interval / (renderCtx.barsCount + gap * (renderCtx.barsCount + 3));
- const intervalGap = barInterval * gap * 2;
- const barGap = barInterval * gap;
+ const barGapRatio = renderCtx.shared.barGap;
+ const intervalGapRatio = renderCtx.shared.intervalGap;
+ const barInterval = separateBar
+ ? interval
+ : interval / (renderCtx.barsCount + barGapRatio * (renderCtx.barsCount - 1) + intervalGapRatio * 2);
+ const intervalGap = barInterval * intervalGapRatio;
+ const barGap = barInterval * barGapRatio;
const value = api.value(1);
const startTime = separateBar ? start : start + intervalGap + (barInterval + barGap) * renderCtx.barIndex;
const delta = barInterval;
@@ -124,7 +130,7 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
const zeroPos = api.coord([0, offset]);
- const style: any = {
+ let style: any = {
fill: renderCtx.visualSettings.color,
stroke: renderCtx.visualSettings.borderColor,
lineWidth: renderCtx.visualSettings.borderWidth
@@ -139,10 +145,20 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
position = 'top';
}
}
- style.text = (renderCtx.labelOption.formatter as LabelFormatterCallback)({value: [null, value]} as any);
+ style.text = (renderCtx.labelOption.formatter as LabelFormatterCallback)(
+ {
+ seriesName: params.seriesName,
+ value: [null, value]
+ } as CallbackDataParams);
style.textDistance = 5;
style.textPosition = position;
+ style.textBackgroundColor = renderCtx.labelOption.backgroundColor;
+ style.textPadding = renderCtx.labelOption.padding;
+ style.textBorderRadius = renderCtx.labelOption.borderRadius;
style.rich = renderCtx.labelOption.rich;
+ if (renderCtx.additionalLabelOption) {
+ style = {...style, ...renderCtx.additionalLabelOption};
+ }
}
let borderRadius: number[];
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
index e931349bca..3589d69d4f 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
@@ -17,10 +17,11 @@
import {
ECharts,
EChartsOption,
- EChartsSeriesItem,
+ EChartsSeriesItem, EChartsShape,
EChartsTooltipTrigger,
EChartsTooltipWidgetSettings,
- measureThresholdLabelOffset, timeAxisBandWidthCalculator
+ measureThresholdOffset,
+ timeAxisBandWidthCalculator
} from '@home/components/widget/lib/chart/echarts-widget.models';
import {
autoDateFormat,
@@ -30,12 +31,17 @@ import {
textStyle,
tsToFormatTimeUnit
} from '@shared/models/widget-settings.models';
-import { XAXisOption, YAXisOption } from 'echarts/types/dist/shared';
+import {
+ LabelLayoutOptionCallback,
+ VisualMapComponentOption,
+ XAXisOption,
+ YAXisOption
+} from 'echarts/types/dist/shared';
import { CustomSeriesOption, LineSeriesOption } from 'echarts/charts';
import {
formatValue,
isDefinedAndNotNull,
- isFunction,
+ isFunction, isNumber,
isNumeric,
isUndefined,
isUndefinedOrNull,
@@ -45,7 +51,7 @@ import {
import { LinearGradientObject } from 'zrender/lib/graphic/LinearGradient';
import tinycolor from 'tinycolor2';
import { ValueAxisBaseOption } from 'echarts/types/src/coord/axisCommonTypes';
-import { SeriesLabelOption } from 'echarts/types/src/util/types';
+import { LabelFormatterCallback, LabelLayoutOption, SeriesLabelOption } from 'echarts/types/src/util/types';
import {
BarRenderContext,
BarRenderSharedContext,
@@ -58,6 +64,7 @@ import { TbColorScheme } from '@shared/models/color.models';
import { AbstractControl, ValidationErrors } from '@angular/forms';
import { MarkLine2DDataItemOption } from 'echarts/types/src/component/marker/MarkLineModel';
import { DatePipe } from '@angular/common';
+import { BuiltinTextPosition } from 'zrender/src/core/types';
export enum TimeSeriesChartType {
default = 'default',
@@ -74,7 +81,7 @@ export const timeSeriesChartTypeTranslations = new Map(
]
);
-export enum TimeSeriesChartShape {
- emptyCircle = 'emptyCircle',
- circle = 'circle',
- rect = 'rect',
- roundRect = 'roundRect',
- triangle = 'triangle',
- diamond = 'diamond',
- pin = 'pin',
- arrow = 'arrow',
- none = 'none'
-}
-
-export const timeSeriesChartShapes = Object.keys(TimeSeriesChartShape) as TimeSeriesChartShape[];
-
-export const timeSeriesChartShapeTranslations = new Map(
- [
- [TimeSeriesChartShape.emptyCircle, 'widgets.time-series-chart.shape-empty-circle'],
- [TimeSeriesChartShape.circle, 'widgets.time-series-chart.shape-circle'],
- [TimeSeriesChartShape.rect, 'widgets.time-series-chart.shape-rect'],
- [TimeSeriesChartShape.roundRect, 'widgets.time-series-chart.shape-round-rect'],
- [TimeSeriesChartShape.triangle, 'widgets.time-series-chart.shape-triangle'],
- [TimeSeriesChartShape.diamond, 'widgets.time-series-chart.shape-diamond'],
- [TimeSeriesChartShape.pin, 'widgets.time-series-chart.shape-pin'],
- [TimeSeriesChartShape.arrow, 'widgets.time-series-chart.shape-arrow'],
- [TimeSeriesChartShape.none, 'widgets.time-series-chart.shape-none']
- ]
-);
-
export enum TimeSeriesChartLineType {
solid = 'solid',
dashed = 'dashed',
@@ -401,6 +380,38 @@ export const defaultTimeSeriesChartYAxisSettings: TimeSeriesChartYAxisSettings =
splitLinesColor: timeSeriesChartColorScheme['axis.splitLine'].light
};
+export const defaultTimeSeriesChartXAxisSettings: TimeSeriesChartXAxisSettings = {
+ show: true,
+ label: '',
+ labelFont: {
+ family: 'Roboto',
+ size: 12,
+ sizeUnit: 'px',
+ style: 'normal',
+ weight: '600',
+ lineHeight: '1'
+ },
+ labelColor: timeSeriesChartColorScheme['axis.label'].light,
+ position: AxisPosition.bottom,
+ showTickLabels: true,
+ tickLabelFont: {
+ family: 'Roboto',
+ size: 10,
+ sizeUnit: 'px',
+ style: 'normal',
+ weight: '400',
+ lineHeight: '1'
+ },
+ tickLabelColor: timeSeriesChartColorScheme['axis.tickLabel'].light,
+ ticksFormat: {},
+ showTicks: true,
+ ticksColor: timeSeriesChartColorScheme['axis.ticks'].light,
+ showLine: true,
+ lineColor: timeSeriesChartColorScheme['axis.line'].light,
+ showSplitLines: true,
+ splitLinesColor: timeSeriesChartColorScheme['axis.splitLine'].light
+};
+
export type TimeSeriesChartYAxes = {[id: TimeSeriesChartYAxisId]: TimeSeriesChartYAxisSettings};
export interface TimeSeriesChartThreshold {
@@ -415,16 +426,19 @@ export interface TimeSeriesChartThreshold {
units?: string;
decimals?: number;
lineColor: string;
- lineType: TimeSeriesChartLineType;
+ lineType: TimeSeriesChartLineType | number | number[];
lineWidth: number;
- startSymbol: TimeSeriesChartShape;
+ startSymbol: EChartsShape;
startSymbolSize: number;
- endSymbol: TimeSeriesChartShape;
+ endSymbol: EChartsShape;
endSymbolSize: number;
showLabel: boolean;
labelPosition: ThresholdLabelPosition;
labelFont: Font;
labelColor: string;
+ enableLabelBackground: boolean;
+ labelBackground: string;
+ additionalLabelOption?: {[key: string]: any};
}
export const timeSeriesChartThresholdValid = (threshold: TimeSeriesChartThreshold): boolean => {
@@ -469,9 +483,9 @@ export const timeSeriesChartThresholdDefaultSettings: TimeSeriesChartThreshold =
lineColor: timeSeriesChartColorScheme['threshold.line'].light,
lineType: TimeSeriesChartLineType.solid,
lineWidth: 1,
- startSymbol: TimeSeriesChartShape.none,
+ startSymbol: EChartsShape.none,
startSymbolSize: 5,
- endSymbol: TimeSeriesChartShape.arrow,
+ endSymbol: EChartsShape.arrow,
endSymbolSize: 5,
showLabel: true,
labelPosition: ThresholdLabelPosition.end,
@@ -483,7 +497,9 @@ export const timeSeriesChartThresholdDefaultSettings: TimeSeriesChartThreshold =
weight: '400',
lineHeight: '1'
},
- labelColor: timeSeriesChartColorScheme['threshold.label'].light
+ labelColor: timeSeriesChartColorScheme['threshold.label'].light,
+ enableLabelBackground: false,
+ labelBackground: 'rgba(255,255,255,0.56)'
};
export enum TimeSeriesChartNoAggregationBarWidthStrategy {
@@ -513,6 +529,25 @@ export interface TimeSeriesChartNoAggregationBarWidthSettings {
barWidth?: TimeSeriesChartBarWidth;
}
+export const timeSeriesChartNoAggregationBarWidthDefaultSettings: TimeSeriesChartNoAggregationBarWidthSettings = {
+ strategy: TimeSeriesChartNoAggregationBarWidthStrategy.group,
+ groupWidth: {
+ relative: true,
+ relativeWidth: 2,
+ absoluteWidth: 1000
+ },
+ barWidth: {
+ relative: true,
+ relativeWidth: 2,
+ absoluteWidth: 1000
+ }
+};
+
+export interface TimeSeriesChartBarWidthSettings {
+ barGap: number;
+ intervalGap: number;
+}
+
export enum TimeSeriesChartAnimationEasing {
linear = 'linear',
quadraticIn = 'quadraticIn',
@@ -560,6 +595,50 @@ export interface TimeSeriesChartAnimationSettings {
animationDelayUpdate: number;
}
+export const timeSeriesChartAnimationDefaultSettings: TimeSeriesChartAnimationSettings = {
+ animation: true,
+ animationThreshold: 2000,
+ animationDuration: 500,
+ animationEasing: TimeSeriesChartAnimationEasing.cubicOut,
+ animationDelay: 0,
+ animationDurationUpdate: 300,
+ animationEasingUpdate: TimeSeriesChartAnimationEasing.cubicOut,
+ animationDelayUpdate: 0
+};
+
+export interface TimeSeriesChartVisualMapPiece {
+ lt?: number;
+ gt?: number;
+ lte?: number;
+ gte?: number;
+ value?: number;
+ color?: string;
+}
+
+export const createTimeSeriesChartVisualMapPiece = (color: string, from?: number, to?: number): TimeSeriesChartVisualMapPiece => {
+ const piece: TimeSeriesChartVisualMapPiece = {
+ color
+ };
+ if (isNumber(from) && isNumber(to)) {
+ if (from === to) {
+ piece.value = from;
+ } else {
+ piece.gte = from;
+ piece.lt = to;
+ }
+ } else if (isNumber(from)) {
+ piece.gte = from;
+ } else if (isNumber(to)) {
+ piece.lt = to;
+ }
+ return piece;
+};
+
+export interface TimeSeriesChartVisualMapSettings {
+ outOfRangeColor: string;
+ pieces: TimeSeriesChartVisualMapPiece[];
+}
+
export interface TimeSeriesChartSettings extends EChartsTooltipWidgetSettings {
thresholds: TimeSeriesChartThreshold[];
darkMode: boolean;
@@ -568,7 +647,9 @@ export interface TimeSeriesChartSettings extends EChartsTooltipWidgetSettings {
yAxes: TimeSeriesChartYAxes;
xAxis: TimeSeriesChartXAxisSettings;
animation: TimeSeriesChartAnimationSettings;
+ barWidthSettings: TimeSeriesChartBarWidthSettings;
noAggregationBarWidthSettings: TimeSeriesChartNoAggregationBarWidthSettings;
+ visualMapSettings?: TimeSeriesChartVisualMapSettings;
}
export const timeSeriesChartDefaultSettings: TimeSeriesChartSettings = {
@@ -581,60 +662,16 @@ export const timeSeriesChartDefaultSettings: TimeSeriesChartSettings = {
defaultTimeSeriesChartYAxisSettings,
{ id: 'default', order: 0 } as TimeSeriesChartYAxisSettings)
},
- xAxis: {
- show: true,
- label: '',
- labelFont: {
- family: 'Roboto',
- size: 12,
- sizeUnit: 'px',
- style: 'normal',
- weight: '600',
- lineHeight: '1'
- },
- labelColor: timeSeriesChartColorScheme['axis.label'].light,
- position: AxisPosition.bottom,
- showTickLabels: true,
- tickLabelFont: {
- family: 'Roboto',
- size: 10,
- sizeUnit: 'px',
- style: 'normal',
- weight: '400',
- lineHeight: '1'
- },
- tickLabelColor: timeSeriesChartColorScheme['axis.tickLabel'].light,
- ticksFormat: {},
- showTicks: true,
- ticksColor: timeSeriesChartColorScheme['axis.ticks'].light,
- showLine: true,
- lineColor: timeSeriesChartColorScheme['axis.line'].light,
- showSplitLines: true,
- splitLinesColor: timeSeriesChartColorScheme['axis.splitLine'].light
- },
- animation: {
- animation: true,
- animationThreshold: 2000,
- animationDuration: 500,
- animationEasing: TimeSeriesChartAnimationEasing.cubicOut,
- animationDelay: 0,
- animationDurationUpdate: 300,
- animationEasingUpdate: TimeSeriesChartAnimationEasing.cubicOut,
- animationDelayUpdate: 0
- },
- noAggregationBarWidthSettings: {
- strategy: TimeSeriesChartNoAggregationBarWidthStrategy.group,
- groupWidth: {
- relative: true,
- relativeWidth: 2,
- absoluteWidth: 1000
- },
- barWidth: {
- relative: true,
- relativeWidth: 2,
- absoluteWidth: 1000
- }
+ xAxis: mergeDeep({} as TimeSeriesChartXAxisSettings,
+ defaultTimeSeriesChartXAxisSettings),
+ animation: mergeDeep({} as TimeSeriesChartAnimationSettings,
+ timeSeriesChartAnimationDefaultSettings),
+ barWidthSettings: {
+ barGap: 0.3,
+ intervalGap: 0.6
},
+ noAggregationBarWidthSettings: mergeDeep({} as TimeSeriesChartNoAggregationBarWidthSettings,
+ timeSeriesChartNoAggregationBarWidthDefaultSettings),
showTooltip: true,
tooltipTrigger: EChartsTooltipTrigger.axis,
tooltipValueFont: {
@@ -683,7 +720,10 @@ export interface LineSeriesSettings {
pointLabelPosition: SeriesLabelPosition;
pointLabelFont: Font;
pointLabelColor: string;
- pointShape: TimeSeriesChartShape;
+ enablePointLabelBackground: boolean;
+ pointLabelBackground: string;
+ pointLabelFormatter?: string | LabelFormatterCallback;
+ pointShape: EChartsShape;
pointSize: number;
fillAreaSettings: SeriesFillSettings;
}
@@ -693,9 +733,14 @@ export interface BarSeriesSettings {
borderWidth: number;
borderRadius: number;
showLabel: boolean;
- labelPosition: SeriesLabelPosition;
+ labelPosition: SeriesLabelPosition | BuiltinTextPosition;
labelFont: Font;
labelColor: string;
+ enableLabelBackground: boolean;
+ labelBackground: string;
+ labelFormatter?: string | LabelFormatterCallback;
+ labelLayout?: LabelLayoutOption | LabelLayoutOptionCallback;
+ additionalLabelOption?: {[key: string]: any};
backgroundSettings: SeriesFillSettings;
}
@@ -732,7 +777,9 @@ export const timeSeriesChartKeyDefaultSettings: TimeSeriesChartKeySettings = {
lineHeight: '1'
},
pointLabelColor: timeSeriesChartColorScheme['series.label'].light,
- pointShape: TimeSeriesChartShape.emptyCircle,
+ enablePointLabelBackground: false,
+ pointLabelBackground: 'rgba(255,255,255,0.56)',
+ pointShape: EChartsShape.emptyCircle,
pointSize: 4,
fillAreaSettings: {
type: SeriesFillType.none,
@@ -758,6 +805,8 @@ export const timeSeriesChartKeyDefaultSettings: TimeSeriesChartKeySettings = {
lineHeight: '1'
},
labelColor: timeSeriesChartColorScheme['series.label'].light,
+ enableLabelBackground: false,
+ labelBackground: 'rgba(255,255,255,0.56)',
backgroundSettings: {
type: SeriesFillType.none,
opacity: 0.4,
@@ -944,7 +993,12 @@ export const createTimeSeriesXAxisOption = (settings: TimeSeriesChartXAxisSettin
fontFamily: xAxisTickLabelStyle.fontFamily,
fontSize: xAxisTickLabelStyle.fontSize,
hideOverlap: true,
- formatter: (value: number, index: number, extra: {level: number}) => {
+ /** Min/Max time label always visible **/
+ /* alignMinLabel: 'left',
+ alignMaxLabel: 'right',
+ showMinLabel: true,
+ showMaxLabel: true, */
+ formatter: (value: number, _index: number, extra: {level: number}) => {
const unit = tsToFormatTimeUnit(value);
const format = ticksFormat[unit];
const formatted = datePipe.transform(value, format);
@@ -974,6 +1028,21 @@ export const createTimeSeriesXAxisOption = (settings: TimeSeriesChartXAxisSettin
};
};
+export const createTimeSeriesVisualMapOption = (settings: TimeSeriesChartVisualMapSettings,
+ selectedRanges: {[key: number]: boolean}): VisualMapComponentOption => ({
+ show: false,
+ type: 'piecewise',
+ selected: selectedRanges,
+ dimension: 1,
+ pieces: settings.pieces,
+ outOfRange: {
+ color: settings.outOfRangeColor
+},
+ inRange: !settings.pieces.length ? {
+ color: settings.outOfRangeColor
+ } : undefined
+});
+
export const generateChartData = (dataItems: TimeSeriesChartDataItem[],
thresholdItems: TimeSeriesChartThresholdItem[],
stack: boolean,
@@ -983,7 +1052,7 @@ export const generateChartData = (dataItems: TimeSeriesChartDataItem[],
let series = generateChartSeries(dataItems,
stack, noAggregation, barRenderSharedContext, darkMode);
if (thresholdItems.length) {
- const thresholds = generateChartThresholds(thresholdItems, darkMode);
+ const thresholds = generateChartThresholds(thresholdItems);
series = series.concat(thresholds);
}
return series;
@@ -995,7 +1064,7 @@ export const calculateThresholdsOffset = (chart: ECharts,
const result: [number, number] = [0, 0];
for (const item of thresholdItems) {
const yAxis = yAxisList[item.yAxisIndex];
- const offset = measureThresholdLabelOffset(chart, yAxis.id, item.id, item.value);
+ const offset = measureThresholdOffset(chart, yAxis.id, item.id, item.value);
result[0] = Math.max(result[0], offset[0]);
result[1] = Math.max(result[1], offset[1]);
}
@@ -1017,7 +1086,7 @@ export const parseThresholdData = (value: any): TimeSeriesChartThresholdValue =>
return thresholdValue;
};
-const generateChartThresholds = (thresholdItems: TimeSeriesChartThresholdItem[], darkMode: boolean): Array => {
+const generateChartThresholds = (thresholdItems: TimeSeriesChartThresholdItem[]): Array => {
const series: Array = [];
for (const item of thresholdItems) {
if (isDefinedAndNotNull(item.value)) {
@@ -1056,6 +1125,14 @@ const generateChartThresholds = (thresholdItems: TimeSeriesChartThresholdItem[],
}
}
};
+ if (item.settings.enableLabelBackground) {
+ seriesOption.markLine.label.backgroundColor = item.settings.labelBackground;
+ seriesOption.markLine.label.padding = [4, 5];
+ seriesOption.markLine.label.borderRadius = 4;
+ }
+ if (item.settings.additionalLabelOption) {
+ seriesOption.markLine.label = {...seriesOption.markLine.label, ...item.settings.additionalLabelOption};
+ }
item.option = seriesOption;
}
seriesOption.markLine.data = [];
@@ -1131,7 +1208,7 @@ const generateChartSeries = (dataItems: TimeSeriesChartDataItem[],
export const updateDarkMode = (options: EChartsOption, settings: TimeSeriesChartSettings,
yAxisList: TimeSeriesChartYAxis[],
- dataItems: TimeSeriesChartDataItem[], thresholdDataItems: TimeSeriesChartThresholdItem[],
+ dataItems: TimeSeriesChartDataItem[],
darkMode: boolean): EChartsOption => {
options.darkMode = darkMode;
if (Array.isArray(options.yAxis)) {
@@ -1171,7 +1248,7 @@ export const updateDarkMode = (options: EChartsOption, settings: TimeSeriesChart
} else {
if (item.barRenderContext?.labelOption?.show) {
const barSettings = item.dataKey.settings as BarSeriesSettings;
- item.barRenderContext.labelOption.rich.value.color = prepareChartThemeColor(barSettings.labelColor,
+ (item.barRenderContext.labelOption.rich.value as any).fill = prepareChartThemeColor(barSettings.labelColor,
darkMode, 'series.label');
}
}
@@ -1215,7 +1292,10 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
const lineSeriesOption = seriesOption as LineSeriesOption;
lineSeriesOption.type = 'line';
lineSeriesOption.label = createSeriesLabelOption(item, lineSettings.showPointLabel,
- lineSettings.pointLabelFont, lineSettings.pointLabelColor, lineSettings.pointLabelPosition, darkMode);
+ lineSettings.pointLabelFont, lineSettings.pointLabelColor,
+ lineSettings.enablePointLabelBackground, lineSettings.pointLabelBackground,
+ lineSettings.pointLabelPosition,
+ lineSettings.pointLabelFormatter, false, darkMode);
lineSeriesOption.step = lineSettings.step ? lineSettings.stepType : false;
lineSeriesOption.smooth = lineSettings.smooth;
if (lineSettings.smooth) {
@@ -1229,7 +1309,7 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
lineSeriesOption.areaStyle = {};
if (lineSettings.fillAreaSettings.type === SeriesFillType.opacity) {
lineSeriesOption.areaStyle.opacity = lineSettings.fillAreaSettings.opacity;
- } else {
+ } else if (lineSettings.fillAreaSettings.type === SeriesFillType.gradient) {
lineSeriesOption.areaStyle.opacity = 1;
lineSeriesOption.areaStyle.color = createLinearOpacityGradient(seriesColor, lineSettings.fillAreaSettings.gradient);
}
@@ -1256,9 +1336,12 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
}
item.barRenderContext.visualSettings = barVisualSettings;
item.barRenderContext.labelOption = createSeriesLabelOption(item, barSettings.showLabel,
- barSettings.labelFont, barSettings.labelColor, barSettings.labelPosition, darkMode);
+ barSettings.labelFont, barSettings.labelColor, barSettings.enableLabelBackground, barSettings.labelBackground,
+ barSettings.labelPosition, barSettings.labelFormatter, true, darkMode);
+ item.barRenderContext.additionalLabelOption = barSettings.additionalLabelOption;
barSeriesOption.renderItem = (params, api) =>
renderTimeSeriesBar(params, api, item.barRenderContext);
+ barSeriesOption.labelLayout = barSettings.labelLayout;
}
}
seriesOption.data = item.data;
@@ -1266,30 +1349,63 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
};
const createSeriesLabelOption = (item: TimeSeriesChartDataItem, show: boolean,
- labelFont: Font, labelColor: string, position: SeriesLabelPosition,
+ labelFont: Font, labelColor: string,
+ enableBackground: boolean, labelBackground: string,
+ position: SeriesLabelPosition | BuiltinTextPosition,
+ labelFormatter: string | LabelFormatterCallback,
+ labelColorFill: boolean,
darkMode: boolean): SeriesLabelOption => {
let labelStyle: ComponentStyle = {};
if (show) {
- labelStyle = createChartTextStyle(labelFont, labelColor, darkMode, 'series.label');
+ labelStyle = createChartTextStyle(labelFont, labelColor, darkMode, 'series.label', labelColorFill);
}
- return {
- show,
- position,
- formatter: (params): string => {
+ let formatter: LabelFormatterCallback;
+ if (isFunction(labelFormatter)) {
+ formatter = labelFormatter as LabelFormatterCallback;
+ } else if (labelFormatter?.length) {
+ const formatFunction = parseFunction(labelFormatter, ['value']);
+ formatter = (params): string => {
+ let result: string;
+ try {
+ result = formatFunction(params.value[1]);
+ } catch (_e) {
+ }
+ if (isUndefined(result)) {
+ result = formatValue(params.value[1], item.decimals, item.units, false);
+ }
+ return `{value|${result}}`;
+ };
+ } else {
+ formatter = (params): string => {
const value = formatValue(params.value[1], item.decimals, item.units, false);
return `{value|${value}}`;
- },
+ };
+ }
+ const labelOption: SeriesLabelOption = {
+ show,
+ position,
+ formatter,
rich: {
value: labelStyle
}
};
+ if (enableBackground) {
+ labelOption.backgroundColor = labelBackground;
+ labelOption.padding = [4, 5];
+ labelOption.borderRadius = 4;
+ }
+ return labelOption;
};
-const createChartTextStyle = (font: Font, color: string, darkMode: boolean, colorKey?: string): ComponentStyle => {
+const createChartTextStyle = (font: Font, color: string, darkMode: boolean, colorKey?: string, fill = false): ComponentStyle => {
const style = textStyle(font);
delete style.lineHeight;
style.fontSize = font.size;
- style.color = prepareChartThemeColor(color, darkMode, colorKey);
+ if (fill) {
+ style.fill = prepareChartThemeColor(color, darkMode, colorKey);
+ } else {
+ style.color = prepareChartThemeColor(color, darkMode, colorKey);
+ }
return style;
};
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
index bd9005c497..00f2c55d3f 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
@@ -18,6 +18,7 @@ import { WidgetContext } from '@home/models/widget-component.models';
import {
AxisPosition,
calculateThresholdsOffset,
+ createTimeSeriesVisualMapOption,
createTimeSeriesXAxisOption,
createTimeSeriesYAxis,
defaultTimeSeriesChartYAxisSettings,
@@ -31,7 +32,6 @@ import {
TimeSeriesChartNoAggregationBarWidthStrategy,
TimeSeriesChartSeriesType,
TimeSeriesChartSettings,
- TimeSeriesChartShape,
TimeSeriesChartThreshold,
timeSeriesChartThresholdDefaultSettings,
TimeSeriesChartThresholdItem,
@@ -48,10 +48,11 @@ import {
calculateYAxisWidth,
ECharts,
echartsModule,
- EChartsOption,
+ EChartsOption, EChartsShape,
echartsTooltipFormatter,
EChartsTooltipTrigger,
getAxisExtent,
+ getFocusedSeriesIndex,
measureXAxisNameHeight,
measureYAxisNameWidth,
toNamedData
@@ -60,7 +61,7 @@ import { DateFormatProcessor } from '@shared/models/widget-settings.models';
import { isDefinedAndNotNull, isEqual, mergeDeep } from '@core/utils';
import { DataKey, Datasource, DatasourceType, widgetType } from '@shared/models/widget.models';
import * as echarts from 'echarts/core';
-import { CallbackDataParams } from 'echarts/types/dist/shared';
+import { CallbackDataParams, PiecewiseVisualMapOption } from 'echarts/types/dist/shared';
import { Renderer2 } from '@angular/core';
import { CustomSeriesOption, LineSeriesOption } from 'echarts/charts';
import { BehaviorSubject } from 'rxjs';
@@ -86,7 +87,7 @@ export class TbTimeSeriesChart {
settings.type = TimeSeriesChartSeriesType.line;
settings.lineSettings.showLine = false;
settings.lineSettings.showPoints = true;
- settings.lineSettings.pointShape = TimeSeriesChartShape.circle;
+ settings.lineSettings.pointShape = EChartsShape.circle;
settings.lineSettings.pointSize = 8;
}
return settings;
@@ -107,6 +108,9 @@ export class TbTimeSeriesChart {
private dataItems: TimeSeriesChartDataItem[] = [];
private thresholdItems: TimeSeriesChartThresholdItem[] = [];
+ private hasVisualMap = false;
+ private visualMapSelectedRanges: {[key: number]: boolean};
+
private timeSeriesChart: ECharts;
private timeSeriesChartOptions: EChartsOption;
@@ -145,6 +149,7 @@ export class TbTimeSeriesChart {
this.setupYAxes();
this.setupData();
this.setupThresholds();
+ this.setupVisualMap();
if (this.settings.showTooltip && this.settings.tooltipShowDate) {
this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.tooltipDateFormat);
}
@@ -186,6 +191,9 @@ export class TbTimeSeriesChart {
} else {
this.timeSeriesChartOptions.tooltip[0].axisPointer.type = 'shadow';
}
+ if (this.hasVisualMap) {
+ (this.timeSeriesChartOptions.visualMap as PiecewiseVisualMapOption).selected = this.visualMapSelectedRanges;
+ }
this.barRenderSharedContext.timeInterval = this.ctx.timeWindow.interval;
this.updateSeriesData(true);
if (this.highlightedDataKey) {
@@ -263,6 +271,16 @@ export class TbTimeSeriesChart {
}
}
+ public toggleVisualMapRange(index: number): void {
+ if (this.hasVisualMap) {
+ this.visualMapSelectedRanges[index] = !this.visualMapSelectedRanges[index];
+ this.timeSeriesChart.dispatchAction({
+ type: 'selectDataRange',
+ selected: this.visualMapSelectedRanges
+ });
+ }
+ }
+
public destroy(): void {
if (this.shapeResize$) {
this.shapeResize$.disconnect();
@@ -284,8 +302,7 @@ export class TbTimeSeriesChart {
this.darkMode = darkMode;
if (this.timeSeriesChart) {
this.timeSeriesChartOptions = updateDarkMode(this.timeSeriesChartOptions,
- this.settings, this.yAxisList, this.dataItems,
- this.thresholdItems, darkMode);
+ this.settings, this.yAxisList, this.dataItems, darkMode);
this.timeSeriesChart.setOption(this.timeSeriesChartOptions);
}
}
@@ -300,6 +317,8 @@ export class TbTimeSeriesChart {
const targetBarWidth = noAggregationBarWidthSettings.strategy === TimeSeriesChartNoAggregationBarWidthStrategy.group ?
noAggregationBarWidthSettings.groupWidth : noAggregationBarWidthSettings.barWidth;
this.barRenderSharedContext = {
+ barGap: this.settings.barWidthSettings.barGap,
+ intervalGap: this.settings.barWidthSettings.intervalGap,
timeInterval: this.ctx.timeWindow?.interval,
noAggregationBarWidthStrategy: noAggregationBarWidthSettings.strategy,
noAggregationWidthRelative: targetBarWidth.relative,
@@ -313,7 +332,10 @@ export class TbTimeSeriesChart {
timeSeriesChartKeyDefaultSettings, dataKey.settings);
if ((keySettings.type === TimeSeriesChartSeriesType.line && keySettings.lineSettings.showPointLabel &&
keySettings.lineSettings.pointLabelPosition === SeriesLabelPosition.top) ||
- (keySettings.type === TimeSeriesChartSeriesType.bar && keySettings.barSettings.showLabel)) {
+ (keySettings.type === TimeSeriesChartSeriesType.bar &&
+ keySettings.barSettings.showLabel &&
+ [SeriesLabelPosition.top, SeriesLabelPosition.bottom]
+ .includes(keySettings.barSettings.labelPosition as SeriesLabelPosition))) {
this.topPointLabels = true;
}
dataKey.settings = keySettings;
@@ -346,6 +368,11 @@ export class TbTimeSeriesChart {
for (const thresholdSettings of this.settings.thresholds) {
const threshold = mergeDeep({} as TimeSeriesChartThreshold,
timeSeriesChartThresholdDefaultSettings, thresholdSettings);
+ if (!this.topPointLabels) {
+ if (threshold.showLabel && !threshold.labelPosition.endsWith('Bottom')) {
+ this.topPointLabels = true;
+ }
+ }
let latestDataKey: DataKey = null;
let entityDataKey: DataKey = null;
let value = null;
@@ -429,6 +456,15 @@ export class TbTimeSeriesChart {
}
}
+ private setupVisualMap(): void {
+ if (this.settings.visualMapSettings?.pieces && this.settings.visualMapSettings?.pieces.length) {
+ this.hasVisualMap = true;
+ this.visualMapSelectedRanges = {};
+ this.settings.visualMapSettings.pieces.forEach((_val, index) => {
+ this.visualMapSelectedRanges[index] = true;
+ });
+ }
+ }
private nextComponentId(): string {
return (this.componentIndexCounter++) + '';
@@ -492,8 +528,9 @@ export class TbTimeSeriesChart {
},
formatter: (params: CallbackDataParams[]) =>
this.settings.showTooltip ? echartsTooltipFormatter(this.renderer, this.tooltipDateFormat,
- this.settings, params, 0, '', -1, this.dataItems,
- this.noAggregation ? null : this.ctx.timeWindow.interval) : undefined,
+ this.settings, params, 0, '',
+ this.settings.tooltipShowFocusedSeries ? getFocusedSeriesIndex(this.timeSeriesChart) : -1,
+ this.dataItems, this.noAggregation ? null : this.ctx.timeWindow.interval) : undefined,
padding: [8, 12],
backgroundColor: this.settings.tooltipBackgroundColor,
borderWidth: 0,
@@ -533,6 +570,10 @@ export class TbTimeSeriesChart {
animationEasingUpdate: this.settings.animation.animationEasingUpdate,
animationDelayUpdate: this.settings.animation.animationDelayUpdate
};
+ if (this.hasVisualMap) {
+ this.timeSeriesChartOptions.visualMap =
+ createTimeSeriesVisualMapOption(this.settings.visualMapSettings, this.visualMapSelectedRanges);
+ }
this.timeSeriesChartOptions.xAxis[0].tbTimeWindow = this.ctx.defaultSubscription.timeWindow;
@@ -542,7 +583,7 @@ export class TbTimeSeriesChart {
}
this.timeSeriesChart.setOption(this.timeSeriesChartOptions);
- this.updateAxes();
+ this.updateAxes(false);
if (this.settings.dataZoom) {
this.timeSeriesChart.on('datazoom', () => {
@@ -567,7 +608,7 @@ export class TbTimeSeriesChart {
this.barRenderSharedContext, this.darkMode);
}
- private updateAxes() {
+ private updateAxes(lazy = true) {
const leftAxisList = this.yAxisList.filter(axis => axis.option.position === 'left');
let res = this.updateYAxisOffset(leftAxisList);
let leftOffset = res.offset + (!res.offset && this.settings.dataZoom ? 5 : 0);
@@ -617,7 +658,7 @@ export class TbTimeSeriesChart {
}
if (changed) {
this.timeSeriesChartOptions.yAxis = this.yAxisList.map(axis => axis.option);
- this.timeSeriesChart.setOption(this.timeSeriesChartOptions, {replaceMerge: ['yAxis', 'xAxis', 'grid'], lazyUpdate: true});
+ this.timeSeriesChart.setOption(this.timeSeriesChartOptions, {replaceMerge: ['yAxis', 'xAxis', 'grid'], lazyUpdate: lazy});
}
if (this.yAxisList.length) {
const extent = getAxisExtent(this.timeSeriesChart, this.yAxisList[0].id);
@@ -696,7 +737,7 @@ export class TbTimeSeriesChart {
private minTopOffset(): number {
const showTickLabels =
!!this.yAxisList.find(yAxis => yAxis.settings.show && yAxis.settings.showTickLabels);
- return (this.topPointLabels) ? 20 :
+ return (this.topPointLabels) ? 25 :
(showTickLabels ? 10 : 5);
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html
index b20b941bd1..7db5a92746 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.html
@@ -17,39 +17,99 @@
-->
-
widgets.bar-chart.bar-chart-card-style
-
-
- {{ 'widgets.bar-chart.label-on-bar' | translate }}
+
widgets.bar-chart.bar-chart-style
+
+
+ {{ 'widgets.time-series-chart.data-zoom' | translate }}
-
-
-
-
-
-
-
-
- {{ 'widgets.bar-chart.value-on-bar' | translate }}
-
-
-
-
-
-
+
+
@@ -149,10 +209,22 @@
-
-
- {{ timeSeriesChartShapeTranslations.get(shape) | translate }}
+
+ {{ echartsShapeTranslations.get(shape) | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts
index 84533b26e4..5b4701bf07 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts
@@ -28,11 +28,11 @@ import {
lineSeriesStepTypeTranslations,
seriesLabelPositions,
seriesLabelPositionTranslations,
- timeSeriesChartShapes,
- timeSeriesChartShapeTranslations, TimeSeriesChartType,
+ TimeSeriesChartType,
timeSeriesLineTypes,
timeSeriesLineTypeTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models';
+import { echartsShapes, echartsShapeTranslations } from '@home/components/widget/lib/chart/echarts-widget.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { merge } from 'rxjs';
@@ -67,9 +67,9 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
seriesLabelPositionTranslations = seriesLabelPositionTranslations;
- timeSeriesChartShapes = timeSeriesChartShapes;
+ echartsShapes = echartsShapes;
- timeSeriesChartShapeTranslations = timeSeriesChartShapeTranslations;
+ echartsShapeTranslations = echartsShapeTranslations;
pointLabelPreviewFn = this._pointLabelPreviewFn.bind(this);
@@ -103,6 +103,8 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
pointLabelPosition: [null, []],
pointLabelFont: [null, []],
pointLabelColor: [null, []],
+ enablePointLabelBackground: [null, []],
+ pointLabelBackground: [null, []],
pointShape: [null, []],
pointSize: [null, [Validators.min(0)]],
fillAreaSettings: [null, []]
@@ -112,7 +114,8 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
});
merge(this.lineSettingsFormGroup.get('showLine').valueChanges,
this.lineSettingsFormGroup.get('step').valueChanges,
- this.lineSettingsFormGroup.get('showPointLabel').valueChanges)
+ this.lineSettingsFormGroup.get('showPointLabel').valueChanges,
+ this.lineSettingsFormGroup.get('enablePointLabelBackground').valueChanges)
.subscribe(() => {
this.updateValidators();
});
@@ -147,6 +150,7 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
const showLine: boolean = this.lineSettingsFormGroup.get('showLine').value;
const step: boolean = this.lineSettingsFormGroup.get('step').value;
const showPointLabel: boolean = this.lineSettingsFormGroup.get('showPointLabel').value;
+ const enablePointLabelBackground: boolean = this.lineSettingsFormGroup.get('enablePointLabelBackground').value;
if (showLine) {
this.lineSettingsFormGroup.get('step').enable({emitEvent: false});
if (step) {
@@ -169,10 +173,18 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
this.lineSettingsFormGroup.get('pointLabelPosition').enable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelFont').enable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelColor').enable({emitEvent: false});
+ this.lineSettingsFormGroup.get('enablePointLabelBackground').enable({emitEvent: false});
+ if (enablePointLabelBackground) {
+ this.lineSettingsFormGroup.get('pointLabelBackground').enable({emitEvent: false});
+ } else {
+ this.lineSettingsFormGroup.get('pointLabelBackground').disable({emitEvent: false});
+ }
} else {
this.lineSettingsFormGroup.get('pointLabelPosition').disable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelFont').disable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelColor').disable({emitEvent: false});
+ this.lineSettingsFormGroup.get('enablePointLabelBackground').disable({emitEvent: false});
+ this.lineSettingsFormGroup.get('pointLabelBackground').disable({emitEvent: false});
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.html
index 1d4bb95f5c..66b6c9896d 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.html
@@ -56,13 +56,13 @@
-
+
+
+
+
+
+ widgets.bar-chart.bar-appearance
+
+
+ {{ 'widgets.bar-chart.label-on-bar' | translate }}
+
+
+
+
+
+
+
+
+
+
+ {{ 'widgets.bar-chart.value-on-bar' | translate }}
+
+
+
+
+
+
+
+
+
+
+ {{ 'widgets.time-series-chart.series.bar.show-border' | translate }}
+
+
+
+
+
+
+ widgets.time-series-chart.series.bar.border-width
+
+
+
+
+
+ widgets.time-series-chart.series.bar.border-radius
+
+
+
+
+ widgets.time-series-chart.axis.y-axis
+
+
+
+ widgets.time-series-chart.axis.x-axis
+
-
-
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts
index b69b023d34..b221d09cf9 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-with-labels-widget-settings.component.ts
@@ -16,6 +16,7 @@
import { Component, Injector } from '@angular/core';
import {
+ Datasource,
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
@@ -37,6 +38,15 @@ import {
})
export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsComponent {
+ public get datasource(): Datasource {
+ const datasources: Datasource[] = this.widgetConfig.config.datasources;
+ if (datasources && datasources.length) {
+ return datasources[0];
+ } else {
+ return null;
+ }
+ }
+
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
@@ -64,12 +74,26 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
protected onSettingsSet(settings: WidgetSettings) {
this.barChartWidgetSettingsForm = this.fb.group({
+ dataZoom: [settings.dataZoom, []],
+
showBarLabel: [settings.showBarLabel, []],
barLabelFont: [settings.barLabelFont, []],
barLabelColor: [settings.barLabelColor, []],
showBarValue: [settings.showBarValue, []],
barValueFont: [settings.barValueFont, []],
barValueColor: [settings.barValueColor, []],
+ showBarBorder: [settings.showBarBorder, []],
+ barBorderWidth: [settings.barBorderWidth, []],
+ barBorderRadius: [settings.barBorderRadius, []],
+ barBackgroundSettings: [settings.barBackgroundSettings, []],
+ noAggregationBarWidthSettings: [settings.noAggregationBarWidthSettings, []],
+
+ yAxis: [settings.yAxis, []],
+ xAxis: [settings.xAxis, []],
+
+ thresholds: [settings.thresholds, []],
+
+ animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
@@ -88,17 +112,19 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
- background: [settings.background, []]
+ background: [settings.background, []],
+ padding: [settings.padding, []]
});
}
protected validatorTriggers(): string[] {
- return ['showBarLabel', 'showBarValue', 'showLegend', 'showTooltip', 'tooltipShowDate'];
+ return ['showBarLabel', 'showBarValue', 'showBarBorder', 'showLegend', 'showTooltip', 'tooltipShowDate'];
}
protected updateValidators(emitEvent: boolean) {
const showBarLabel: boolean = this.barChartWidgetSettingsForm.get('showBarLabel').value;
const showBarValue: boolean = this.barChartWidgetSettingsForm.get('showBarValue').value;
+ const showBarBorder: boolean = this.barChartWidgetSettingsForm.get('showBarBorder').value;
const showLegend: boolean = this.barChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.barChartWidgetSettingsForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.barChartWidgetSettingsForm.get('tooltipShowDate').value;
@@ -119,6 +145,12 @@ export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsCom
this.barChartWidgetSettingsForm.get('barValueColor').disable();
}
+ if (showBarBorder) {
+ this.barChartWidgetSettingsForm.get('barBorderWidth').enable();
+ } else {
+ this.barChartWidgetSettingsForm.get('barBorderWidth').disable();
+ }
+
if (showLegend) {
this.barChartWidgetSettingsForm.get('legendPosition').enable();
this.barChartWidgetSettingsForm.get('legendLabelFont').enable();
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html
index cf5bbcfdd5..a19b8eb845 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html
@@ -17,29 +17,175 @@
-->
{{ 'widgets.background.background' | translate }}
-
+
widget-config.card-appearance
+
+
+
+
+ {{ 'widgets.background.background' | translate }}
+
+
+
+
+
{{ 'widget-config.card-padding' | translate }}
+
-
{{ 'widgets.range-chart.data-zoom' | translate }}
-
+ widgets.range-chart.range-chart-card-style
+ widgets.range-chart.range-chart-style
-
-
+ {
this.updateModel();
});
merge(this.barSettingsFormGroup.get('showBorder').valueChanges,
- this.barSettingsFormGroup.get('showLabel').valueChanges)
+ this.barSettingsFormGroup.get('showLabel').valueChanges,
+ this.barSettingsFormGroup.get('enableLabelBackground').valueChanges)
.subscribe(() => {
this.updateValidators();
});
@@ -116,6 +119,7 @@ export class TimeSeriesChartBarSettingsComponent implements OnInit, ControlValue
private updateValidators() {
const showBorder: boolean = this.barSettingsFormGroup.get('showBorder').value;
const showLabel: boolean = this.barSettingsFormGroup.get('showLabel').value;
+ const enableLabelBackground: boolean = this.barSettingsFormGroup.get('enableLabelBackground').value;
if (showBorder) {
this.barSettingsFormGroup.get('borderWidth').enable({emitEvent: false});
} else {
@@ -125,10 +129,18 @@ export class TimeSeriesChartBarSettingsComponent implements OnInit, ControlValue
this.barSettingsFormGroup.get('labelPosition').enable({emitEvent: false});
this.barSettingsFormGroup.get('labelFont').enable({emitEvent: false});
this.barSettingsFormGroup.get('labelColor').enable({emitEvent: false});
+ this.barSettingsFormGroup.get('enableLabelBackground').enable({emitEvent: false});
+ if (enableLabelBackground) {
+ this.barSettingsFormGroup.get('labelBackground').enable({emitEvent: false});
+ } else {
+ this.barSettingsFormGroup.get('labelBackground').disable({emitEvent: false});
+ }
} else {
this.barSettingsFormGroup.get('labelPosition').disable({emitEvent: false});
this.barSettingsFormGroup.get('labelFont').disable({emitEvent: false});
this.barSettingsFormGroup.get('labelColor').disable({emitEvent: false});
+ this.barSettingsFormGroup.get('enableLabelBackground').disable({emitEvent: false});
+ this.barSettingsFormGroup.get('labelBackground').disable({emitEvent: false});
}
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html
index 78f1129727..cc3102c475 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html
@@ -97,12 +97,21 @@
{{ 'widgets.range-chart.range-colors' | translate }}
-
+
- widgets.range-chart.range-chart-appearance
+
+
+
+
+ {{ 'widgets.range-chart.range-colors' | translate }}
+
+
+
+
+ {{ 'widgets.range-chart.out-of-range-color' | translate }}
+
+
+ {{ 'widgets.range-chart.show-range-thresholds' | translate }}
+
+
+
+
+
+
+ {{ 'widgets.range-chart.fill-area' | translate }}
+
+
+
+
+
+
+
+ widgets.range-chart.fill-area-opacity
+
+
+ widgets.time-series-chart.series.line.line
+
+
+ {{ 'widgets.time-series-chart.series.line.show-line' | translate }}
+
+
+
+
+ {{ 'widgets.time-series-chart.series.line.step-line' | translate }}
+
+
+
+
+ {{ lineSeriesStepTypeTranslations.get(stepType) | translate }}
+
+
+
+
+
+
+ {{ 'widgets.time-series-chart.series.line.smooth-line' | translate }}
+
+
+
+
+
+
+ {{ timeSeriesLineTypeTranslations.get(lineType) | translate }}
+
+
+
+
+ widgets.time-series-chart.line-type
+
+
+
+
+
+ widgets.time-series-chart.line-width
+
+
widgets.time-series-chart.series.point.points
+
+
+ {{ 'widgets.time-series-chart.series.point.show-points' | translate }}
+
+
+
+
+
+
+
+ {{ 'widgets.time-series-chart.series.point.point-label' | translate }}
+
+
+
+
+
+ {{ seriesLabelPositionTranslations.get(position) | translate }}
+
+
+
+
+
+
+
+
+
+
+ {{ 'widgets.time-series-chart.series.point.point-label-background' | translate }}
+
+
+
+
+
+
+
+
+ {{ echartsShapeTranslations.get(shape) | translate }}
+
+
+
+
+ widgets.time-series-chart.series.point.point-shape
+
+
+
+
+
+ widgets.time-series-chart.series.point.point-size
+
-
-
+
+ {{ 'widgets.range-chart.out-of-range-color' | translate }}
-
+
+
- widgets.time-series-chart.axis.y-axis
+
-
- {{ 'widgets.range-chart.fill-area' | translate }}
-
+
+
@@ -139,10 +285,22 @@
-
+
+
+ widgets.time-series-chart.axis.x-axis
+
-
-
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts
index f0870dbd80..b9a058af24 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts
@@ -16,17 +16,24 @@
import { Component, Injector } from '@angular/core';
import {
+ Datasource,
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
-import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
+import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue } from '@core/utils';
import { rangeChartDefaultSettings } from '@home/components/widget/lib/chart/range-chart-widget.models';
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models';
+import {
+ lineSeriesStepTypes, lineSeriesStepTypeTranslations,
+ seriesLabelPositions, seriesLabelPositionTranslations,
+ timeSeriesLineTypes, timeSeriesLineTypeTranslations
+} from '@home/components/widget/lib/chart/time-series-chart.models';
+import { echartsShapes, echartsShapeTranslations } from '@home/components/widget/lib/chart/echarts-widget.models';
@Component({
selector: 'tb-range-chart-widget-settings',
@@ -35,12 +42,39 @@ import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-s
})
export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
+ public get datasource(): Datasource {
+ const datasources: Datasource[] = this.widgetConfig.config.datasources;
+ if (datasources && datasources.length) {
+ return datasources[0];
+ } else {
+ return null;
+ }
+ }
+
+ lineSeriesStepTypes = lineSeriesStepTypes;
+
+ lineSeriesStepTypeTranslations = lineSeriesStepTypeTranslations;
+
+ timeSeriesLineTypes = timeSeriesLineTypes;
+
+ timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations;
+
+ seriesLabelPositions = seriesLabelPositions;
+
+ seriesLabelPositionTranslations = seriesLabelPositionTranslations;
+
+ echartsShapes = echartsShapes;
+
+ echartsShapeTranslations = echartsShapeTranslations;
+
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
rangeChartWidgetSettingsForm: UntypedFormGroup;
+ pointLabelPreviewFn = this._pointLabelPreviewFn.bind(this);
+
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this);
@@ -64,7 +98,34 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
dataZoom: [settings.dataZoom, []],
rangeColors: [settings.rangeColors, []],
outOfRangeColor: [settings.outOfRangeColor, []],
+ showRangeThresholds: [settings.showRangeThresholds, []],
+ rangeThreshold: [settings.rangeThreshold, []],
fillArea: [settings.fillArea, []],
+ fillAreaOpacity: [settings.fillAreaOpacity, [Validators.min(0), Validators.max(1)]],
+
+ showLine: [settings.showLine, []],
+ step: [settings.step, []],
+ stepType: [settings.stepType, []],
+ smooth: [settings.smooth, []],
+ lineType: [settings.lineType, []],
+ lineWidth: [settings.lineWidth, [Validators.min(0)]],
+
+ showPoints: [settings.showPoints, []],
+ showPointLabel: [settings.showPointLabel, []],
+ pointLabelPosition: [settings.pointLabelPosition, []],
+ pointLabelFont: [settings.pointLabelFont, []],
+ pointLabelColor: [settings.pointLabelColor, []],
+ enablePointLabelBackground: [settings.enablePointLabelBackground, []],
+ pointLabelBackground: [settings.pointLabelBackground, []],
+ pointShape: [settings.pointShape, []],
+ pointSize: [settings.pointSize, [Validators.min(0)]],
+
+ yAxis: [settings.yAxis, []],
+ xAxis: [settings.xAxis, []],
+
+ thresholds: [settings.thresholds, []],
+
+ animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
@@ -83,19 +144,75 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
- background: [settings.background, []]
+ background: [settings.background, []],
+ padding: [settings.padding, []]
});
}
protected validatorTriggers(): string[] {
- return ['showLegend', 'showTooltip', 'tooltipShowDate'];
+ return ['showRangeThresholds', 'fillArea', 'showLine', 'step', 'showPointLabel', 'enablePointLabelBackground',
+ 'showLegend', 'showTooltip', 'tooltipShowDate'];
}
protected updateValidators(emitEvent: boolean) {
+ const showRangeThresholds: boolean = this.rangeChartWidgetSettingsForm.get('showRangeThresholds').value;
+ const fillArea: boolean = this.rangeChartWidgetSettingsForm.get('fillArea').value;
+ const showLine: boolean = this.rangeChartWidgetSettingsForm.get('showLine').value;
+ const step: boolean = this.rangeChartWidgetSettingsForm.get('step').value;
+ const showPointLabel: boolean = this.rangeChartWidgetSettingsForm.get('showPointLabel').value;
+ const enablePointLabelBackground: boolean = this.rangeChartWidgetSettingsForm.get('enablePointLabelBackground').value;
const showLegend: boolean = this.rangeChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.rangeChartWidgetSettingsForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.rangeChartWidgetSettingsForm.get('tooltipShowDate').value;
+ if (showRangeThresholds) {
+ this.rangeChartWidgetSettingsForm.get('rangeThreshold').enable();
+ } else {
+ this.rangeChartWidgetSettingsForm.get('rangeThreshold').disable();
+ }
+
+ if (fillArea) {
+ this.rangeChartWidgetSettingsForm.get('fillAreaOpacity').enable();
+ } else {
+ this.rangeChartWidgetSettingsForm.get('fillAreaOpacity').disable();
+ }
+
+ if (showLine) {
+ this.rangeChartWidgetSettingsForm.get('step').enable({emitEvent: false});
+ if (step) {
+ this.rangeChartWidgetSettingsForm.get('stepType').enable();
+ this.rangeChartWidgetSettingsForm.get('smooth').disable();
+ } else {
+ this.rangeChartWidgetSettingsForm.get('stepType').disable();
+ this.rangeChartWidgetSettingsForm.get('smooth').enable();
+ }
+ this.rangeChartWidgetSettingsForm.get('lineType').enable();
+ this.rangeChartWidgetSettingsForm.get('lineWidth').enable();
+ } else {
+ this.rangeChartWidgetSettingsForm.get('step').disable({emitEvent: false});
+ this.rangeChartWidgetSettingsForm.get('stepType').disable();
+ this.rangeChartWidgetSettingsForm.get('smooth').disable();
+ this.rangeChartWidgetSettingsForm.get('lineType').disable();
+ this.rangeChartWidgetSettingsForm.get('lineWidth').disable();
+ }
+ if (showPointLabel) {
+ this.rangeChartWidgetSettingsForm.get('pointLabelPosition').enable();
+ this.rangeChartWidgetSettingsForm.get('pointLabelFont').enable();
+ this.rangeChartWidgetSettingsForm.get('pointLabelColor').enable();
+ this.rangeChartWidgetSettingsForm.get('enablePointLabelBackground').enable({emitEvent: false});
+ if (enablePointLabelBackground) {
+ this.rangeChartWidgetSettingsForm.get('pointLabelBackground').enable();
+ } else {
+ this.rangeChartWidgetSettingsForm.get('pointLabelBackground').disable();
+ }
+ } else {
+ this.rangeChartWidgetSettingsForm.get('pointLabelPosition').disable();
+ this.rangeChartWidgetSettingsForm.get('pointLabelFont').disable();
+ this.rangeChartWidgetSettingsForm.get('pointLabelColor').disable();
+ this.rangeChartWidgetSettingsForm.get('enablePointLabelBackground').disable({emitEvent: false});
+ this.rangeChartWidgetSettingsForm.get('pointLabelBackground').disable();
+ }
+
if (showLegend) {
this.rangeChartWidgetSettingsForm.get('legendPosition').enable();
this.rangeChartWidgetSettingsForm.get('legendLabelFont').enable();
@@ -136,6 +253,12 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
}
}
+ private _pointLabelPreviewFn(): string {
+ const units: string = this.widgetConfig.config.units;
+ const decimals: number = this.widgetConfig.config.decimals;
+ return formatValue(22, decimals, units, false);
+ }
+
private _tooltipValuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
@@ -148,5 +271,4 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
processor.update(Date.now());
return processor.formatted;
}
-
}
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.html
index 447784091e..ddbeaf2480 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.html
@@ -59,6 +59,15 @@
{{ 'widgets.background.background' | translate }}
-
+
widget-config.card-appearance
+
+
+
+
+ {{ 'widgets.background.background' | translate }}
+
+
+
+
+
{{ 'widget-config.card-padding' | translate }}
+
+
+ {{ 'widgets.time-series-chart.series.bar.label-background' | translate }}
+
+
+
+
+
+ {{ 'widgets.time-series-chart.series.point.point-label-background' | translate }}
+
+
+
+
widgets.time-series-chart.series.point.point-shape
+
-
widget-config.units-short
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts
index 8dafc7050f..ac49b8137d 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-axis-settings.component.ts
@@ -70,6 +70,14 @@ export class TimeSeriesChartAxisSettingsComponent implements OnInit, ControlValu
@coerceBoolean()
advanced = false;
+ @Input()
+ @coerceBoolean()
+ hideUnits = false;
+
+ @Input()
+ @coerceBoolean()
+ hideDecimals = false;
+
private modelValue: TimeSeriesChartXAxisSettings | TimeSeriesChartYAxisSettings;
private propagateChange = null;
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-fill-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.html
similarity index 96%
rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-fill-settings.component.html
rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.html
index 934f985483..99e3c1be8f 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-fill-settings.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.html
@@ -27,8 +27,8 @@
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-fill-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.ts
similarity index 97%
rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-fill-settings.component.ts
rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.ts
index 44cc870f5b..dd7f4dd7f6 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-fill-settings.component.ts
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.ts
@@ -34,7 +34,7 @@ import { AppState } from '@core/core.state';
@Component({
selector: 'tb-time-series-chart-fill-settings',
templateUrl: './time-series-chart-fill-settings.component.html',
- styleUrls: ['./../widget-settings.scss'],
+ styleUrls: ['./../../widget-settings.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
@@ -73,7 +73,7 @@ export class TimeSeriesChartFillSettingsComponent implements OnInit, ControlValu
ngOnInit(): void {
this.fillSettingsFormGroup = this.fb.group({
type: [null, []],
- opacity: [null, [Validators.min(0), Validators.max(100)]],
+ opacity: [null, [Validators.min(0), Validators.max(1)]],
gradient: this.fb.group({
start: [null, [Validators.min(0), Validators.max(100)]],
end: [null, [Validators.min(0), Validators.max(100)]]
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html
index 7e2c9f74c2..d0ea8f0ef3 100644
--- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html
+++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html
@@ -73,7 +73,7 @@
[formControl]="entityKeyFormControl">
-
widget-config.decimals-short
widgets.time-series-chart.series.opacity
+
@@ -98,14 +98,13 @@
-
+
+