Browse Source

UI: Update range chart advanced settings. Add label background option to series/threshold labels. Minor improvements and fixes.

pull/10473/head
Igor Kulikov 3 years ago
parent
commit
1a9e69c762
  1. 26
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html
  2. 34
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts
  3. 101
      ui-ngx/src/app/modules/home/components/widget/lib/chart/echarts-widget.models.ts
  4. 49
      ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts
  5. 3
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts
  6. 99
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts
  7. 7
      ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts
  8. 202
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html
  9. 127
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.ts
  10. 9
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.html
  11. 14
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.ts
  12. 13
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html
  13. 22
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts
  14. 4
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.html
  15. 2
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.ts
  16. 15
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html
  17. 74
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts
  18. 19
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html
  19. 40
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts
  20. 39
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.html
  21. 124
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts
  22. 5
      ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts
  23. 10
      ui-ngx/src/assets/locale/locale.constant-en_US.json
  24. 2
      ui-ngx/src/assets/locale/locale.constant-pl_PL.json
  25. 2
      ui-ngx/src/assets/locale/locale.constant-zh_CN.json

26
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.html

@ -102,10 +102,17 @@
formControlName="outOfRangeColor"> formControlName="outOfRangeColor">
</tb-color-input> </tb-color-input>
</div> </div>
<div class="tb-form-row"> <div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showRangeThresholds"> <mat-slide-toggle class="mat-slide" formControlName="showRangeThresholds">
{{ 'widgets.range-chart.show-range-thresholds' | translate }} {{ 'widgets.range-chart.show-range-thresholds' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
<tb-time-series-chart-threshold-settings
boxButton
hideYAxis
[widgetConfig]="widgetConfig?.config"
title="widgets.range-chart.range-thresholds-settings"
formControlName="rangeThreshold">
</tb-time-series-chart-threshold-settings>
</div> </div>
<div class="tb-form-row"> <div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="fillArea"> <mat-slide-toggle class="mat-slide" formControlName="fillArea">
@ -115,8 +122,8 @@
<div class="tb-form-row space-between column-xs"> <div class="tb-form-row space-between column-xs">
<div translate>widgets.range-chart.fill-area-opacity</div> <div translate>widgets.range-chart.fill-area-opacity</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="fillAreaOpacity" min="0" max="100" <input matInput type="number" formControlName="fillAreaOpacity" min="0" max="1"
step="1" placeholder="{{ 'widget-config.set' | translate }}"/> step="0.1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="tb-form-panel stroked"> <div class="tb-form-panel stroked">
@ -193,12 +200,21 @@
</tb-color-input> </tb-color-input>
</div> </div>
</div> </div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="enablePointLabelBackground">
{{ 'widgets.time-series-chart.series.point.point-label-background' | translate }}
</mat-slide-toggle>
<tb-color-input asBoxInput
colorClearButton
formControlName="pointLabelBackground">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs"> <div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-shape</div> <div translate>widgets.time-series-chart.series.point.point-shape</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape"> <mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape"> <mat-option *ngFor="let shape of echartsShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }} {{ echartsShapeTranslations.get(shape) | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

34
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/range-chart-basic-config.component.ts

@ -49,11 +49,10 @@ import {
lineSeriesStepTypeTranslations, lineSeriesStepTypeTranslations,
seriesLabelPositions, seriesLabelPositions,
seriesLabelPositionTranslations, seriesLabelPositionTranslations,
timeSeriesChartShapes,
timeSeriesChartShapeTranslations,
timeSeriesLineTypes, timeSeriesLineTypes,
timeSeriesLineTypeTranslations timeSeriesLineTypeTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
import { echartsShapes, echartsShapeTranslations } from '@home/components/widget/lib/chart/echarts-widget.models';
@Component({ @Component({
selector: 'tb-range-chart-basic-config', selector: 'tb-range-chart-basic-config',
@ -83,9 +82,9 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
seriesLabelPositionTranslations = seriesLabelPositionTranslations; seriesLabelPositionTranslations = seriesLabelPositionTranslations;
timeSeriesChartShapes = timeSeriesChartShapes; echartsShapes = echartsShapes;
timeSeriesChartShapeTranslations = timeSeriesChartShapeTranslations; echartsShapeTranslations = echartsShapeTranslations;
legendPositions = legendPositions; legendPositions = legendPositions;
@ -139,8 +138,9 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
rangeColors: [settings.rangeColors, []], rangeColors: [settings.rangeColors, []],
outOfRangeColor: [settings.outOfRangeColor, []], outOfRangeColor: [settings.outOfRangeColor, []],
showRangeThresholds: [settings.showRangeThresholds, []], showRangeThresholds: [settings.showRangeThresholds, []],
rangeThreshold: [settings.rangeThreshold, []],
fillArea: [settings.fillArea, []], fillArea: [settings.fillArea, []],
fillAreaOpacity: [settings.fillAreaOpacity, [Validators.min(0), Validators.max(100)]], fillAreaOpacity: [settings.fillAreaOpacity, [Validators.min(0), Validators.max(1)]],
showLine: [settings.showLine, []], showLine: [settings.showLine, []],
step: [settings.step, []], step: [settings.step, []],
@ -154,6 +154,8 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
pointLabelPosition: [settings.pointLabelPosition, []], pointLabelPosition: [settings.pointLabelPosition, []],
pointLabelFont: [settings.pointLabelFont, []], pointLabelFont: [settings.pointLabelFont, []],
pointLabelColor: [settings.pointLabelColor, []], pointLabelColor: [settings.pointLabelColor, []],
enablePointLabelBackground: [settings.enablePointLabelBackground, []],
pointLabelBackground: [settings.pointLabelBackground, []],
pointShape: [settings.pointShape, []], pointShape: [settings.pointShape, []],
pointSize: [settings.pointSize, [Validators.min(0)]], pointSize: [settings.pointSize, [Validators.min(0)]],
@ -216,6 +218,7 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.widgetConfig.config.settings.rangeColors = config.rangeColors; this.widgetConfig.config.settings.rangeColors = config.rangeColors;
this.widgetConfig.config.settings.outOfRangeColor = config.outOfRangeColor; this.widgetConfig.config.settings.outOfRangeColor = config.outOfRangeColor;
this.widgetConfig.config.settings.showRangeThresholds = config.showRangeThresholds; this.widgetConfig.config.settings.showRangeThresholds = config.showRangeThresholds;
this.widgetConfig.config.settings.rangeThreshold = config.rangeThreshold;
this.widgetConfig.config.settings.fillArea = config.fillArea; this.widgetConfig.config.settings.fillArea = config.fillArea;
this.widgetConfig.config.settings.fillAreaOpacity = config.fillAreaOpacity; this.widgetConfig.config.settings.fillAreaOpacity = config.fillAreaOpacity;
@ -231,6 +234,8 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.widgetConfig.config.settings.pointLabelPosition = config.pointLabelPosition; this.widgetConfig.config.settings.pointLabelPosition = config.pointLabelPosition;
this.widgetConfig.config.settings.pointLabelFont = config.pointLabelFont; this.widgetConfig.config.settings.pointLabelFont = config.pointLabelFont;
this.widgetConfig.config.settings.pointLabelColor = config.pointLabelColor; this.widgetConfig.config.settings.pointLabelColor = config.pointLabelColor;
this.widgetConfig.config.settings.enablePointLabelBackground = config.enablePointLabelBackground;
this.widgetConfig.config.settings.pointLabelBackground = config.pointLabelBackground;
this.widgetConfig.config.settings.pointShape = config.pointShape; this.widgetConfig.config.settings.pointShape = config.pointShape;
this.widgetConfig.config.settings.pointSize = config.pointSize; this.widgetConfig.config.settings.pointSize = config.pointSize;
@ -268,16 +273,19 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
} }
protected validatorTriggers(): string[] { protected validatorTriggers(): string[] {
return ['showTitle', 'showIcon', 'fillArea', 'showLine', 'step', 'showPointLabel', 'showLegend', 'showTooltip', 'tooltipShowDate']; return ['showTitle', 'showIcon', 'showRangeThresholds', 'fillArea', 'showLine',
'step', 'showPointLabel', 'enablePointLabelBackground', 'showLegend', 'showTooltip', 'tooltipShowDate'];
} }
protected updateValidators(emitEvent: boolean, trigger?: string) { protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.rangeChartWidgetConfigForm.get('showTitle').value; const showTitle: boolean = this.rangeChartWidgetConfigForm.get('showTitle').value;
const showIcon: boolean = this.rangeChartWidgetConfigForm.get('showIcon').value; const showIcon: boolean = this.rangeChartWidgetConfigForm.get('showIcon').value;
const showRangeThresholds: boolean = this.rangeChartWidgetConfigForm.get('showRangeThresholds').value;
const fillArea: boolean = this.rangeChartWidgetConfigForm.get('fillArea').value; const fillArea: boolean = this.rangeChartWidgetConfigForm.get('fillArea').value;
const showLine: boolean = this.rangeChartWidgetConfigForm.get('showLine').value; const showLine: boolean = this.rangeChartWidgetConfigForm.get('showLine').value;
const step: boolean = this.rangeChartWidgetConfigForm.get('step').value; const step: boolean = this.rangeChartWidgetConfigForm.get('step').value;
const showPointLabel: boolean = this.rangeChartWidgetConfigForm.get('showPointLabel').value; const showPointLabel: boolean = this.rangeChartWidgetConfigForm.get('showPointLabel').value;
const enablePointLabelBackground: boolean = this.rangeChartWidgetConfigForm.get('enablePointLabelBackground').value;
const showLegend: boolean = this.rangeChartWidgetConfigForm.get('showLegend').value; const showLegend: boolean = this.rangeChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.rangeChartWidgetConfigForm.get('showTooltip').value; const showTooltip: boolean = this.rangeChartWidgetConfigForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.rangeChartWidgetConfigForm.get('tooltipShowDate').value; const tooltipShowDate: boolean = this.rangeChartWidgetConfigForm.get('tooltipShowDate').value;
@ -309,6 +317,12 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.rangeChartWidgetConfigForm.get('iconColor').disable(); this.rangeChartWidgetConfigForm.get('iconColor').disable();
} }
if (showRangeThresholds) {
this.rangeChartWidgetConfigForm.get('rangeThreshold').enable();
} else {
this.rangeChartWidgetConfigForm.get('rangeThreshold').disable();
}
if (fillArea) { if (fillArea) {
this.rangeChartWidgetConfigForm.get('fillAreaOpacity').enable(); this.rangeChartWidgetConfigForm.get('fillAreaOpacity').enable();
} else { } else {
@ -337,10 +351,18 @@ export class RangeChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.rangeChartWidgetConfigForm.get('pointLabelPosition').enable(); this.rangeChartWidgetConfigForm.get('pointLabelPosition').enable();
this.rangeChartWidgetConfigForm.get('pointLabelFont').enable(); this.rangeChartWidgetConfigForm.get('pointLabelFont').enable();
this.rangeChartWidgetConfigForm.get('pointLabelColor').enable(); this.rangeChartWidgetConfigForm.get('pointLabelColor').enable();
this.rangeChartWidgetConfigForm.get('enablePointLabelBackground').enable({emitEvent: false});
if (enablePointLabelBackground) {
this.rangeChartWidgetConfigForm.get('pointLabelBackground').enable();
} else {
this.rangeChartWidgetConfigForm.get('pointLabelBackground').disable();
}
} else { } else {
this.rangeChartWidgetConfigForm.get('pointLabelPosition').disable(); this.rangeChartWidgetConfigForm.get('pointLabelPosition').disable();
this.rangeChartWidgetConfigForm.get('pointLabelFont').disable(); this.rangeChartWidgetConfigForm.get('pointLabelFont').disable();
this.rangeChartWidgetConfigForm.get('pointLabelColor').disable(); this.rangeChartWidgetConfigForm.get('pointLabelColor').disable();
this.rangeChartWidgetConfigForm.get('enablePointLabelBackground').disable({emitEvent: false});
this.rangeChartWidgetConfigForm.get('pointLabelBackground').disable();
} }
if (showLegend) { if (showLegend) {

101
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 * as echarts from 'echarts/core';
import AxisModel from 'echarts/types/src/coord/cartesian/AxisModel'; import AxisModel from 'echarts/types/src/coord/cartesian/AxisModel';
import { estimateLabelUnionRect } from 'echarts/lib/coord/axisHelper'; import { estimateLabelUnionRect } from 'echarts/lib/coord/axisHelper';
import { formatValue, isDefinedAndNotNull } from '@core/utils'; import { formatValue, isDefinedAndNotNull, isNumber } from '@core/utils';
import { import {
DataZoomComponent, DataZoomComponent,
DataZoomComponentOption, DataZoomComponentOption,
@ -55,6 +55,7 @@ import { DateFormatProcessor, DateFormatSettings, Font } from '@shared/models/wi
import GlobalModel from 'echarts/types/src/model/Global'; import GlobalModel from 'echarts/types/src/model/Global';
import Axis2D from 'echarts/types/src/coord/cartesian/Axis2D'; import Axis2D from 'echarts/types/src/coord/cartesian/Axis2D';
import SeriesModel from 'echarts/types/src/model/Series'; import SeriesModel from 'echarts/types/src/model/Series';
import { MarkLine2DDataItemOption } from 'echarts/types/src/component/marker/MarkLineModel';
class EChartsModule { class EChartsModule {
private initialized = false; private initialized = false;
@ -110,6 +111,51 @@ export type EChartsSeriesItem = {
decimals?: number; 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, string>(
[
[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, EChartsShapeOffsetFunction>(
[
[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) => { export const timeAxisBandWidthCalculator: TimeAxisBandWidthCalculator = (model) => {
let interval: number; let interval: number;
const axisOption = model.option; const axisOption = model.option;
@ -211,7 +257,23 @@ export const measureXAxisNameHeight = (chart: ECharts, name: string): number =>
return 0; 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); const axis = getYAxis(chart, axisId);
if (axis && !axis.scale.isBlank()) { if (axis && !axis.scale.isBlank()) {
const extent = axis.scale.getExtent(); const extent = axis.scale.getExtent();
@ -220,6 +282,16 @@ export const measureThresholdLabelOffset = (chart: ECharts, axisId: string, thre
if (models?.length) { if (models?.length) {
const lineSeriesModel = models[0] as SeriesModel<LineSeriesOption>; const lineSeriesModel = models[0] as SeriesModel<LineSeriesOption>;
const markLineModel = lineSeriesModel.getModel('markLine'); 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']); const labelPosition = markLineModel.get(['label', 'position']);
if (labelPosition === 'start' || labelPosition === 'end') { if (labelPosition === 'start' || labelPosition === 'end') {
const labelModel = markLineModel.getModel('label'); const labelModel = markLineModel.getModel('label');
@ -239,23 +311,38 @@ export const measureThresholdLabelOffset = (chart: ECharts, axisId: string, thre
} }
} }
if (!textWidth) { if (!textWidth) {
return [0,0]; return offset;
} }
const distanceOpt = markLineModel.get(['label', 'distance']); const distanceOpt = markLineModel.get(['label', 'distance']);
let distance = 5; let distance = 5;
if (distanceOpt) { if (distanceOpt) {
distance = typeof distanceOpt === 'number' ? distanceOpt : distanceOpt[0]; 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') { if (labelPosition === 'start') {
return [offset, 0]; offset[0] = Math.max(offset[0], textOffset);
} else { } 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] => { export const getAxisExtent = (chart: ECharts, axisId: string): [number, number] => {

49
ui-ngx/src/app/modules/home/components/widget/lib/chart/range-chart-widget.models.ts

@ -24,22 +24,21 @@ import {
sortedColorRange sortedColorRange
} from '@shared/models/widget-settings.models'; } from '@shared/models/widget-settings.models';
import { LegendPosition } from '@shared/models/widget.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 { import {
createTimeSeriesChartVisualMapPiece, createTimeSeriesChartVisualMapPiece,
defaultTimeSeriesChartXAxisSettings, defaultTimeSeriesChartXAxisSettings,
defaultTimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings,
LineSeriesStepType, LineSeriesStepType,
SeriesFillType, SeriesFillType,
SeriesLabelPosition, timeSeriesChartAnimationDefaultSettings, SeriesLabelPosition, ThresholdLabelPosition, timeSeriesChartAnimationDefaultSettings,
TimeSeriesChartAnimationSettings, TimeSeriesChartAnimationSettings,
timeSeriesChartColorScheme, timeSeriesChartColorScheme,
TimeSeriesChartKeySettings, TimeSeriesChartKeySettings,
TimeSeriesChartLineType, TimeSeriesChartLineType,
TimeSeriesChartSeriesType, TimeSeriesChartSeriesType,
TimeSeriesChartSettings, TimeSeriesChartSettings,
TimeSeriesChartShape, TimeSeriesChartThreshold, timeSeriesChartThresholdDefaultSettings,
TimeSeriesChartThreshold,
TimeSeriesChartThresholdType, TimeSeriesChartThresholdType,
TimeSeriesChartVisualMapPiece, TimeSeriesChartVisualMapPiece,
TimeSeriesChartXAxisSettings, TimeSeriesChartXAxisSettings,
@ -64,6 +63,7 @@ export interface RangeChartWidgetSettings extends EChartsTooltipWidgetSettings {
rangeColors: Array<ColorRange>; rangeColors: Array<ColorRange>;
outOfRangeColor: string; outOfRangeColor: string;
showRangeThresholds: boolean; showRangeThresholds: boolean;
rangeThreshold: Partial<TimeSeriesChartThreshold>;
fillArea: boolean; fillArea: boolean;
fillAreaOpacity: number; fillAreaOpacity: number;
showLine: boolean; showLine: boolean;
@ -77,7 +77,9 @@ export interface RangeChartWidgetSettings extends EChartsTooltipWidgetSettings {
pointLabelPosition: SeriesLabelPosition; pointLabelPosition: SeriesLabelPosition;
pointLabelFont: Font; pointLabelFont: Font;
pointLabelColor: string; pointLabelColor: string;
pointShape: TimeSeriesChartShape; enablePointLabelBackground: boolean;
pointLabelBackground: string;
pointShape: EChartsShape;
pointSize: number; pointSize: number;
yAxis: TimeSeriesChartYAxisSettings; yAxis: TimeSeriesChartYAxisSettings;
xAxis: TimeSeriesChartXAxisSettings; xAxis: TimeSeriesChartXAxisSettings;
@ -104,6 +106,17 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = {
], ],
outOfRangeColor: '#ccc', outOfRangeColor: '#ccc',
showRangeThresholds: true, showRangeThresholds: true,
rangeThreshold: mergeDeep({} as Partial<TimeSeriesChartThreshold>,
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, fillArea: true,
fillAreaOpacity: 0.7, fillAreaOpacity: 0.7,
showLine: true, showLine: true,
@ -124,7 +137,9 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = {
lineHeight: '1' lineHeight: '1'
}, },
pointLabelColor: timeSeriesChartColorScheme['series.label'].light, pointLabelColor: timeSeriesChartColorScheme['series.label'].light,
pointShape: TimeSeriesChartShape.emptyCircle, enablePointLabelBackground: false,
pointLabelBackground: 'rgba(255,255,255,0.56)',
pointShape: EChartsShape.emptyCircle,
pointSize: 4, pointSize: 4,
yAxis: mergeDeep({} as TimeSeriesChartYAxisSettings, yAxis: mergeDeep({} as TimeSeriesChartYAxisSettings,
defaultTimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings,
@ -185,26 +200,12 @@ export const rangeChartDefaultSettings: RangeChartWidgetSettings = {
export const rangeChartTimeSeriesSettings = (settings: RangeChartWidgetSettings, rangeItems: RangeItem[], export const rangeChartTimeSeriesSettings = (settings: RangeChartWidgetSettings, rangeItems: RangeItem[],
decimals: number, units: string): DeepPartial<TimeSeriesChartSettings> => { decimals: number, units: string): DeepPartial<TimeSeriesChartSettings> => {
let thresholds: DeepPartial<TimeSeriesChartThreshold>[] = settings.showRangeThresholds ? getMarkPoints(rangeItems).map(item => ({ let thresholds: DeepPartial<TimeSeriesChartThreshold>[] = settings.showRangeThresholds ? getMarkPoints(rangeItems).map(item => ({
type: TimeSeriesChartThresholdType.constant, ...{type: TimeSeriesChartThresholdType.constant,
yAxisId: 'default', yAxisId: 'default',
units, units,
decimals, decimals,
lineWidth: 1, value: item},
lineColor: '#37383b', ...settings.rangeThreshold
lineType: [3, 3],
startSymbol: TimeSeriesChartShape.circle,
startSymbolSize: 5,
endSymbol: TimeSeriesChartShape.arrow,
endSymbolSize: 7,
showLabel: true,
labelPosition: 'insideEndTop',
labelColor: '#37383b',
additionalLabelOption: {
backgroundColor: 'rgba(255,255,255,0.56)',
padding: [4, 5],
borderRadius: 4,
},
value: item
} as DeepPartial<TimeSeriesChartThreshold>)) : []; } as DeepPartial<TimeSeriesChartThreshold>)) : [];
if (settings.thresholds?.length) { if (settings.thresholds?.length) {
thresholds = thresholds.concat(settings.thresholds); thresholds = thresholds.concat(settings.thresholds);
@ -254,6 +255,8 @@ export const rangeChartTimeSeriesKeySettings = (settings: RangeChartWidgetSettin
pointLabelPosition: settings.pointLabelPosition, pointLabelPosition: settings.pointLabelPosition,
pointLabelFont: settings.pointLabelFont, pointLabelFont: settings.pointLabelFont,
pointLabelColor: settings.pointLabelColor, pointLabelColor: settings.pointLabelColor,
enablePointLabelBackground: settings.enablePointLabelBackground,
pointLabelBackground: settings.pointLabelBackground,
pointShape: settings.pointShape, pointShape: settings.pointShape,
pointSize: settings.pointSize, pointSize: settings.pointSize,
fillAreaSettings: { fillAreaSettings: {

3
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart-bar.models.ts

@ -152,6 +152,9 @@ export const renderTimeSeriesBar = (params: CustomSeriesRenderItemParams, api: C
} as CallbackDataParams); } as CallbackDataParams);
style.textDistance = 5; style.textDistance = 5;
style.textPosition = position; style.textPosition = position;
style.textBackgroundColor = renderCtx.labelOption.backgroundColor;
style.textPadding = renderCtx.labelOption.padding;
style.textBorderRadius = renderCtx.labelOption.borderRadius;
style.rich = renderCtx.labelOption.rich; style.rich = renderCtx.labelOption.rich;
if (renderCtx.additionalLabelOption) { if (renderCtx.additionalLabelOption) {
style = {...style, ...renderCtx.additionalLabelOption}; style = {...style, ...renderCtx.additionalLabelOption};

99
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.models.ts

@ -17,10 +17,10 @@
import { import {
ECharts, ECharts,
EChartsOption, EChartsOption,
EChartsSeriesItem, EChartsSeriesItem, EChartsShape,
EChartsTooltipTrigger, EChartsTooltipTrigger,
EChartsTooltipWidgetSettings, EChartsTooltipWidgetSettings,
measureThresholdLabelOffset, measureThresholdOffset,
timeAxisBandWidthCalculator timeAxisBandWidthCalculator
} from '@home/components/widget/lib/chart/echarts-widget.models'; } from '@home/components/widget/lib/chart/echarts-widget.models';
import { import {
@ -134,34 +134,6 @@ export const timeSeriesAxisPositionTranslations = new Map<AxisPosition, string>(
] ]
); );
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, string>(
[
[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 { export enum TimeSeriesChartLineType {
solid = 'solid', solid = 'solid',
dashed = 'dashed', dashed = 'dashed',
@ -456,14 +428,16 @@ export interface TimeSeriesChartThreshold {
lineColor: string; lineColor: string;
lineType: TimeSeriesChartLineType | number | number[]; lineType: TimeSeriesChartLineType | number | number[];
lineWidth: number; lineWidth: number;
startSymbol: TimeSeriesChartShape; startSymbol: EChartsShape;
startSymbolSize: number; startSymbolSize: number;
endSymbol: TimeSeriesChartShape; endSymbol: EChartsShape;
endSymbolSize: number; endSymbolSize: number;
showLabel: boolean; showLabel: boolean;
labelPosition: ThresholdLabelPosition; labelPosition: ThresholdLabelPosition;
labelFont: Font; labelFont: Font;
labelColor: string; labelColor: string;
enableLabelBackground: boolean;
labelBackground: string;
additionalLabelOption?: {[key: string]: any}; additionalLabelOption?: {[key: string]: any};
} }
@ -509,9 +483,9 @@ export const timeSeriesChartThresholdDefaultSettings: TimeSeriesChartThreshold =
lineColor: timeSeriesChartColorScheme['threshold.line'].light, lineColor: timeSeriesChartColorScheme['threshold.line'].light,
lineType: TimeSeriesChartLineType.solid, lineType: TimeSeriesChartLineType.solid,
lineWidth: 1, lineWidth: 1,
startSymbol: TimeSeriesChartShape.none, startSymbol: EChartsShape.none,
startSymbolSize: 5, startSymbolSize: 5,
endSymbol: TimeSeriesChartShape.arrow, endSymbol: EChartsShape.arrow,
endSymbolSize: 5, endSymbolSize: 5,
showLabel: true, showLabel: true,
labelPosition: ThresholdLabelPosition.end, labelPosition: ThresholdLabelPosition.end,
@ -523,7 +497,9 @@ export const timeSeriesChartThresholdDefaultSettings: TimeSeriesChartThreshold =
weight: '400', weight: '400',
lineHeight: '1' lineHeight: '1'
}, },
labelColor: timeSeriesChartColorScheme['threshold.label'].light labelColor: timeSeriesChartColorScheme['threshold.label'].light,
enableLabelBackground: false,
labelBackground: 'rgba(255,255,255,0.56)'
}; };
export enum TimeSeriesChartNoAggregationBarWidthStrategy { export enum TimeSeriesChartNoAggregationBarWidthStrategy {
@ -744,8 +720,10 @@ export interface LineSeriesSettings {
pointLabelPosition: SeriesLabelPosition; pointLabelPosition: SeriesLabelPosition;
pointLabelFont: Font; pointLabelFont: Font;
pointLabelColor: string; pointLabelColor: string;
enablePointLabelBackground: boolean;
pointLabelBackground: string;
pointLabelFormatter?: string | LabelFormatterCallback; pointLabelFormatter?: string | LabelFormatterCallback;
pointShape: TimeSeriesChartShape; pointShape: EChartsShape;
pointSize: number; pointSize: number;
fillAreaSettings: SeriesFillSettings; fillAreaSettings: SeriesFillSettings;
} }
@ -758,6 +736,8 @@ export interface BarSeriesSettings {
labelPosition: SeriesLabelPosition | BuiltinTextPosition; labelPosition: SeriesLabelPosition | BuiltinTextPosition;
labelFont: Font; labelFont: Font;
labelColor: string; labelColor: string;
enableLabelBackground: boolean;
labelBackground: string;
labelFormatter?: string | LabelFormatterCallback; labelFormatter?: string | LabelFormatterCallback;
labelLayout?: LabelLayoutOption | LabelLayoutOptionCallback; labelLayout?: LabelLayoutOption | LabelLayoutOptionCallback;
additionalLabelOption?: {[key: string]: any}; additionalLabelOption?: {[key: string]: any};
@ -797,7 +777,9 @@ export const timeSeriesChartKeyDefaultSettings: TimeSeriesChartKeySettings = {
lineHeight: '1' lineHeight: '1'
}, },
pointLabelColor: timeSeriesChartColorScheme['series.label'].light, pointLabelColor: timeSeriesChartColorScheme['series.label'].light,
pointShape: TimeSeriesChartShape.emptyCircle, enablePointLabelBackground: false,
pointLabelBackground: 'rgba(255,255,255,0.56)',
pointShape: EChartsShape.emptyCircle,
pointSize: 4, pointSize: 4,
fillAreaSettings: { fillAreaSettings: {
type: SeriesFillType.none, type: SeriesFillType.none,
@ -823,6 +805,8 @@ export const timeSeriesChartKeyDefaultSettings: TimeSeriesChartKeySettings = {
lineHeight: '1' lineHeight: '1'
}, },
labelColor: timeSeriesChartColorScheme['series.label'].light, labelColor: timeSeriesChartColorScheme['series.label'].light,
enableLabelBackground: false,
labelBackground: 'rgba(255,255,255,0.56)',
backgroundSettings: { backgroundSettings: {
type: SeriesFillType.none, type: SeriesFillType.none,
opacity: 0.4, opacity: 0.4,
@ -1080,7 +1064,7 @@ export const calculateThresholdsOffset = (chart: ECharts,
const result: [number, number] = [0, 0]; const result: [number, number] = [0, 0];
for (const item of thresholdItems) { for (const item of thresholdItems) {
const yAxis = yAxisList[item.yAxisIndex]; 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[0] = Math.max(result[0], offset[0]);
result[1] = Math.max(result[1], offset[1]); result[1] = Math.max(result[1], offset[1]);
} }
@ -1141,6 +1125,11 @@ 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) { if (item.settings.additionalLabelOption) {
seriesOption.markLine.label = {...seriesOption.markLine.label, ...item.settings.additionalLabelOption}; seriesOption.markLine.label = {...seriesOption.markLine.label, ...item.settings.additionalLabelOption};
} }
@ -1259,7 +1248,7 @@ export const updateDarkMode = (options: EChartsOption, settings: TimeSeriesChart
} else { } else {
if (item.barRenderContext?.labelOption?.show) { if (item.barRenderContext?.labelOption?.show) {
const barSettings = item.dataKey.settings as BarSeriesSettings; 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'); darkMode, 'series.label');
} }
} }
@ -1303,8 +1292,10 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
const lineSeriesOption = seriesOption as LineSeriesOption; const lineSeriesOption = seriesOption as LineSeriesOption;
lineSeriesOption.type = 'line'; lineSeriesOption.type = 'line';
lineSeriesOption.label = createSeriesLabelOption(item, lineSettings.showPointLabel, lineSeriesOption.label = createSeriesLabelOption(item, lineSettings.showPointLabel,
lineSettings.pointLabelFont, lineSettings.pointLabelColor, lineSettings.pointLabelPosition, lineSettings.pointLabelFont, lineSettings.pointLabelColor,
lineSettings.pointLabelFormatter, darkMode); lineSettings.enablePointLabelBackground, lineSettings.pointLabelBackground,
lineSettings.pointLabelPosition,
lineSettings.pointLabelFormatter, false, darkMode);
lineSeriesOption.step = lineSettings.step ? lineSettings.stepType : false; lineSeriesOption.step = lineSettings.step ? lineSettings.stepType : false;
lineSeriesOption.smooth = lineSettings.smooth; lineSeriesOption.smooth = lineSettings.smooth;
if (lineSettings.smooth) { if (lineSettings.smooth) {
@ -1345,7 +1336,8 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
} }
item.barRenderContext.visualSettings = barVisualSettings; item.barRenderContext.visualSettings = barVisualSettings;
item.barRenderContext.labelOption = createSeriesLabelOption(item, barSettings.showLabel, item.barRenderContext.labelOption = createSeriesLabelOption(item, barSettings.showLabel,
barSettings.labelFont, barSettings.labelColor, barSettings.labelPosition, barSettings.labelFormatter, darkMode); barSettings.labelFont, barSettings.labelColor, barSettings.enableLabelBackground, barSettings.labelBackground,
barSettings.labelPosition, barSettings.labelFormatter, true, darkMode);
item.barRenderContext.additionalLabelOption = barSettings.additionalLabelOption; item.barRenderContext.additionalLabelOption = barSettings.additionalLabelOption;
barSeriesOption.renderItem = (params, api) => barSeriesOption.renderItem = (params, api) =>
renderTimeSeriesBar(params, api, item.barRenderContext); renderTimeSeriesBar(params, api, item.barRenderContext);
@ -1357,12 +1349,15 @@ const createTimeSeriesChartSeries = (item: TimeSeriesChartDataItem,
}; };
const createSeriesLabelOption = (item: TimeSeriesChartDataItem, show: boolean, const createSeriesLabelOption = (item: TimeSeriesChartDataItem, show: boolean,
labelFont: Font, labelColor: string, position: SeriesLabelPosition | BuiltinTextPosition, labelFont: Font, labelColor: string,
enableBackground: boolean, labelBackground: string,
position: SeriesLabelPosition | BuiltinTextPosition,
labelFormatter: string | LabelFormatterCallback, labelFormatter: string | LabelFormatterCallback,
labelColorFill: boolean,
darkMode: boolean): SeriesLabelOption => { darkMode: boolean): SeriesLabelOption => {
let labelStyle: ComponentStyle = {}; let labelStyle: ComponentStyle = {};
if (show) { if (show) {
labelStyle = createChartTextStyle(labelFont, labelColor, darkMode, 'series.label'); labelStyle = createChartTextStyle(labelFont, labelColor, darkMode, 'series.label', labelColorFill);
} }
let formatter: LabelFormatterCallback; let formatter: LabelFormatterCallback;
if (isFunction(labelFormatter)) { if (isFunction(labelFormatter)) {
@ -1386,7 +1381,7 @@ const createSeriesLabelOption = (item: TimeSeriesChartDataItem, show: boolean,
return `{value|${value}}`; return `{value|${value}}`;
}; };
} }
return { const labelOption: SeriesLabelOption = {
show, show,
position, position,
formatter, formatter,
@ -1394,13 +1389,23 @@ const createSeriesLabelOption = (item: TimeSeriesChartDataItem, show: boolean,
value: labelStyle 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); const style = textStyle(font);
delete style.lineHeight; delete style.lineHeight;
style.fontSize = font.size; 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; return style;
}; };

7
ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts

@ -32,7 +32,6 @@ import {
TimeSeriesChartNoAggregationBarWidthStrategy, TimeSeriesChartNoAggregationBarWidthStrategy,
TimeSeriesChartSeriesType, TimeSeriesChartSeriesType,
TimeSeriesChartSettings, TimeSeriesChartSettings,
TimeSeriesChartShape,
TimeSeriesChartThreshold, TimeSeriesChartThreshold,
timeSeriesChartThresholdDefaultSettings, timeSeriesChartThresholdDefaultSettings,
TimeSeriesChartThresholdItem, TimeSeriesChartThresholdItem,
@ -49,7 +48,7 @@ import {
calculateYAxisWidth, calculateYAxisWidth,
ECharts, ECharts,
echartsModule, echartsModule,
EChartsOption, EChartsOption, EChartsShape,
echartsTooltipFormatter, echartsTooltipFormatter,
EChartsTooltipTrigger, EChartsTooltipTrigger,
getAxisExtent, getAxisExtent,
@ -88,7 +87,7 @@ export class TbTimeSeriesChart {
settings.type = TimeSeriesChartSeriesType.line; settings.type = TimeSeriesChartSeriesType.line;
settings.lineSettings.showLine = false; settings.lineSettings.showLine = false;
settings.lineSettings.showPoints = true; settings.lineSettings.showPoints = true;
settings.lineSettings.pointShape = TimeSeriesChartShape.circle; settings.lineSettings.pointShape = EChartsShape.circle;
settings.lineSettings.pointSize = 8; settings.lineSettings.pointSize = 8;
} }
return settings; return settings;
@ -738,7 +737,7 @@ export class TbTimeSeriesChart {
private minTopOffset(): number { private minTopOffset(): number {
const showTickLabels = const showTickLabels =
!!this.yAxisList.find(yAxis => yAxis.settings.show && yAxis.settings.showTickLabels); !!this.yAxisList.find(yAxis => yAxis.settings.show && yAxis.settings.showTickLabels);
return (this.topPointLabels) ? 20 : return (this.topPointLabels) ? 25 :
(showTickLabels ? 10 : 5); (showTickLabels ? 10 : 5);
} }

202
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/range-chart-widget-settings.component.html

@ -17,29 +17,175 @@
--> -->
<ng-container [formGroup]="rangeChartWidgetSettingsForm"> <ng-container [formGroup]="rangeChartWidgetSettingsForm">
<div class="tb-form-panel"> <div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.range-chart.range-chart-card-style</div> <div class="tb-form-panel-title" translate>widgets.range-chart.range-chart-style</div>
<div class="tb-form-row"> <div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="dataZoom"> <mat-slide-toggle class="mat-slide" formControlName="dataZoom">
{{ 'widgets.range-chart.data-zoom' | translate }} {{ 'widgets.range-chart.data-zoom' | translate }}
</mat-slide-toggle> </mat-slide-toggle>
</div> </div>
<div class="tb-form-row space-between"> <div class="tb-form-panel">
<div>{{ 'widgets.range-chart.range-colors' | translate }}</div> <div class="tb-form-panel-title" translate>widgets.range-chart.range-chart-appearance</div>
<tb-color-range-settings formControlName="rangeColors"> <div class="tb-form-row space-between">
</tb-color-range-settings> <div>{{ 'widgets.range-chart.range-colors' | translate }}</div>
<tb-color-range-settings formControlName="rangeColors">
</tb-color-range-settings>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.range-chart.out-of-range-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="outOfRangeColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showRangeThresholds">
{{ 'widgets.range-chart.show-range-thresholds' | translate }}
</mat-slide-toggle>
<tb-time-series-chart-threshold-settings
boxButton
hideYAxis
[widgetConfig]="widgetConfig?.config"
title="widgets.range-chart.range-thresholds-settings"
formControlName="rangeThreshold">
</tb-time-series-chart-threshold-settings>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="fillArea">
{{ 'widgets.range-chart.fill-area' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.range-chart.fill-area-opacity</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="fillAreaOpacity" min="0" max="1"
step="0.1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field>
</div>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.series.line.line</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showLine">
{{ 'widgets.time-series-chart.series.line.show-line' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="step">
{{ 'widgets.time-series-chart.series.line.step-line' | translate }}
</mat-slide-toggle>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="stepType">
<mat-option *ngFor="let stepType of lineSeriesStepTypes" [value]="stepType">
{{ lineSeriesStepTypeTranslations.get(stepType) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="smooth">
{{ 'widgets.time-series-chart.series.line.smooth-line' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.line-type</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="lineType">
<mat-option *ngFor="let lineType of timeSeriesLineTypes" [value]="lineType">
{{ timeSeriesLineTypeTranslations.get(lineType) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.line-width</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="lineWidth" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field>
</div>
</div>
<div class="tb-form-panel stroked">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.series.point.points</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="showPoints">
{{ 'widgets.time-series-chart.series.point.show-points' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showPointLabel">
<div tb-hint-tooltip-icon="{{'widgets.time-series-chart.series.point.point-label-hint' | translate}}">
{{ 'widgets.time-series-chart.series.point.point-label' | translate }}
</div>
</mat-slide-toggle>
<div fxLayout="row" fxFlex.lt-md fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.lt-md appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointLabelPosition">
<mat-option *ngFor="let position of seriesLabelPositions" [value]="position">
{{ seriesLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="pointLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="pointLabelPreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="pointLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="enablePointLabelBackground">
{{ 'widgets.time-series-chart.series.point.point-label-background' | translate }}
</mat-slide-toggle>
<tb-color-input asBoxInput
colorClearButton
formControlName="pointLabelBackground">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-shape</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of echartsShapes" [value]="shape">
{{ echartsShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-size</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="pointSize" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field>
</div>
</div>
</div> </div>
<div class="tb-form-row space-between"> <div class="tb-form-panel">
<div>{{ 'widgets.range-chart.out-of-range-color' | translate }}</div> <div class="tb-form-panel-title" translate>widgets.time-series-chart.axis.y-axis</div>
<tb-color-input asBoxInput <tb-time-series-chart-axis-settings
colorClearButton formControlName="yAxis"
formControlName="outOfRangeColor"> axisType="yAxis"
</tb-color-input> hideUnits
hideDecimals>
</tb-time-series-chart-axis-settings>
</div> </div>
<div class="tb-form-row"> <div class="tb-form-panel">
<mat-slide-toggle class="mat-slide" formControlName="fillArea"> <div class="tb-form-panel-title" translate>widgets.time-series-chart.axis.x-axis</div>
{{ 'widgets.range-chart.fill-area' | translate }} <tb-time-series-chart-axis-settings
</mat-slide-toggle> formControlName="xAxis"
axisType="xAxis">
</tb-time-series-chart-axis-settings>
</div> </div>
<tb-time-series-chart-thresholds-panel
formControlName="thresholds"
[aliasController]="aliasController"
[dataKeyCallbacks]="dataKeyCallbacks"
[datasource]="datasource"
[widgetConfig]="widgetConfig?.config"
hideYAxis>
</tb-time-series-chart-thresholds-panel>
<div class="tb-form-panel tb-slide-toggle"> <div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="rangeChartWidgetSettingsForm.get('showLegend').value" [disabled]="!rangeChartWidgetSettingsForm.get('showLegend').value"> <mat-expansion-panel class="tb-settings" [expanded]="rangeChartWidgetSettingsForm.get('showLegend').value" [disabled]="!rangeChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap"> <mat-expansion-panel-header fxLayout="row wrap">
@ -139,16 +285,22 @@
</ng-template> </ng-template>
</mat-expansion-panel> </mat-expansion-panel>
</div> </div>
<div class="tb-form-row space-between"> <tb-time-series-chart-animation-settings
<div>{{ 'widgets.background.background' | translate }}</div> formControlName="animation">
<tb-background-settings formControlName="background"> </tb-time-series-chart-animation-settings>
</tb-background-settings> <div class="tb-form-panel">
</div> <div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between"> <div class="tb-form-row space-between">
<div>{{ 'widget-config.card-padding' | translate }}</div> <div>{{ 'widgets.background.background' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic"> <tb-background-settings formControlName="background">
<input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}"> </tb-background-settings>
</mat-form-field> </div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-padding' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="padding" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div> </div>
</div> </div>
</ng-container> </ng-container>

127
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 { Component, Injector } from '@angular/core';
import { import {
Datasource,
legendPositions, legendPositions,
legendPositionTranslationMap, legendPositionTranslationMap,
WidgetSettings, WidgetSettings,
WidgetSettingsComponent WidgetSettingsComponent
} from '@shared/models/widget.models'; } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { formatValue } from '@core/utils'; import { formatValue } from '@core/utils';
import { rangeChartDefaultSettings } from '@home/components/widget/lib/chart/range-chart-widget.models'; import { rangeChartDefaultSettings } from '@home/components/widget/lib/chart/range-chart-widget.models';
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.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({ @Component({
selector: 'tb-range-chart-widget-settings', selector: 'tb-range-chart-widget-settings',
@ -35,12 +42,39 @@ import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-s
}) })
export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent { 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; legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap; legendPositionTranslationMap = legendPositionTranslationMap;
rangeChartWidgetSettingsForm: UntypedFormGroup; rangeChartWidgetSettingsForm: UntypedFormGroup;
pointLabelPreviewFn = this._pointLabelPreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this);
@ -64,7 +98,34 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
dataZoom: [settings.dataZoom, []], dataZoom: [settings.dataZoom, []],
rangeColors: [settings.rangeColors, []], rangeColors: [settings.rangeColors, []],
outOfRangeColor: [settings.outOfRangeColor, []], outOfRangeColor: [settings.outOfRangeColor, []],
showRangeThresholds: [settings.showRangeThresholds, []],
rangeThreshold: [settings.rangeThreshold, []],
fillArea: [settings.fillArea, []], 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, []], showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []], legendPosition: [settings.legendPosition, []],
@ -89,14 +150,69 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
} }
protected validatorTriggers(): string[] { protected validatorTriggers(): string[] {
return ['showLegend', 'showTooltip', 'tooltipShowDate']; return ['showRangeThresholds', 'fillArea', 'showLine', 'step', 'showPointLabel', 'enablePointLabelBackground',
'showLegend', 'showTooltip', 'tooltipShowDate'];
} }
protected updateValidators(emitEvent: boolean) { 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 showLegend: boolean = this.rangeChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.rangeChartWidgetSettingsForm.get('showTooltip').value; const showTooltip: boolean = this.rangeChartWidgetSettingsForm.get('showTooltip').value;
const tooltipShowDate: boolean = this.rangeChartWidgetSettingsForm.get('tooltipShowDate').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) { if (showLegend) {
this.rangeChartWidgetSettingsForm.get('legendPosition').enable(); this.rangeChartWidgetSettingsForm.get('legendPosition').enable();
this.rangeChartWidgetSettingsForm.get('legendLabelFont').enable(); this.rangeChartWidgetSettingsForm.get('legendLabelFont').enable();
@ -137,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 { private _tooltipValuePreviewFn(): string {
const units: string = this.widgetConfig.config.units; const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals; const decimals: number = this.widgetConfig.config.decimals;
@ -149,5 +271,4 @@ export class RangeChartWidgetSettingsComponent extends WidgetSettingsComponent {
processor.update(Date.now()); processor.update(Date.now());
return processor.formatted; return processor.formatted;
} }
} }

9
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.html

@ -59,6 +59,15 @@
</tb-color-input> </tb-color-input>
</div> </div>
</div> </div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="enableLabelBackground">
{{ 'widgets.time-series-chart.series.bar.label-background' | translate }}
</mat-slide-toggle>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelBackground">
</tb-color-input>
</div>
<tb-time-series-chart-fill-settings <tb-time-series-chart-fill-settings
formControlName="backgroundSettings" formControlName="backgroundSettings"
title="widgets.time-series-chart.series.background" title="widgets.time-series-chart.series.background"

14
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-bar-settings.component.ts

@ -76,13 +76,16 @@ export class TimeSeriesChartBarSettingsComponent implements OnInit, ControlValue
labelPosition: [null, []], labelPosition: [null, []],
labelFont: [null, []], labelFont: [null, []],
labelColor: [null, []], labelColor: [null, []],
enableLabelBackground: [null, []],
labelBackground: [null, []],
backgroundSettings: [null, []] backgroundSettings: [null, []]
}); });
this.barSettingsFormGroup.valueChanges.subscribe(() => { this.barSettingsFormGroup.valueChanges.subscribe(() => {
this.updateModel(); this.updateModel();
}); });
merge(this.barSettingsFormGroup.get('showBorder').valueChanges, merge(this.barSettingsFormGroup.get('showBorder').valueChanges,
this.barSettingsFormGroup.get('showLabel').valueChanges) this.barSettingsFormGroup.get('showLabel').valueChanges,
this.barSettingsFormGroup.get('enableLabelBackground').valueChanges)
.subscribe(() => { .subscribe(() => {
this.updateValidators(); this.updateValidators();
}); });
@ -116,6 +119,7 @@ export class TimeSeriesChartBarSettingsComponent implements OnInit, ControlValue
private updateValidators() { private updateValidators() {
const showBorder: boolean = this.barSettingsFormGroup.get('showBorder').value; const showBorder: boolean = this.barSettingsFormGroup.get('showBorder').value;
const showLabel: boolean = this.barSettingsFormGroup.get('showLabel').value; const showLabel: boolean = this.barSettingsFormGroup.get('showLabel').value;
const enableLabelBackground: boolean = this.barSettingsFormGroup.get('enableLabelBackground').value;
if (showBorder) { if (showBorder) {
this.barSettingsFormGroup.get('borderWidth').enable({emitEvent: false}); this.barSettingsFormGroup.get('borderWidth').enable({emitEvent: false});
} else { } else {
@ -125,10 +129,18 @@ export class TimeSeriesChartBarSettingsComponent implements OnInit, ControlValue
this.barSettingsFormGroup.get('labelPosition').enable({emitEvent: false}); this.barSettingsFormGroup.get('labelPosition').enable({emitEvent: false});
this.barSettingsFormGroup.get('labelFont').enable({emitEvent: false}); this.barSettingsFormGroup.get('labelFont').enable({emitEvent: false});
this.barSettingsFormGroup.get('labelColor').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 { } else {
this.barSettingsFormGroup.get('labelPosition').disable({emitEvent: false}); this.barSettingsFormGroup.get('labelPosition').disable({emitEvent: false});
this.barSettingsFormGroup.get('labelFont').disable({emitEvent: false}); this.barSettingsFormGroup.get('labelFont').disable({emitEvent: false});
this.barSettingsFormGroup.get('labelColor').disable({emitEvent: false}); this.barSettingsFormGroup.get('labelColor').disable({emitEvent: false});
this.barSettingsFormGroup.get('enableLabelBackground').disable({emitEvent: false});
this.barSettingsFormGroup.get('labelBackground').disable({emitEvent: false});
} }
} }

13
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.html

@ -97,12 +97,21 @@
</tb-color-input> </tb-color-input>
</div> </div>
</div> </div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="enablePointLabelBackground">
{{ 'widgets.time-series-chart.series.point.point-label-background' | translate }}
</mat-slide-toggle>
<tb-color-input asBoxInput
colorClearButton
formControlName="pointLabelBackground">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs"> <div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.point.point-shape</div> <div translate>widgets.time-series-chart.series.point.point-shape</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape"> <mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape"> <mat-option *ngFor="let shape of echartsShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }} {{ echartsShapeTranslations.get(shape) | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

22
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/time-series-chart-line-settings.component.ts

@ -28,11 +28,11 @@ import {
lineSeriesStepTypeTranslations, lineSeriesStepTypeTranslations,
seriesLabelPositions, seriesLabelPositions,
seriesLabelPositionTranslations, seriesLabelPositionTranslations,
timeSeriesChartShapes, TimeSeriesChartType,
timeSeriesChartShapeTranslations, TimeSeriesChartType,
timeSeriesLineTypes, timeSeriesLineTypes,
timeSeriesLineTypeTranslations timeSeriesLineTypeTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models'; } 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 { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { merge } from 'rxjs'; import { merge } from 'rxjs';
@ -67,9 +67,9 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
seriesLabelPositionTranslations = seriesLabelPositionTranslations; seriesLabelPositionTranslations = seriesLabelPositionTranslations;
timeSeriesChartShapes = timeSeriesChartShapes; echartsShapes = echartsShapes;
timeSeriesChartShapeTranslations = timeSeriesChartShapeTranslations; echartsShapeTranslations = echartsShapeTranslations;
pointLabelPreviewFn = this._pointLabelPreviewFn.bind(this); pointLabelPreviewFn = this._pointLabelPreviewFn.bind(this);
@ -103,6 +103,8 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
pointLabelPosition: [null, []], pointLabelPosition: [null, []],
pointLabelFont: [null, []], pointLabelFont: [null, []],
pointLabelColor: [null, []], pointLabelColor: [null, []],
enablePointLabelBackground: [null, []],
pointLabelBackground: [null, []],
pointShape: [null, []], pointShape: [null, []],
pointSize: [null, [Validators.min(0)]], pointSize: [null, [Validators.min(0)]],
fillAreaSettings: [null, []] fillAreaSettings: [null, []]
@ -112,7 +114,8 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
}); });
merge(this.lineSettingsFormGroup.get('showLine').valueChanges, merge(this.lineSettingsFormGroup.get('showLine').valueChanges,
this.lineSettingsFormGroup.get('step').valueChanges, this.lineSettingsFormGroup.get('step').valueChanges,
this.lineSettingsFormGroup.get('showPointLabel').valueChanges) this.lineSettingsFormGroup.get('showPointLabel').valueChanges,
this.lineSettingsFormGroup.get('enablePointLabelBackground').valueChanges)
.subscribe(() => { .subscribe(() => {
this.updateValidators(); this.updateValidators();
}); });
@ -147,6 +150,7 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
const showLine: boolean = this.lineSettingsFormGroup.get('showLine').value; const showLine: boolean = this.lineSettingsFormGroup.get('showLine').value;
const step: boolean = this.lineSettingsFormGroup.get('step').value; const step: boolean = this.lineSettingsFormGroup.get('step').value;
const showPointLabel: boolean = this.lineSettingsFormGroup.get('showPointLabel').value; const showPointLabel: boolean = this.lineSettingsFormGroup.get('showPointLabel').value;
const enablePointLabelBackground: boolean = this.lineSettingsFormGroup.get('enablePointLabelBackground').value;
if (showLine) { if (showLine) {
this.lineSettingsFormGroup.get('step').enable({emitEvent: false}); this.lineSettingsFormGroup.get('step').enable({emitEvent: false});
if (step) { if (step) {
@ -169,10 +173,18 @@ export class TimeSeriesChartLineSettingsComponent implements OnInit, ControlValu
this.lineSettingsFormGroup.get('pointLabelPosition').enable({emitEvent: false}); this.lineSettingsFormGroup.get('pointLabelPosition').enable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelFont').enable({emitEvent: false}); this.lineSettingsFormGroup.get('pointLabelFont').enable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelColor').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 { } else {
this.lineSettingsFormGroup.get('pointLabelPosition').disable({emitEvent: false}); this.lineSettingsFormGroup.get('pointLabelPosition').disable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelFont').disable({emitEvent: false}); this.lineSettingsFormGroup.get('pointLabelFont').disable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelColor').disable({emitEvent: false}); this.lineSettingsFormGroup.get('pointLabelColor').disable({emitEvent: false});
this.lineSettingsFormGroup.get('enablePointLabelBackground').disable({emitEvent: false});
this.lineSettingsFormGroup.get('pointLabelBackground').disable({emitEvent: false});
} }
} }

4
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.html

@ -27,8 +27,8 @@
<div class="tb-form-row space-between column-xs"> <div class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.series.opacity</div> <div translate>widgets.time-series-chart.series.opacity</div>
<mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="medium-width number" appearance="outline" subscriptSizing="dynamic">
<input matInput type="number" formControlName="opacity" min="0" max="100" <input matInput type="number" formControlName="opacity" min="0" max="1"
step="1" placeholder="{{ 'widget-config.set' | translate }}"/> step="0.1" placeholder="{{ 'widget-config.set' | translate }}"/>
</mat-form-field> </mat-form-field>
</div> </div>
</ng-container> </ng-container>

2
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component.ts

@ -73,7 +73,7 @@ export class TimeSeriesChartFillSettingsComponent implements OnInit, ControlValu
ngOnInit(): void { ngOnInit(): void {
this.fillSettingsFormGroup = this.fb.group({ this.fillSettingsFormGroup = this.fb.group({
type: [null, []], type: [null, []],
opacity: [null, [Validators.min(0), Validators.max(100)]], opacity: [null, [Validators.min(0), Validators.max(1)]],
gradient: this.fb.group({ gradient: this.fb.group({
start: [null, [Validators.min(0), Validators.max(100)]], start: [null, [Validators.min(0), Validators.max(100)]],
end: [null, [Validators.min(0), Validators.max(100)]] end: [null, [Validators.min(0), Validators.max(100)]]

15
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.html

@ -98,14 +98,13 @@
</mat-form-field> </mat-form-field>
</div> </div>
<div class="tb-form-table-row-cell-buttons"> <div class="tb-form-table-row-cell-buttons">
<button type="button" <tb-time-series-chart-threshold-settings
mat-icon-button [widgetConfig]="widgetConfig"
#matButton [yAxisIds]="yAxisIds"
(click)="editThreshold($event, matButton)" [hideYAxis]="hideYAxis"
matTooltip="{{ 'widgets.time-series-chart.threshold.threshold-settings' | translate }}" icon="settings"
matTooltipPosition="above"> [formControl]="thresholdSettingsFormControl">
<mat-icon>settings</mat-icon> </tb-time-series-chart-threshold-settings>
</button>
<button type="button" <button type="button"
mat-icon-button mat-icon-button
(click)="thresholdRemoved.emit()" (click)="thresholdRemoved.emit()"

74
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-row.component.ts

@ -19,11 +19,11 @@ import {
Component, Component,
EventEmitter, EventEmitter,
forwardRef, forwardRef,
Input, OnChanges, Input,
OnChanges,
OnInit, OnInit,
Output, Output,
Renderer2, SimpleChanges, SimpleChanges,
ViewContainerRef,
ViewEncapsulation ViewEncapsulation
} from '@angular/core'; } from '@angular/core';
import { import {
@ -36,7 +36,8 @@ import {
} from '@angular/forms'; } from '@angular/forms';
import { import {
TimeSeriesChartThreshold, TimeSeriesChartThreshold,
TimeSeriesChartThresholdType, TimeSeriesChartYAxisId, TimeSeriesChartThresholdType,
TimeSeriesChartYAxisId,
timeSeriesThresholdTypes, timeSeriesThresholdTypes,
timeSeriesThresholdTypeTranslations timeSeriesThresholdTypeTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
@ -47,12 +48,7 @@ import { IAliasController } from '@core/api/widget-api.models';
import { DataKey, Datasource, DatasourceType, WidgetConfig } from '@shared/models/widget.models'; import { DataKey, Datasource, DatasourceType, WidgetConfig } from '@shared/models/widget.models';
import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models'; import { DataKeysCallbacks } from '@home/components/widget/config/data-keys.component.models';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { deepClone } from '@core/utils'; import { deepClone } from '@core/utils';
import {
TimeSeriesChartThresholdSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component';
import { coerceBoolean } from '@shared/decorators/coercion'; import { coerceBoolean } from '@shared/decorators/coercion';
@Component({ @Component({
@ -117,12 +113,11 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
entityKeyFormControl: UntypedFormControl; entityKeyFormControl: UntypedFormControl;
thresholdSettingsFormControl: UntypedFormControl;
private propagateChange = (_val: any) => {}; private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder, constructor(private fb: UntypedFormBuilder,
private popoverService: TbPopoverService,
private renderer: Renderer2,
private viewContainerRef: ViewContainerRef,
private thresholdsPanel: TimeSeriesChartThresholdsPanelComponent, private thresholdsPanel: TimeSeriesChartThresholdsPanelComponent,
private cd: ChangeDetectorRef) { private cd: ChangeDetectorRef) {
} }
@ -139,6 +134,7 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
}); });
this.latestKeyFormControl = this.fb.control(null, [Validators.required]); this.latestKeyFormControl = this.fb.control(null, [Validators.required]);
this.entityKeyFormControl = this.fb.control(null, [Validators.required]); this.entityKeyFormControl = this.fb.control(null, [Validators.required]);
this.thresholdSettingsFormControl = this.fb.control(null);
this.thresholdFormGroup.valueChanges.subscribe( this.thresholdFormGroup.valueChanges.subscribe(
() => this.updateModel() () => this.updateModel()
); );
@ -148,6 +144,18 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
this.entityKeyFormControl.valueChanges.subscribe( this.entityKeyFormControl.valueChanges.subscribe(
() => this.updateModel() () => this.updateModel()
); );
this.thresholdSettingsFormControl.valueChanges.subscribe((thresholdSettings: Partial<TimeSeriesChartThreshold>) => {
this.modelValue = {...this.modelValue, ...thresholdSettings};
this.thresholdFormGroup.patchValue(
{
yAxisId: this.modelValue.yAxisId,
units: this.modelValue.units,
decimals: this.modelValue.decimals,
lineColor: this.modelValue.lineColor
},
{emitEvent: false});
this.propagateChange(this.modelValue);
});
this.thresholdFormGroup.get('type').valueChanges.subscribe(() => { this.thresholdFormGroup.get('type').valueChanges.subscribe(() => {
this.updateValidators(); this.updateValidators();
}); });
@ -180,8 +188,10 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
this.thresholdFormGroup.disable({emitEvent: false}); this.thresholdFormGroup.disable({emitEvent: false});
this.latestKeyFormControl.disable({emitEvent: false}); this.latestKeyFormControl.disable({emitEvent: false});
this.entityKeyFormControl.disable({emitEvent: false}); this.entityKeyFormControl.disable({emitEvent: false});
this.thresholdSettingsFormControl.disable({emitEvent: false});
} else { } else {
this.thresholdFormGroup.enable({emitEvent: false}); this.thresholdFormGroup.enable({emitEvent: false});
this.thresholdSettingsFormControl.enable({emitEvent: false});
this.updateValidators(); this.updateValidators();
} }
} }
@ -210,46 +220,12 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
name: value.entityKey name: value.entityKey
}, {emitEvent: false}); }, {emitEvent: false});
} }
this.thresholdSettingsFormControl.patchValue(deepClone(this.modelValue),
{emitEvent: false});
this.updateValidators(); this.updateValidators();
this.cd.markForCheck(); this.cd.markForCheck();
} }
editThreshold($event: Event, matButton: MatButton) {
if ($event) {
$event.stopPropagation();
}
const trigger = matButton._elementRef.nativeElement;
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
const ctx: any = {
thresholdSettings: deepClone(this.modelValue),
widgetConfig: this.widgetConfig,
hideYAxis: this.hideYAxis,
yAxisIds: this.yAxisIds
};
const thresholdSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, TimeSeriesChartThresholdSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null,
ctx,
{},
{}, {}, true);
thresholdSettingsPanelPopover.tbComponentRef.instance.popover = thresholdSettingsPanelPopover;
thresholdSettingsPanelPopover.tbComponentRef.instance.thresholdSettingsApplied.subscribe((thresholdSettings) => {
thresholdSettingsPanelPopover.hide();
this.modelValue = {...this.modelValue, ...thresholdSettings};
this.thresholdFormGroup.patchValue(
{
yAxisId: this.modelValue.yAxisId,
units: this.modelValue.units,
decimals: this.modelValue.decimals,
lineColor: this.modelValue.lineColor
},
{emitEvent: false});
this.propagateChange(this.modelValue);
});
}
}
private updateValidators() { private updateValidators() {
const type: TimeSeriesChartThresholdType = this.thresholdFormGroup.get('type').value; const type: TimeSeriesChartThresholdType = this.thresholdFormGroup.get('type').value;
if (type === TimeSeriesChartThresholdType.constant) { if (type === TimeSeriesChartThresholdType.constant) {
@ -288,6 +264,8 @@ export class TimeSeriesChartThresholdRowComponent implements ControlValueAccesso
this.modelValue.entityKey = entityKey?.name; this.modelValue.entityKey = entityKey?.name;
this.modelValue.entityKeyType = (entityKey?.type as any); this.modelValue.entityKeyType = (entityKey?.type as any);
} }
this.thresholdSettingsFormControl.patchValue(deepClone(this.modelValue),
{emitEvent: false});
this.propagateChange(this.modelValue); this.propagateChange(this.modelValue);
} }
} }

19
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.html

@ -16,7 +16,7 @@
--> -->
<div class="tb-threshold-settings-panel" [formGroup]="thresholdSettingsFormGroup"> <div class="tb-threshold-settings-panel" [formGroup]="thresholdSettingsFormGroup">
<div class="tb-threshold-settings-title">{{ 'widgets.time-series-chart.threshold.threshold-settings' | translate }}</div> <div class="tb-threshold-settings-title">{{ panelTitle | translate }}</div>
<div class="tb-threshold-settings-panel-content"> <div class="tb-threshold-settings-panel-content">
<div *ngIf="!hideYAxis" class="tb-form-row space-between column-xs"> <div *ngIf="!hideYAxis" class="tb-form-row space-between column-xs">
<div translate>widgets.time-series-chart.axis.y-axis</div> <div translate>widgets.time-series-chart.axis.y-axis</div>
@ -64,6 +64,15 @@
</tb-color-input> </tb-color-input>
</div> </div>
</div> </div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="enableLabelBackground">
{{ 'widgets.time-series-chart.threshold.label-background' | translate }}
</mat-slide-toggle>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelBackground">
</tb-color-input>
</div>
<div class="tb-form-panel"> <div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.time-series-chart.threshold.line-appearance</div> <div class="tb-form-panel-title" translate>widgets.time-series-chart.threshold.line-appearance</div>
<div class="tb-form-row space-between"> <div class="tb-form-row space-between">
@ -94,8 +103,8 @@
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="startSymbol"> <mat-select formControlName="startSymbol">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape"> <mat-option *ngFor="let shape of echartsShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }} {{ echartsShapeTranslations.get(shape) | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>
@ -111,8 +120,8 @@
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> <div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic"> <mat-form-field class="flex" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="endSymbol"> <mat-select formControlName="endSymbol">
<mat-option *ngFor="let shape of timeSeriesChartShapes" [value]="shape"> <mat-option *ngFor="let shape of echartsShapes" [value]="shape">
{{ timeSeriesChartShapeTranslations.get(shape) | translate }} {{ echartsShapeTranslations.get(shape) | translate }}
</mat-option> </mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

40
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component.ts

@ -18,15 +18,18 @@ import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } fro
import { TbPopoverComponent } from '@shared/components/popover.component'; import { TbPopoverComponent } from '@shared/components/popover.component';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { import {
TimeSeriesChartShape, TimeSeriesChartThreshold,
timeSeriesChartShapes, TimeSeriesChartYAxisId,
timeSeriesChartShapeTranslations,
TimeSeriesChartThreshold, TimeSeriesChartYAxisId,
timeSeriesLineTypes, timeSeriesLineTypes,
timeSeriesLineTypeTranslations, timeSeriesLineTypeTranslations,
timeSeriesThresholdLabelPositions, timeSeriesThresholdLabelPositions,
timeSeriesThresholdLabelPositionTranslations timeSeriesThresholdLabelPositionTranslations
} from '@home/components/widget/lib/chart/time-series-chart.models'; } from '@home/components/widget/lib/chart/time-series-chart.models';
import {
EChartsShape,
echartsShapes,
echartsShapeTranslations
} from '@home/components/widget/lib/chart/echarts-widget.models';
import { merge } from 'rxjs'; import { merge } from 'rxjs';
import { WidgetConfig } from '@shared/models/widget.models'; import { WidgetConfig } from '@shared/models/widget.models';
import { formatValue, isDefinedAndNotNull } from '@core/utils'; import { formatValue, isDefinedAndNotNull } from '@core/utils';
@ -45,9 +48,9 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit {
timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations; timeSeriesLineTypeTranslations = timeSeriesLineTypeTranslations;
timeSeriesChartShapes = timeSeriesChartShapes; echartsShapes = echartsShapes;
timeSeriesChartShapeTranslations = timeSeriesChartShapeTranslations; echartsShapeTranslations = echartsShapeTranslations;
timeSeriesThresholdLabelPositions = timeSeriesThresholdLabelPositions; timeSeriesThresholdLabelPositions = timeSeriesThresholdLabelPositions;
@ -71,6 +74,9 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit {
@coerceBoolean() @coerceBoolean()
hideYAxis = false; hideYAxis = false;
@Input()
panelTitle = 'widgets.time-series-chart.threshold.threshold-settings';
@Output() @Output()
thresholdSettingsApplied = new EventEmitter<Partial<TimeSeriesChartThreshold>>(); thresholdSettingsApplied = new EventEmitter<Partial<TimeSeriesChartThreshold>>();
@ -95,10 +101,13 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit {
showLabel: [this.thresholdSettings.showLabel, []], showLabel: [this.thresholdSettings.showLabel, []],
labelPosition: [this.thresholdSettings.labelPosition, []], labelPosition: [this.thresholdSettings.labelPosition, []],
labelFont: [this.thresholdSettings.labelFont, []], labelFont: [this.thresholdSettings.labelFont, []],
labelColor: [this.thresholdSettings.labelColor, []] labelColor: [this.thresholdSettings.labelColor, []],
enableLabelBackground: [this.thresholdSettings.enableLabelBackground, []],
labelBackground: [this.thresholdSettings.labelBackground, []]
} }
); );
merge(this.thresholdSettingsFormGroup.get('showLabel').valueChanges, merge(this.thresholdSettingsFormGroup.get('showLabel').valueChanges,
this.thresholdSettingsFormGroup.get('enableLabelBackground').valueChanges,
this.thresholdSettingsFormGroup.get('startSymbol').valueChanges, this.thresholdSettingsFormGroup.get('startSymbol').valueChanges,
this.thresholdSettingsFormGroup.get('endSymbol').valueChanges).subscribe(() => { this.thresholdSettingsFormGroup.get('endSymbol').valueChanges).subscribe(() => {
this.updateValidators(); this.updateValidators();
@ -117,23 +126,32 @@ export class TimeSeriesChartThresholdSettingsPanelComponent implements OnInit {
private updateValidators() { private updateValidators() {
const showLabel: boolean = this.thresholdSettingsFormGroup.get('showLabel').value; const showLabel: boolean = this.thresholdSettingsFormGroup.get('showLabel').value;
const startSymbol: TimeSeriesChartShape = this.thresholdSettingsFormGroup.get('startSymbol').value; const enableLabelBackground: boolean = this.thresholdSettingsFormGroup.get('enableLabelBackground').value;
const endSymbol: TimeSeriesChartShape = this.thresholdSettingsFormGroup.get('endSymbol').value; const startSymbol: EChartsShape = this.thresholdSettingsFormGroup.get('startSymbol').value;
const endSymbol: EChartsShape = this.thresholdSettingsFormGroup.get('endSymbol').value;
if (showLabel) { if (showLabel) {
this.thresholdSettingsFormGroup.get('labelPosition').enable({emitEvent: false}); this.thresholdSettingsFormGroup.get('labelPosition').enable({emitEvent: false});
this.thresholdSettingsFormGroup.get('labelFont').enable({emitEvent: false}); this.thresholdSettingsFormGroup.get('labelFont').enable({emitEvent: false});
this.thresholdSettingsFormGroup.get('labelColor').enable({emitEvent: false}); this.thresholdSettingsFormGroup.get('labelColor').enable({emitEvent: false});
this.thresholdSettingsFormGroup.get('enableLabelBackground').enable({emitEvent: false});
if (enableLabelBackground) {
this.thresholdSettingsFormGroup.get('labelBackground').enable({emitEvent: false});
} else {
this.thresholdSettingsFormGroup.get('labelBackground').disable({emitEvent: false});
}
} else { } else {
this.thresholdSettingsFormGroup.get('labelPosition').disable({emitEvent: false}); this.thresholdSettingsFormGroup.get('labelPosition').disable({emitEvent: false});
this.thresholdSettingsFormGroup.get('labelFont').disable({emitEvent: false}); this.thresholdSettingsFormGroup.get('labelFont').disable({emitEvent: false});
this.thresholdSettingsFormGroup.get('labelColor').disable({emitEvent: false}); this.thresholdSettingsFormGroup.get('labelColor').disable({emitEvent: false});
this.thresholdSettingsFormGroup.get('enableLabelBackground').disable({emitEvent: false});
this.thresholdSettingsFormGroup.get('labelBackground').disable({emitEvent: false});
} }
if (startSymbol === TimeSeriesChartShape.none) { if (startSymbol === EChartsShape.none) {
this.thresholdSettingsFormGroup.get('startSymbolSize').disable({emitEvent: false}); this.thresholdSettingsFormGroup.get('startSymbolSize').disable({emitEvent: false});
} else { } else {
this.thresholdSettingsFormGroup.get('startSymbolSize').enable({emitEvent: false}); this.thresholdSettingsFormGroup.get('startSymbolSize').enable({emitEvent: false});
} }
if (endSymbol === TimeSeriesChartShape.none) { if (endSymbol === EChartsShape.none) {
this.thresholdSettingsFormGroup.get('endSymbolSize').disable({emitEvent: false}); this.thresholdSettingsFormGroup.get('endSymbolSize').disable({emitEvent: false});
} else { } else {
this.thresholdSettingsFormGroup.get('endSymbolSize').enable({emitEvent: false}); this.thresholdSettingsFormGroup.get('endSymbolSize').enable({emitEvent: false});

39
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.html

@ -0,0 +1,39 @@
<!--
Copyright © 2016-2024 The Thingsboard Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<button *ngIf="boxButton; else iconButton"
type="button"
mat-stroked-button
class="tb-box-button"
[disabled]="disabled"
#matButton
(click)="openThresholdSettingsPopup($event, matButton)"
matTooltip="{{ title | translate }}"
matTooltipPosition="above">
<tb-icon matButtonIcon>{{icon}}</tb-icon>
</button>
<ng-template #iconButton>
<button type="button"
mat-icon-button
[disabled]="disabled"
#matButton
(click)="openThresholdSettingsPopup($event, matButton)"
matTooltip="{{ title | translate }}"
matTooltipPosition="above">
<tb-icon>{{icon}}</tb-icon>
</button>
</ng-template>

124
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component.ts

@ -0,0 +1,124 @@
///
/// Copyright © 2016-2024 The Thingsboard Authors
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit, Renderer2, ViewContainerRef } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatButton } from '@angular/material/button';
import { TbPopoverService } from '@shared/components/popover.service';
import { deepClone } from '@core/utils';
import { coerceBoolean } from '@shared/decorators/coercion';
import { WidgetConfig } from '@shared/models/widget.models';
import {
TimeSeriesChartThreshold,
TimeSeriesChartYAxisId
} from '@home/components/widget/lib/chart/time-series-chart.models';
import {
TimeSeriesChartThresholdSettingsPanelComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings-panel.component';
@Component({
selector: 'tb-time-series-chart-threshold-settings',
templateUrl: './time-series-chart-threshold-settings.component.html',
styleUrls: [],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => TimeSeriesChartThresholdSettingsComponent),
multi: true
}
]
})
export class TimeSeriesChartThresholdSettingsComponent implements OnInit, ControlValueAccessor {
@Input()
disabled: boolean;
@Input()
widgetConfig: WidgetConfig;
@Input()
yAxisIds: TimeSeriesChartYAxisId[];
@Input()
@coerceBoolean()
hideYAxis = false;
@Input()
@coerceBoolean()
boxButton = false;
@Input()
icon = 'settings';
@Input()
title = 'widgets.time-series-chart.threshold.threshold-settings';
private modelValue: Partial<TimeSeriesChartThreshold>;
private propagateChange = null;
constructor(private popoverService: TbPopoverService,
private renderer: Renderer2,
private viewContainerRef: ViewContainerRef) {}
ngOnInit(): void {
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
registerOnTouched(fn: any): void {
}
setDisabledState(isDisabled: boolean): void {
this.disabled = isDisabled;
}
writeValue(value: Partial<TimeSeriesChartThreshold>): void {
this.modelValue = value;
}
openThresholdSettingsPopup($event: Event, matButton: MatButton) {
if ($event) {
$event.stopPropagation();
}
const trigger = matButton._elementRef.nativeElement;
if (this.popoverService.hasPopover(trigger)) {
this.popoverService.hidePopover(trigger);
} else {
const ctx: any = {
thresholdSettings: deepClone(this.modelValue),
panelTitle: this.title,
widgetConfig: this.widgetConfig,
hideYAxis: this.hideYAxis,
yAxisIds: this.yAxisIds
};
const thresholdSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
this.viewContainerRef, TimeSeriesChartThresholdSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null,
ctx,
{},
{}, {}, true);
thresholdSettingsPanelPopover.tbComponentRef.instance.popover = thresholdSettingsPanelPopover;
thresholdSettingsPanelPopover.tbComponentRef.instance.thresholdSettingsApplied.subscribe((thresholdSettings) => {
thresholdSettingsPanelPopover.hide();
this.modelValue = thresholdSettings;
this.propagateChange(this.modelValue);
});
}
}
}

5
ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts

@ -130,6 +130,9 @@ import {
import { import {
TimeSeriesChartFillSettingsComponent TimeSeriesChartFillSettingsComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component'; } from '@home/components/widget/lib/settings/common/chart/time-series-chart-fill-settings.component';
import {
TimeSeriesChartThresholdSettingsComponent
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-threshold-settings.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -178,6 +181,7 @@ import {
TimeSeriesChartYAxisSettingsPanelComponent, TimeSeriesChartYAxisSettingsPanelComponent,
TimeSeriesChartAnimationSettingsComponent, TimeSeriesChartAnimationSettingsComponent,
TimeSeriesChartFillSettingsComponent, TimeSeriesChartFillSettingsComponent,
TimeSeriesChartThresholdSettingsComponent,
DataKeyInputComponent, DataKeyInputComponent,
EntityAliasInputComponent EntityAliasInputComponent
], ],
@ -232,6 +236,7 @@ import {
TimeSeriesChartYAxisSettingsPanelComponent, TimeSeriesChartYAxisSettingsPanelComponent,
TimeSeriesChartAnimationSettingsComponent, TimeSeriesChartAnimationSettingsComponent,
TimeSeriesChartFillSettingsComponent, TimeSeriesChartFillSettingsComponent,
TimeSeriesChartThresholdSettingsComponent,
DataKeyInputComponent, DataKeyInputComponent,
EntityAliasInputComponent EntityAliasInputComponent
], ],

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

@ -6176,9 +6176,10 @@
"range-colors": "Range colors", "range-colors": "Range colors",
"out-of-range-color": "Out of range color", "out-of-range-color": "Out of range color",
"show-range-thresholds": "Show range thresholds", "show-range-thresholds": "Show range thresholds",
"range-thresholds-settings": "Range thresholds settings",
"fill-area": "Fill area", "fill-area": "Fill area",
"fill-area-opacity": "Fill area opacity", "fill-area-opacity": "Fill area opacity",
"range-chart-card-style": "Range chart card style" "range-chart-style": "Range chart style"
}, },
"rpc": { "rpc": {
"value-settings": "Value settings", "value-settings": "Value settings",
@ -6772,7 +6773,8 @@
"label-position-inside-middle-bottom": "Inside middle bottom", "label-position-inside-middle-bottom": "Inside middle bottom",
"label-position-inside-end": "Inside end", "label-position-inside-end": "Inside end",
"label-position-inside-end-top": "Inside end top", "label-position-inside-end-top": "Inside end top",
"label-position-inside-end-bottom": "Inside end bottom" "label-position-inside-end-bottom": "Inside end bottom",
"label-background": "Label background"
}, },
"axis": { "axis": {
"axes": "Axes", "axes": "Axes",
@ -6853,6 +6855,7 @@
"show-points": "Show points", "show-points": "Show points",
"point-label": "Point label", "point-label": "Point label",
"point-label-hint": "Display label with value over the series point.", "point-label-hint": "Display label with value over the series point.",
"point-label-background": "Point label background",
"point-shape": "Point shape", "point-shape": "Point shape",
"point-size": "Point size" "point-size": "Point size"
}, },
@ -6861,7 +6864,8 @@
"border-width": "Border width", "border-width": "Border width",
"border-radius": "Border radius", "border-radius": "Border radius",
"label": "Label", "label": "Label",
"label-hint": "Display label with value over the bar." "label-hint": "Display label with value over the bar.",
"label-background": "Label background"
} }
} }
}, },

2
ui-ngx/src/assets/locale/locale.constant-pl_PL.json

@ -5924,7 +5924,7 @@
"range-colors":"Kolory zakresu", "range-colors":"Kolory zakresu",
"out-of-range-color":"Kolor poza zakresem", "out-of-range-color":"Kolor poza zakresem",
"fill-area":"Wypełnij obszar", "fill-area":"Wypełnij obszar",
"range-chart-card-style":"Styl karty wykresu zakresu" "range-chart-style":"Styl wykresu zakresu"
}, },
"rpc":{ "rpc":{
"value-settings":"Ustawienia wartości", "value-settings":"Ustawienia wartości",

2
ui-ngx/src/assets/locale/locale.constant-zh_CN.json

@ -5491,7 +5491,7 @@
"range-colors": "范围颜色", "range-colors": "范围颜色",
"out-of-range-color": "超出范围颜色", "out-of-range-color": "超出范围颜色",
"fill-area": "填充区域", "fill-area": "填充区域",
"range-chart-card-style": "范围图表卡片样式" "range-chart-style": "范围图样式"
}, },
"rpc": { "rpc": {
"value-settings": "值设置", "value-settings": "值设置",

Loading…
Cancel
Save