Browse Source

UI: Improve latest chart widgets configuration.

pull/10686/head
Igor Kulikov 2 years ago
parent
commit
e48bd45ab8
  1. 261
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-basic-config.component.html
  2. 284
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/bar-chart-basic-config.component.ts
  3. 258
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/doughnut-basic-config.component.html
  4. 318
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/doughnut-basic-config.component.ts
  5. 529
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/latest-chart-basic-config.component.html
  6. 366
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/latest-chart-basic-config.component.ts
  7. 276
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/pie-chart-basic-config.component.html
  8. 311
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/pie-chart-basic-config.component.ts
  9. 268
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/polar-area-chart-basic-config.component.html
  10. 288
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/polar-area-chart-basic-config.component.ts
  11. 340
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/radar-chart-basic-config.component.html
  12. 385
      ui-ngx/src/app/modules/home/components/widget/config/basic/chart/radar-chart-basic-config.component.ts
  13. 169
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-widget-settings.component.html
  14. 146
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/bar-chart-widget-settings.component.ts
  15. 166
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-widget-settings.component.html
  16. 176
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-widget-settings.component.ts
  17. 463
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.html
  18. 217
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.ts
  19. 184
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/pie-chart-widget-settings.component.html
  20. 172
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/pie-chart-widget-settings.component.ts
  21. 176
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/polar-area-chart-widget-settings.component.html
  22. 146
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/polar-area-chart-widget-settings.component.ts
  23. 248
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.html
  24. 244
      ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.ts
  25. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

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

@ -1,261 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="barChartWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDatasourceLabel
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideUnits
hideDecimals
hideDataKeyUnits
hideDataKeyDecimals
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="barChartWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.card-icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="barChartWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="barChartWidgetConfigForm.get('showLegend').value" [disabled]="!barChartWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="barChartWidgetConfigForm.get('showTooltip').value" [disabled]="!barChartWidgetConfigForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

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

@ -14,86 +14,36 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { DataKey } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { formatValue, isUndefined, mergeDeep } from '@core/utils';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
barChartWidgetDefaultSettings,
BarChartWidgetSettings
} from '@home/components/widget/lib/chart/bar-chart-widget.models';
import {
LatestChartBasicConfigComponent
} from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
@Component({
selector: 'tb-bar-chart-basic-config',
templateUrl: './bar-chart-basic-config.component.html',
templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class BarChartBasicConfigComponent extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.barChartWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
public get displayTimewindowConfig(): boolean {
const datasources = this.barChartWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.barChartWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
barChartWidgetConfigForm: UntypedFormGroup;
export class BarChartBasicConfigComponent extends LatestChartBasicConfigComponent<BarChartWidgetSettings> {
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('barChart')
barChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.barChartWidgetConfigForm;
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] {
@ -102,215 +52,29 @@ export class BarChartBasicConfigComponent extends BasicWidgetConfigComponent {
{ name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30' }];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: BarChartWidgetSettings = mergeDeep<BarChartWidgetSettings>({} as BarChartWidgetSettings,
barChartWidgetDefaultSettings, configData.config.settings as BarChartWidgetSettings);
this.barChartWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
titleFont: [configData.config.titleFont, []],
titleColor: [configData.config.titleColor, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
sortSeries: [settings.sortSeries, []],
units: [configData.config.units, []],
decimals: [configData.config.decimals, []],
barSettings: [settings.barSettings, []],
axisMin: [settings.axisMin, []],
axisMax: [settings.axisMax, []],
axisTickLabelFont: [settings.axisTickLabelFont, []],
axisTickLabelColor: [settings.axisTickLabelColor, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
protected defaultSettings() {
return barChartWidgetDefaultSettings;
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
public latestChartConfigTemplate(): TemplateRef<any> {
return this.barChartConfigTemplate;
}
this.widgetConfig.config.settings.sortSeries = config.sortSeries;
protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: BarChartWidgetSettings) {
latestChartWidgetConfigForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
latestChartWidgetConfigForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
latestChartWidgetConfigForm.addControl('axisMax', this.fb.control(settings.axisMax, []));
latestChartWidgetConfigForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
latestChartWidgetConfigForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
}
protected prepareOutputLatestChartConfig(config: any) {
this.widgetConfig.config.settings.barSettings = config.barSettings;
this.widgetConfig.config.settings.axisMin = config.axisMin;
this.widgetConfig.config.settings.axisMax = config.axisMax;
this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont;
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor;
this.widgetConfig.config.settings.animation = config.animation;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendPosition = config.legendPosition;
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont;
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor;
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont;
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor;
this.widgetConfig.config.settings.showTooltip = config.showTooltip;
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType;
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals;
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont;
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
this.widgetConfig.config.settings.background = config.background;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon', 'showLegend', 'showTooltip'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.barChartWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.barChartWidgetConfigForm.get('showTitleIcon').value;
const showLegend: boolean = this.barChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.barChartWidgetConfigForm.get('showTooltip').value;
if (showTitle) {
this.barChartWidgetConfigForm.get('title').enable();
this.barChartWidgetConfigForm.get('titleFont').enable();
this.barChartWidgetConfigForm.get('titleColor').enable();
this.barChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.barChartWidgetConfigForm.get('titleIcon').enable();
this.barChartWidgetConfigForm.get('iconColor').enable();
} else {
this.barChartWidgetConfigForm.get('titleIcon').disable();
this.barChartWidgetConfigForm.get('iconColor').disable();
}
} else {
this.barChartWidgetConfigForm.get('title').disable();
this.barChartWidgetConfigForm.get('titleFont').disable();
this.barChartWidgetConfigForm.get('titleColor').disable();
this.barChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.barChartWidgetConfigForm.get('titleIcon').disable();
this.barChartWidgetConfigForm.get('iconColor').disable();
}
if (showLegend) {
this.barChartWidgetConfigForm.get('legendPosition').enable();
this.barChartWidgetConfigForm.get('legendLabelFont').enable();
this.barChartWidgetConfigForm.get('legendLabelColor').enable();
this.barChartWidgetConfigForm.get('legendValueFont').enable();
this.barChartWidgetConfigForm.get('legendValueColor').enable();
} else {
this.barChartWidgetConfigForm.get('legendPosition').disable();
this.barChartWidgetConfigForm.get('legendLabelFont').disable();
this.barChartWidgetConfigForm.get('legendLabelColor').disable();
this.barChartWidgetConfigForm.get('legendValueFont').disable();
this.barChartWidgetConfigForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.barChartWidgetConfigForm.get('tooltipValueType').enable();
this.barChartWidgetConfigForm.get('tooltipValueDecimals').enable();
this.barChartWidgetConfigForm.get('tooltipValueFont').enable();
this.barChartWidgetConfigForm.get('tooltipValueColor').enable();
this.barChartWidgetConfigForm.get('tooltipBackgroundColor').enable();
this.barChartWidgetConfigForm.get('tooltipBackgroundBlur').enable();
} else {
this.barChartWidgetConfigForm.get('tooltipValueType').disable();
this.barChartWidgetConfigForm.get('tooltipValueDecimals').disable();
this.barChartWidgetConfigForm.get('tooltipValueFont').disable();
this.barChartWidgetConfigForm.get('tooltipValueColor').disable();
this.barChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.barChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}
}
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
private _valuePreviewFn(): string {
const units: string = this.barChartWidgetConfigForm.get('units').value;
const decimals: number = this.barChartWidgetConfigForm.get('decimals').value;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.barChartWidgetConfigForm.get('tooltipValueType').value;
const decimals: number = this.barChartWidgetConfigForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.barChartWidgetConfigForm.get('units').value;
return formatValue(110, decimals, units, false);
}
}
}

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

@ -1,258 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="doughnutWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDatasourceLabel
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideUnits
hideDecimals
hideDataKeyUnits
hideDataKeyDecimals
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<tb-image-cards-select rowHeight="{{ horizontal ? '8:5' : '5:4' }}"
[cols]="{columns: 2,
breakpoints: {
'lt-sm': 1
}}"
label="{{ 'widgets.doughnut.layout' | translate }}" formControlName="layout">
<tb-image-cards-select-option *ngFor="let layout of doughnutLayouts"
[value]="layout"
[image]="doughnutLayoutImageMap.get(layout)">
{{ doughnutLayoutTranslationMap.get(layout) | translate }}
</tb-image-cards-select-option>
</tb-image-cards-select>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="autoScale">
{{ 'widgets.latest-chart.auto-scale' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="doughnutWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.card-icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="doughnutWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div [fxShow]="totalEnabled" class="tb-form-row space-between">
<div>{{ 'widgets.doughnut.central-total-value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="totalValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-settings formControlName="totalValueColor" settingsKey="{{'widgets.doughnut.central-total-value' | translate }}">
</tb-color-settings>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="doughnutWidgetConfigForm.get('showLegend').value" [disabled]="!doughnutWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="doughnutWidgetConfigForm.get('showTooltip').value" [disabled]="!doughnutWidgetConfigForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

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

@ -14,111 +14,37 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { DataKey } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { formatValue, isDefinedAndNotNull, isUndefined, mergeDeep } from '@core/utils';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import {
doughnutDefaultSettings,
DoughnutLayout,
doughnutLayoutImages,
doughnutLayouts,
doughnutLayoutTranslations,
DoughnutWidgetSettings,
horizontalDoughnutLayoutImages
DoughnutWidgetSettings
} from '@home/components/widget/lib/chart/doughnut-widget.models';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
LatestChartBasicConfigComponent
} from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
@Component({
selector: 'tb-doughnut-basic-config',
templateUrl: './doughnut-basic-config.component.html',
templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class DoughnutBasicConfigComponent extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.doughnutWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
public get displayTimewindowConfig(): boolean {
const datasources = this.doughnutWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.doughnutWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
doughnutLayouts = doughnutLayouts;
doughnutLayoutTranslationMap = doughnutLayoutTranslations;
horizontal = false;
doughnutLayoutImageMap: Map<DoughnutLayout, string>;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
doughnutWidgetConfigForm: UntypedFormGroup;
export class DoughnutBasicConfigComponent extends LatestChartBasicConfigComponent<DoughnutWidgetSettings> {
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
get totalEnabled(): boolean {
const layout: DoughnutLayout = this.doughnutWidgetConfigForm.get('layout').value;
return layout === DoughnutLayout.with_total;
}
@ViewChild('doughnutChart')
doughnutChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.doughnutWidgetConfigForm;
}
protected setupConfig(widgetConfig: WidgetConfigComponentData) {
const params = widgetConfig.typeParameters as any;
this.horizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false;
this.doughnutLayoutImageMap = this.horizontal ? horizontalDoughnutLayoutImages : doughnutLayoutImages;
super.setupConfig(widgetConfig);
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] {
@ -126,223 +52,43 @@ export class DoughnutBasicConfigComponent extends BasicWidgetConfigComponent {
{ name: 'solarPower', label: 'Solar power', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FF4D5A' }];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: DoughnutWidgetSettings = mergeDeep<DoughnutWidgetSettings>({} as DoughnutWidgetSettings,
doughnutDefaultSettings(this.horizontal), configData.config.settings as DoughnutWidgetSettings);
this.doughnutWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
layout: [settings.layout, []],
autoScale: [settings.autoScale, []],
clockwise: [settings.clockwise, []],
sortSeries: [settings.sortSeries, []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
titleFont: [configData.config.titleFont, []],
titleColor: [configData.config.titleColor, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
totalValueFont: [settings.totalValueFont, []],
totalValueColor: [settings.totalValueColor, []],
units: [configData.config.units, []],
decimals: [configData.config.decimals, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
protected defaultSettings() {
return doughnutDefaultSettings(this.doughnutHorizontal);
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
public latestChartConfigTemplate(): TemplateRef<any> {
return this.doughnutChartConfigTemplate;
}
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: DoughnutWidgetSettings) {
latestChartWidgetConfigForm.addControl('layout', this.fb.control(settings.layout, []));
latestChartWidgetConfigForm.addControl('autoScale', this.fb.control(settings.autoScale, []));
latestChartWidgetConfigForm.addControl('clockwise', this.fb.control(settings.clockwise, []));
latestChartWidgetConfigForm.addControl('totalValueFont', this.fb.control(settings.totalValueFont, []));
latestChartWidgetConfigForm.addControl('totalValueColor', this.fb.control(settings.totalValueColor, []));
}
protected prepareOutputLatestChartConfig(config: any) {
this.widgetConfig.config.settings.layout = config.layout;
this.widgetConfig.config.settings.autoScale = config.autoScale;
this.widgetConfig.config.settings.clockwise = config.clockwise;
this.widgetConfig.config.settings.sortSeries = config.sortSeries;
this.widgetConfig.config.settings.totalValueFont = config.totalValueFont;
this.widgetConfig.config.settings.totalValueColor = config.totalValueColor;
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
this.widgetConfig.config.settings.animation = config.animation;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendPosition = config.legendPosition;
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont;
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor;
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont;
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor;
this.widgetConfig.config.settings.showTooltip = config.showTooltip;
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType;
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals;
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont;
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
this.widgetConfig.config.settings.background = config.background;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['layout', 'showTitle', 'showTitleIcon', 'showLegend', 'showTooltip'];
protected latestChartValidatorTriggers(): string[] {
return ['layout'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const layout: DoughnutLayout = this.doughnutWidgetConfigForm.get('layout').value;
const showTitle: boolean = this.doughnutWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.doughnutWidgetConfigForm.get('showTitleIcon').value;
const showLegend: boolean = this.doughnutWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.doughnutWidgetConfigForm.get('showTooltip').value;
protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const layout: DoughnutLayout = latestChartWidgetConfigForm.get('layout').value;
const totalEnabled = layout === DoughnutLayout.with_total;
if (showTitle) {
this.doughnutWidgetConfigForm.get('title').enable();
this.doughnutWidgetConfigForm.get('titleFont').enable();
this.doughnutWidgetConfigForm.get('titleColor').enable();
this.doughnutWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.doughnutWidgetConfigForm.get('titleIcon').enable();
this.doughnutWidgetConfigForm.get('iconColor').enable();
} else {
this.doughnutWidgetConfigForm.get('titleIcon').disable();
this.doughnutWidgetConfigForm.get('iconColor').disable();
}
} else {
this.doughnutWidgetConfigForm.get('title').disable();
this.doughnutWidgetConfigForm.get('titleFont').disable();
this.doughnutWidgetConfigForm.get('titleColor').disable();
this.doughnutWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.doughnutWidgetConfigForm.get('titleIcon').disable();
this.doughnutWidgetConfigForm.get('iconColor').disable();
}
if (showLegend) {
this.doughnutWidgetConfigForm.get('legendPosition').enable();
this.doughnutWidgetConfigForm.get('legendLabelFont').enable();
this.doughnutWidgetConfigForm.get('legendLabelColor').enable();
this.doughnutWidgetConfigForm.get('legendValueFont').enable();
this.doughnutWidgetConfigForm.get('legendValueColor').enable();
} else {
this.doughnutWidgetConfigForm.get('legendPosition').disable();
this.doughnutWidgetConfigForm.get('legendLabelFont').disable();
this.doughnutWidgetConfigForm.get('legendLabelColor').disable();
this.doughnutWidgetConfigForm.get('legendValueFont').disable();
this.doughnutWidgetConfigForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.doughnutWidgetConfigForm.get('tooltipValueType').enable();
this.doughnutWidgetConfigForm.get('tooltipValueDecimals').enable();
this.doughnutWidgetConfigForm.get('tooltipValueFont').enable();
this.doughnutWidgetConfigForm.get('tooltipValueColor').enable();
this.doughnutWidgetConfigForm.get('tooltipBackgroundColor').enable();
this.doughnutWidgetConfigForm.get('tooltipBackgroundBlur').enable();
} else {
this.doughnutWidgetConfigForm.get('tooltipValueType').disable();
this.doughnutWidgetConfigForm.get('tooltipValueDecimals').disable();
this.doughnutWidgetConfigForm.get('tooltipValueFont').disable();
this.doughnutWidgetConfigForm.get('tooltipValueColor').disable();
this.doughnutWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.doughnutWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}
if (totalEnabled) {
this.doughnutWidgetConfigForm.get('totalValueFont').enable();
this.doughnutWidgetConfigForm.get('totalValueColor').enable();
} else {
this.doughnutWidgetConfigForm.get('totalValueFont').disable();
this.doughnutWidgetConfigForm.get('totalValueColor').disable();
}
}
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
private _valuePreviewFn(): string {
const units: string = this.doughnutWidgetConfigForm.get('units').value;
const decimals: number = this.doughnutWidgetConfigForm.get('decimals').value;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.doughnutWidgetConfigForm.get('tooltipValueType').value;
const decimals: number = this.doughnutWidgetConfigForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
latestChartWidgetConfigForm.get('totalValueFont').enable();
latestChartWidgetConfigForm.get('totalValueColor').enable();
} else {
const units: string = this.doughnutWidgetConfigForm.get('units').value;
return formatValue(110, decimals, units, false);
latestChartWidgetConfigForm.get('totalValueFont').disable();
latestChartWidgetConfigForm.get('totalValueColor').disable();
}
}
}

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

@ -0,0 +1,529 @@
<!--
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.
-->
<ng-container [formGroup]="latestChartWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDatasourceLabel
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideUnits
hideDecimals
hideDataKeyUnits
hideDataKeyDecimals
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="latestChartWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.card-icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="latestChartWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<ng-container *ngTemplateOutlet="latestChartConfigTemplate()"></ng-container>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="latestChartWidgetConfigForm.get('showLegend').value" [disabled]="!latestChartWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="latestChartWidgetConfigForm.get('showTooltip').value" [disabled]="!latestChartWidgetConfigForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>
<ng-template #pieChart>
<ng-container [formGroup]="latestChartWidgetConfigForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.pie-chart.pie-chart-appearance</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showLabel">
{{ 'widgets.pie-chart.label' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="labelPosition">
<mat-option *ngFor="let position of pieChartLabelPositions" [value]="position">
{{ pieChartLabelPositionTranslationMap.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
disabledLineHeight
forceSizeUnit="px"
[previewText]="'Wind<br/>55%'">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.border' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="borderWidth" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="borderColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.radius' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="radius" type="number" min="0" max="100" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>%</div>
</mat-form-field>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #doughnutChart>
<ng-container [formGroup]="latestChartWidgetConfigForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.doughnut.doughnut-appearance</div>
<tb-image-cards-select rowHeight="{{ doughnutHorizontal ? '8:5' : '5:4' }}"
[cols]="{columns: 2,
breakpoints: {
'lt-sm': 1
}}"
label="{{ 'widgets.doughnut.layout' | translate }}" formControlName="layout">
<tb-image-cards-select-option *ngFor="let layout of doughnutLayouts"
[value]="layout"
[image]="doughnutLayoutImageMap.get(layout)">
{{ doughnutLayoutTranslationMap.get(layout) | translate }}
</tb-image-cards-select-option>
</tb-image-cards-select>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="autoScale">
{{ 'widgets.latest-chart.auto-scale' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div [fxShow]="doughnutTotalEnabled" class="tb-form-row space-between">
<div>{{ 'widgets.doughnut.central-total-value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="totalValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-settings formControlName="totalValueColor" settingsKey="{{'widgets.doughnut.central-total-value' | translate }}">
</tb-color-settings>
</div>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #barChart>
<ng-container [formGroup]="latestChartWidgetConfigForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #polarAreaChart>
<ng-container [formGroup]="latestChartWidgetConfigForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
pieLabelPosition
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.polar-area-chart.polar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.polar-area-chart.start-angle</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="angleAxisStartAngle" type="number" min="0" max="360" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #radarChart>
<ng-container [formGroup]="latestChartWidgetConfigForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.radar-chart.shape' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="shape">
<mat-option *ngFor="let shape of radarChartShapes" [value]="shape">
{{ radarChartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.radar-chart.color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="color">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showLine">
{{ 'widgets.radar-chart.line' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="lineType">
<mat-option *ngFor="let type of chartLineTypes" [value]="type">
{{ chartLineTypeTranslations.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="lineWidth"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showPoints">
{{ 'widgets.radar-chart.points' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of chartShapes" [value]="shape">
{{ chartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="pointSize"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showLabel">
{{ 'widgets.radar-chart.points-label' | translate }}
</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="labelPosition">
<mat-option *ngFor="let position of chartLabelPositions" [value]="position">
{{ chartLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<tb-chart-fill-settings
formControlName="fillAreaSettings">
</tb-chart-fill-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-axis</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowLabel">
{{ 'widgets.radar-chart.axis-label' | translate }}
</mat-slide-toggle>
<tb-font-settings formControlName="axisLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="Wind">
</tb-font-settings>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowTickLabels">
{{ 'widgets.radar-chart.ticks-label' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
</ng-container>
</ng-template>

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

@ -0,0 +1,366 @@
///
/// 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 { Directive, TemplateRef } from '@angular/core';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations,
LatestChartWidgetSettings
} from '@home/components/widget/lib/chart/latest-chart.models';
import { formatValue, isDefinedAndNotNull, isUndefined, mergeDeep } from '@core/utils';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
import {
chartLabelPositions,
chartLabelPositionTranslations,
chartLineTypes,
chartLineTypeTranslations,
chartShapes,
chartShapeTranslations,
pieChartLabelPositions,
pieChartLabelPositionTranslations
} from '@home/components/widget/lib/chart/chart.models';
import {
DoughnutLayout, doughnutLayoutImages,
doughnutLayouts,
doughnutLayoutTranslations, horizontalDoughnutLayoutImages
} from '@home/components/widget/lib/chart/doughnut-widget.models';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class LatestChartBasicConfigComponent<S extends LatestChartWidgetSettings> extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.latestChartWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
public get displayTimewindowConfig(): boolean {
const datasources = this.latestChartWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.latestChartWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
doughnutLayouts = doughnutLayouts;
doughnutLayoutTranslationMap = doughnutLayoutTranslations;
doughnutHorizontal = false;
doughnutLayoutImageMap: Map<DoughnutLayout, string>;
pieChartLabelPositions = pieChartLabelPositions;
pieChartLabelPositionTranslationMap = pieChartLabelPositionTranslations;
radarChartShapes = radarChartShapes;
radarChartShapeTranslations = radarChartShapeTranslations;
chartLineTypes = chartLineTypes;
chartLineTypeTranslations = chartLineTypeTranslations;
chartShapes = chartShapes;
chartShapeTranslations = chartShapeTranslations;
chartLabelPositions = chartLabelPositions;
chartLabelPositionTranslations = chartLabelPositionTranslations;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
latestChartWidgetConfigForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
get doughnutTotalEnabled(): boolean {
const layout: DoughnutLayout = this.latestChartWidgetConfigForm.get('layout').value;
return layout === DoughnutLayout.with_total;
}
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.latestChartWidgetConfigForm;
}
protected setupConfig(widgetConfig: WidgetConfigComponentData) {
const params = widgetConfig.typeParameters as any;
this.doughnutHorizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false;
this.doughnutLayoutImageMap = this.doughnutHorizontal ? horizontalDoughnutLayoutImages : doughnutLayoutImages;
super.setupConfig(widgetConfig);
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: S = mergeDeep<S>({} as S,
this.defaultSettings(), configData.config.settings as S);
this.latestChartWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
titleFont: [configData.config.titleFont, []],
titleColor: [configData.config.titleColor, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
sortSeries: [settings.sortSeries, []],
units: [configData.config.units, []],
decimals: [configData.config.decimals, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
this.setupLatestChartControls(this.latestChartWidgetConfigForm, settings);
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
this.widgetConfig.config.settings.sortSeries = config.sortSeries;
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
this.widgetConfig.config.settings.animation = config.animation;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendPosition = config.legendPosition;
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont;
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor;
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont;
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor;
this.widgetConfig.config.settings.showTooltip = config.showTooltip;
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType;
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals;
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont;
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
this.widgetConfig.config.settings.background = config.background;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
this.prepareOutputLatestChartConfig(config);
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon', 'showLegend', 'showTooltip'].concat(this.latestChartValidatorTriggers());
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.latestChartWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.latestChartWidgetConfigForm.get('showTitleIcon').value;
const showLegend: boolean = this.latestChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.latestChartWidgetConfigForm.get('showTooltip').value;
if (showTitle) {
this.latestChartWidgetConfigForm.get('title').enable();
this.latestChartWidgetConfigForm.get('titleFont').enable();
this.latestChartWidgetConfigForm.get('titleColor').enable();
this.latestChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.latestChartWidgetConfigForm.get('titleIcon').enable();
this.latestChartWidgetConfigForm.get('iconColor').enable();
} else {
this.latestChartWidgetConfigForm.get('titleIcon').disable();
this.latestChartWidgetConfigForm.get('iconColor').disable();
}
} else {
this.latestChartWidgetConfigForm.get('title').disable();
this.latestChartWidgetConfigForm.get('titleFont').disable();
this.latestChartWidgetConfigForm.get('titleColor').disable();
this.latestChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.latestChartWidgetConfigForm.get('titleIcon').disable();
this.latestChartWidgetConfigForm.get('iconColor').disable();
}
if (showLegend) {
this.latestChartWidgetConfigForm.get('legendPosition').enable();
this.latestChartWidgetConfigForm.get('legendLabelFont').enable();
this.latestChartWidgetConfigForm.get('legendLabelColor').enable();
this.latestChartWidgetConfigForm.get('legendValueFont').enable();
this.latestChartWidgetConfigForm.get('legendValueColor').enable();
} else {
this.latestChartWidgetConfigForm.get('legendPosition').disable();
this.latestChartWidgetConfigForm.get('legendLabelFont').disable();
this.latestChartWidgetConfigForm.get('legendLabelColor').disable();
this.latestChartWidgetConfigForm.get('legendValueFont').disable();
this.latestChartWidgetConfigForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.latestChartWidgetConfigForm.get('tooltipValueType').enable();
this.latestChartWidgetConfigForm.get('tooltipValueDecimals').enable();
this.latestChartWidgetConfigForm.get('tooltipValueFont').enable();
this.latestChartWidgetConfigForm.get('tooltipValueColor').enable();
this.latestChartWidgetConfigForm.get('tooltipBackgroundColor').enable();
this.latestChartWidgetConfigForm.get('tooltipBackgroundBlur').enable();
} else {
this.latestChartWidgetConfigForm.get('tooltipValueType').disable();
this.latestChartWidgetConfigForm.get('tooltipValueDecimals').disable();
this.latestChartWidgetConfigForm.get('tooltipValueFont').disable();
this.latestChartWidgetConfigForm.get('tooltipValueColor').disable();
this.latestChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.latestChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}
this.updateLatestChartValidators(this.latestChartWidgetConfigForm, emitEvent, trigger);
}
protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: S) {}
protected prepareOutputLatestChartConfig(config: any) {}
protected latestChartValidatorTriggers(): string[] {
return [];
}
protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
}
protected abstract defaultSettings(): S;
public abstract latestChartConfigTemplate(): TemplateRef<any>;
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
private _valuePreviewFn(): string {
const units: string = this.latestChartWidgetConfigForm.get('units').value;
const decimals: number = this.latestChartWidgetConfigForm.get('decimals').value;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.configForm().get('tooltipValueType').value;
const decimals: number = this.latestChartWidgetConfigForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.latestChartWidgetConfigForm.get('units').value;
return formatValue(110, decimals, units, false);
}
}
}

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

@ -1,276 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="pieChartWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDatasourceLabel
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideUnits
hideDecimals
hideDataKeyUnits
hideDataKeyDecimals
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showLabel">
{{ 'widgets.pie-chart.label' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="labelPosition">
<mat-option *ngFor="let position of pieChartLabelPositions" [value]="position">
{{ pieChartLabelPositionTranslationMap.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
disabledLineHeight
forceSizeUnit="px"
[previewText]="'Wind<br/>55%'">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.border' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="borderWidth" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="borderColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.radius' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="radius" type="number" min="0" max="100" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>%</div>
</mat-form-field>
</div>
</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="pieChartWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.card-icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="pieChartWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="pieChartWidgetConfigForm.get('showLegend').value" [disabled]="!pieChartWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="pieChartWidgetConfigForm.get('showTooltip').value" [disabled]="!pieChartWidgetConfigForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

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

@ -14,94 +14,36 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { DataKey } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { formatValue, isUndefined, mergeDeep } from '@core/utils';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
pieChartWidgetDefaultSettings,
PieChartWidgetSettings
} from '@home/components/widget/lib/chart/pie-chart-widget.models';
import {
pieChartLabelPositions,
pieChartLabelPositionTranslations
} from '@home/components/widget/lib/chart/chart.models';
LatestChartBasicConfigComponent
} from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
@Component({
selector: 'tb-pie-chart-basic-config',
templateUrl: './pie-chart-basic-config.component.html',
templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class PieChartBasicConfigComponent extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.pieChartWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
public get displayTimewindowConfig(): boolean {
const datasources = this.pieChartWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.pieChartWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
pieChartLabelPositions = pieChartLabelPositions;
pieChartLabelPositionTranslationMap = pieChartLabelPositionTranslations;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
pieChartWidgetConfigForm: UntypedFormGroup;
export class PieChartBasicConfigComponent extends LatestChartBasicConfigComponent<PieChartWidgetSettings> {
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('pieChart')
pieChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.pieChartWidgetConfigForm;
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] {
@ -110,81 +52,28 @@ export class PieChartBasicConfigComponent extends BasicWidgetConfigComponent {
{ name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30' }];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: PieChartWidgetSettings = mergeDeep<PieChartWidgetSettings>({} as PieChartWidgetSettings,
pieChartWidgetDefaultSettings, configData.config.settings as PieChartWidgetSettings);
this.pieChartWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
showLabel: [settings.showLabel, []],
labelPosition: [settings.labelPosition, []],
labelFont: [settings.labelFont, []],
labelColor: [settings.labelColor, []],
borderWidth: [settings.borderWidth, [Validators.min(0)]],
borderColor: [settings.borderColor, []],
radius: [settings.radius, [Validators.min(0), Validators.max(100)]],
clockwise: [settings.clockwise, []],
sortSeries: [settings.sortSeries, []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
titleFont: [configData.config.titleFont, []],
titleColor: [configData.config.titleColor, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
units: [configData.config.units, []],
decimals: [configData.config.decimals, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
protected defaultSettings() {
return pieChartWidgetDefaultSettings;
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
public latestChartConfigTemplate(): TemplateRef<any> {
return this.pieChartConfigTemplate;
}
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: PieChartWidgetSettings) {
latestChartWidgetConfigForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
latestChartWidgetConfigForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
latestChartWidgetConfigForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
latestChartWidgetConfigForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
latestChartWidgetConfigForm.addControl('borderWidth', this.fb.control(settings.borderWidth, []));
latestChartWidgetConfigForm.addControl('borderColor', this.fb.control(settings.borderColor, []));
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
latestChartWidgetConfigForm.addControl('radius', this.fb.control(settings.radius, []));
latestChartWidgetConfigForm.addControl('clockwise', this.fb.control(settings.clockwise, []));
}
protected prepareOutputLatestChartConfig(config: any) {
this.widgetConfig.config.settings.showLabel = config.showLabel;
this.widgetConfig.config.settings.labelPosition = config.labelPosition;
this.widgetConfig.config.settings.labelFont = config.labelFont;
@ -194,150 +83,24 @@ export class PieChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.widgetConfig.config.settings.borderColor = config.borderColor;
this.widgetConfig.config.settings.radius = config.radius;
this.widgetConfig.config.settings.clockwise = config.clockwise;
this.widgetConfig.config.settings.sortSeries = config.sortSeries;
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
this.widgetConfig.config.settings.animation = config.animation;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendPosition = config.legendPosition;
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont;
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor;
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont;
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor;
this.widgetConfig.config.settings.showTooltip = config.showTooltip;
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType;
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals;
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont;
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
this.widgetConfig.config.settings.background = config.background;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showLabel', 'showTitle', 'showTitleIcon', 'showLegend', 'showTooltip'];
protected latestChartValidatorTriggers(): string[] {
return ['showLabel'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showLabel: boolean = this.pieChartWidgetConfigForm.get('showLabel').value;
const showTitle: boolean = this.pieChartWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.pieChartWidgetConfigForm.get('showTitleIcon').value;
const showLegend: boolean = this.pieChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.pieChartWidgetConfigForm.get('showTooltip').value;
protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLabel: boolean = latestChartWidgetConfigForm.get('showLabel').value;
if (showLabel) {
this.pieChartWidgetConfigForm.get('labelPosition').enable();
this.pieChartWidgetConfigForm.get('labelFont').enable();
this.pieChartWidgetConfigForm.get('labelColor').enable();
} else {
this.pieChartWidgetConfigForm.get('labelPosition').disable();
this.pieChartWidgetConfigForm.get('labelFont').disable();
this.pieChartWidgetConfigForm.get('labelColor').disable();
}
if (showTitle) {
this.pieChartWidgetConfigForm.get('title').enable();
this.pieChartWidgetConfigForm.get('titleFont').enable();
this.pieChartWidgetConfigForm.get('titleColor').enable();
this.pieChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.pieChartWidgetConfigForm.get('titleIcon').enable();
this.pieChartWidgetConfigForm.get('iconColor').enable();
} else {
this.pieChartWidgetConfigForm.get('titleIcon').disable();
this.pieChartWidgetConfigForm.get('iconColor').disable();
}
} else {
this.pieChartWidgetConfigForm.get('title').disable();
this.pieChartWidgetConfigForm.get('titleFont').disable();
this.pieChartWidgetConfigForm.get('titleColor').disable();
this.pieChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.pieChartWidgetConfigForm.get('titleIcon').disable();
this.pieChartWidgetConfigForm.get('iconColor').disable();
}
if (showLegend) {
this.pieChartWidgetConfigForm.get('legendPosition').enable();
this.pieChartWidgetConfigForm.get('legendLabelFont').enable();
this.pieChartWidgetConfigForm.get('legendLabelColor').enable();
this.pieChartWidgetConfigForm.get('legendValueFont').enable();
this.pieChartWidgetConfigForm.get('legendValueColor').enable();
} else {
this.pieChartWidgetConfigForm.get('legendPosition').disable();
this.pieChartWidgetConfigForm.get('legendLabelFont').disable();
this.pieChartWidgetConfigForm.get('legendLabelColor').disable();
this.pieChartWidgetConfigForm.get('legendValueFont').disable();
this.pieChartWidgetConfigForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.pieChartWidgetConfigForm.get('tooltipValueType').enable();
this.pieChartWidgetConfigForm.get('tooltipValueDecimals').enable();
this.pieChartWidgetConfigForm.get('tooltipValueFont').enable();
this.pieChartWidgetConfigForm.get('tooltipValueColor').enable();
this.pieChartWidgetConfigForm.get('tooltipBackgroundColor').enable();
this.pieChartWidgetConfigForm.get('tooltipBackgroundBlur').enable();
} else {
this.pieChartWidgetConfigForm.get('tooltipValueType').disable();
this.pieChartWidgetConfigForm.get('tooltipValueDecimals').disable();
this.pieChartWidgetConfigForm.get('tooltipValueFont').disable();
this.pieChartWidgetConfigForm.get('tooltipValueColor').disable();
this.pieChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.pieChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}
}
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
private _valuePreviewFn(): string {
const units: string = this.pieChartWidgetConfigForm.get('units').value;
const decimals: number = this.pieChartWidgetConfigForm.get('decimals').value;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.pieChartWidgetConfigForm.get('tooltipValueType').value;
const decimals: number = this.pieChartWidgetConfigForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
latestChartWidgetConfigForm.get('labelPosition').enable();
latestChartWidgetConfigForm.get('labelFont').enable();
latestChartWidgetConfigForm.get('labelColor').enable();
} else {
const units: string = this.pieChartWidgetConfigForm.get('units').value;
return formatValue(110, decimals, units, false);
latestChartWidgetConfigForm.get('labelPosition').disable();
latestChartWidgetConfigForm.get('labelFont').disable();
latestChartWidgetConfigForm.get('labelColor').disable();
}
}
}

268
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/polar-area-chart-basic-config.component.html

@ -1,268 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="polarAreaChartWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDatasourceLabel
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideUnits
hideDecimals
hideDataKeyUnits
hideDataKeyDecimals
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="polarAreaChartWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.card-icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="polarAreaChartWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
pieLabelPosition
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.polar-area-chart.polar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.polar-area-chart.start-angle</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="angleAxisStartAngle" type="number" min="0" max="360" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="polarAreaChartWidgetConfigForm.get('showLegend').value" [disabled]="!polarAreaChartWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="polarAreaChartWidgetConfigForm.get('showTooltip').value" [disabled]="!polarAreaChartWidgetConfigForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

288
ui-ngx/src/app/modules/home/components/widget/config/basic/chart/polar-area-chart-basic-config.component.ts

@ -14,86 +14,36 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { DataKey } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { formatValue, isUndefined, mergeDeep } from '@core/utils';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
polarAreaChartWidgetDefaultSettings,
PolarAreaChartWidgetSettings
} from '@home/components/widget/lib/chart/polar-area-widget.models';
import {
LatestChartBasicConfigComponent
} from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
@Component({
selector: 'tb-polar-area-chart-basic-config',
templateUrl: './polar-area-chart-basic-config.component.html',
templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class PolarAreaChartBasicConfigComponent extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.polarAreaChartWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
public get displayTimewindowConfig(): boolean {
const datasources = this.polarAreaChartWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.polarAreaChartWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
polarAreaChartWidgetConfigForm: UntypedFormGroup;
export class PolarAreaChartBasicConfigComponent extends LatestChartBasicConfigComponent<PolarAreaChartWidgetSettings> {
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('polarAreaChart')
polarAreaChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.polarAreaChartWidgetConfigForm;
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] {
@ -102,83 +52,25 @@ export class PolarAreaChartBasicConfigComponent extends BasicWidgetConfigCompone
{ name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30' }];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: PolarAreaChartWidgetSettings = mergeDeep<PolarAreaChartWidgetSettings>({} as PolarAreaChartWidgetSettings,
polarAreaChartWidgetDefaultSettings, configData.config.settings as PolarAreaChartWidgetSettings);
this.polarAreaChartWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
titleFont: [configData.config.titleFont, []],
titleColor: [configData.config.titleColor, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
sortSeries: [settings.sortSeries, []],
units: [configData.config.units, []],
decimals: [configData.config.decimals, []],
barSettings: [settings.barSettings, []],
axisMin: [settings.axisMin, []],
axisMax: [settings.axisMax, []],
axisTickLabelFont: [settings.axisTickLabelFont, []],
axisTickLabelColor: [settings.axisTickLabelColor, []],
angleAxisStartAngle: [settings.angleAxisStartAngle, [Validators.min(0), Validators.max(360)]],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
protected defaultSettings() {
return polarAreaChartWidgetDefaultSettings;
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
public latestChartConfigTemplate(): TemplateRef<any> {
return this.polarAreaChartConfigTemplate;
}
this.widgetConfig.config.settings.sortSeries = config.sortSeries;
protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: PolarAreaChartWidgetSettings) {
latestChartWidgetConfigForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
latestChartWidgetConfigForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
latestChartWidgetConfigForm.addControl('axisMax', this.fb.control(settings.axisMax, []));
latestChartWidgetConfigForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
latestChartWidgetConfigForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
latestChartWidgetConfigForm.addControl('angleAxisStartAngle', this.fb.control(settings.angleAxisStartAngle, []));
}
protected prepareOutputLatestChartConfig(config: any) {
this.widgetConfig.config.settings.barSettings = config.barSettings;
this.widgetConfig.config.settings.axisMin = config.axisMin;
@ -186,133 +78,5 @@ export class PolarAreaChartBasicConfigComponent extends BasicWidgetConfigCompone
this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont;
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor;
this.widgetConfig.config.settings.angleAxisStartAngle = config.angleAxisStartAngle;
this.widgetConfig.config.settings.animation = config.animation;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendPosition = config.legendPosition;
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont;
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor;
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont;
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor;
this.widgetConfig.config.settings.showTooltip = config.showTooltip;
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType;
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals;
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont;
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
this.widgetConfig.config.settings.background = config.background;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon', 'showLegend', 'showTooltip'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.polarAreaChartWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.polarAreaChartWidgetConfigForm.get('showTitleIcon').value;
const showLegend: boolean = this.polarAreaChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.polarAreaChartWidgetConfigForm.get('showTooltip').value;
if (showTitle) {
this.polarAreaChartWidgetConfigForm.get('title').enable();
this.polarAreaChartWidgetConfigForm.get('titleFont').enable();
this.polarAreaChartWidgetConfigForm.get('titleColor').enable();
this.polarAreaChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.polarAreaChartWidgetConfigForm.get('titleIcon').enable();
this.polarAreaChartWidgetConfigForm.get('iconColor').enable();
} else {
this.polarAreaChartWidgetConfigForm.get('titleIcon').disable();
this.polarAreaChartWidgetConfigForm.get('iconColor').disable();
}
} else {
this.polarAreaChartWidgetConfigForm.get('title').disable();
this.polarAreaChartWidgetConfigForm.get('titleFont').disable();
this.polarAreaChartWidgetConfigForm.get('titleColor').disable();
this.polarAreaChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.polarAreaChartWidgetConfigForm.get('titleIcon').disable();
this.polarAreaChartWidgetConfigForm.get('iconColor').disable();
}
if (showLegend) {
this.polarAreaChartWidgetConfigForm.get('legendPosition').enable();
this.polarAreaChartWidgetConfigForm.get('legendLabelFont').enable();
this.polarAreaChartWidgetConfigForm.get('legendLabelColor').enable();
this.polarAreaChartWidgetConfigForm.get('legendValueFont').enable();
this.polarAreaChartWidgetConfigForm.get('legendValueColor').enable();
} else {
this.polarAreaChartWidgetConfigForm.get('legendPosition').disable();
this.polarAreaChartWidgetConfigForm.get('legendLabelFont').disable();
this.polarAreaChartWidgetConfigForm.get('legendLabelColor').disable();
this.polarAreaChartWidgetConfigForm.get('legendValueFont').disable();
this.polarAreaChartWidgetConfigForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.polarAreaChartWidgetConfigForm.get('tooltipValueType').enable();
this.polarAreaChartWidgetConfigForm.get('tooltipValueDecimals').enable();
this.polarAreaChartWidgetConfigForm.get('tooltipValueFont').enable();
this.polarAreaChartWidgetConfigForm.get('tooltipValueColor').enable();
this.polarAreaChartWidgetConfigForm.get('tooltipBackgroundColor').enable();
this.polarAreaChartWidgetConfigForm.get('tooltipBackgroundBlur').enable();
} else {
this.polarAreaChartWidgetConfigForm.get('tooltipValueType').disable();
this.polarAreaChartWidgetConfigForm.get('tooltipValueDecimals').disable();
this.polarAreaChartWidgetConfigForm.get('tooltipValueFont').disable();
this.polarAreaChartWidgetConfigForm.get('tooltipValueColor').disable();
this.polarAreaChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.polarAreaChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}
}
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
private _valuePreviewFn(): string {
const units: string = this.polarAreaChartWidgetConfigForm.get('units').value;
const decimals: number = this.polarAreaChartWidgetConfigForm.get('decimals').value;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.polarAreaChartWidgetConfigForm.get('tooltipValueType').value;
const decimals: number = this.polarAreaChartWidgetConfigForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.polarAreaChartWidgetConfigForm.get('units').value;
return formatValue(110, decimals, units, false);
}
}
}

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

@ -1,340 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="radarChartWidgetConfigForm">
<tb-timewindow-config-panel *ngIf="displayTimewindowConfig"
[onlyHistoryTimewindow]="onlyHistoryTimewindow()"
formControlName="timewindowConfig">
</tb-timewindow-config-panel>
<tb-datasources
[configMode]="basicMode"
hideDatasourceLabel
hideDataKeys
forceSingleDatasource
formControlName="datasources">
</tb-datasources>
<tb-data-keys-panel
panelTitle="{{ 'widgets.chart.series' | translate }}"
addKeyTitle="{{ 'widgets.chart.add-series' | translate }}"
keySettingsTitle="{{ 'widgets.chart.series-settings' | translate }}"
removeKeyTitle="{{ 'widgets.chart.remove-series' | translate }}"
noKeysText="{{ 'widgets.chart.no-series' | translate }}"
requiredKeysText="{{ 'widgets.chart.no-series-error' | translate }}"
hideUnits
hideDecimals
hideDataKeyUnits
hideDataKeyDecimals
[datasourceType]="datasource?.type"
[deviceId]="datasource?.deviceId"
[entityAliasId]="datasource?.entityAliasId"
formControlName="series">
</tb-data-keys-panel>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showTitle">
{{ 'widget-config.card-title' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="title" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="titleFont"
clearButton
[previewText]="radarChartWidgetConfigForm.get('title').value"
[initialPreviewStyle]="widgetConfig.config.titleStyle">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="titleColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="showTitleIcon">
{{ 'widget-config.card-icon' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-material-icon-select asBoxInput
iconClearButton
[color]="radarChartWidgetConfigForm.get('iconColor').value"
formControlName="titleIcon">
</tb-material-icon-select>
<tb-color-input asBoxInput
colorClearButton
formControlName="iconColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.units-short</div>
<tb-unit-input
formControlName="units">
</tb-unit-input>
</div>
<div class="tb-form-row space-between">
<div translate>widget-config.decimals-short</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="decimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.radar-chart.shape' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="shape">
<mat-option *ngFor="let shape of radarChartShapes" [value]="shape">
{{ radarChartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.radar-chart.color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="color">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showLine">
{{ 'widgets.radar-chart.line' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="lineType">
<mat-option *ngFor="let type of chartLineTypes" [value]="type">
{{ chartLineTypeTranslations.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="lineWidth"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showPoints">
{{ 'widgets.radar-chart.points' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of chartShapes" [value]="shape">
{{ chartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="pointSize"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showLabel">
{{ 'widgets.radar-chart.points-label' | translate }}
</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="labelPosition">
<mat-option *ngFor="let position of chartLabelPositions" [value]="position">
{{ chartLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<tb-chart-fill-settings
formControlName="fillAreaSettings">
</tb-chart-fill-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-axis</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowLabel">
{{ 'widgets.radar-chart.axis-label' | translate }}
</mat-slide-toggle>
<tb-font-settings formControlName="axisLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="Wind">
</tb-font-settings>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowTickLabels">
{{ 'widgets.radar-chart.ticks-label' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="radarChartWidgetConfigForm.get('showLegend').value" [disabled]="!radarChartWidgetConfigForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="radarChartWidgetConfigForm.get('showTooltip').value" [disabled]="!radarChartWidgetConfigForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widget-config.card-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
<div class="tb-form-row space-between column-lt-md">
<div translate>widget-config.show-card-buttons</div>
<mat-chip-listbox multiple formControlName="cardButtons">
<mat-chip-option value="fullscreen">{{ 'fullscreen.fullscreen' | translate }}</mat-chip-option>
</mat-chip-listbox>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widget-config.card-border-radius' | translate }}</div>
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<input matInput formControlName="borderRadius" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<tb-widget-actions-panel
formControlName="actions">
</tb-widget-actions-panel>
</ng-container>

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

@ -14,111 +14,36 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { DataKey } from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
import { formatValue, isUndefined, mergeDeep } from '@core/utils';
import {
getTimewindowConfig,
setTimewindowConfig
} from '@home/components/widget/config/timewindow-config-panel.component';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
radarChartWidgetDefaultSettings,
RadarChartWidgetSettings
} from '@home/components/widget/lib/chart/radar-chart-widget.models';
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
import {
chartLabelPositions,
chartLabelPositionTranslations,
chartLineTypes,
chartLineTypeTranslations,
chartShapes,
chartShapeTranslations
} from '@home/components/widget/lib/chart/chart.models';
LatestChartBasicConfigComponent
} from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
@Component({
selector: 'tb-radar-chart-basic-config',
templateUrl: './radar-chart-basic-config.component.html',
templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss']
})
export class RadarChartBasicConfigComponent extends BasicWidgetConfigComponent {
public get datasource(): Datasource {
const datasources: Datasource[] = this.radarChartWidgetConfigForm.get('datasources').value;
if (datasources && datasources.length) {
return datasources[0];
} else {
return null;
}
}
public get displayTimewindowConfig(): boolean {
const datasources = this.radarChartWidgetConfigForm.get('datasources').value;
return datasourcesHasAggregation(datasources);
}
public onlyHistoryTimewindow(): boolean {
const datasources = this.radarChartWidgetConfigForm.get('datasources').value;
return datasourcesHasOnlyComparisonAggregation(datasources);
}
radarChartShapes = radarChartShapes;
radarChartShapeTranslations = radarChartShapeTranslations;
chartLineTypes = chartLineTypes;
chartLineTypeTranslations = chartLineTypeTranslations;
chartShapes = chartShapes;
chartShapeTranslations = chartShapeTranslations;
chartLabelPositions = chartLabelPositions;
chartLabelPositionTranslations = chartLabelPositionTranslations;
export class RadarChartBasicConfigComponent extends LatestChartBasicConfigComponent<RadarChartWidgetSettings> {
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
radarChartWidgetConfigForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('radarChart')
radarChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) {
super(store, widgetConfigComponent);
}
protected configForm(): UntypedFormGroup {
return this.radarChartWidgetConfigForm;
protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent, fb);
}
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] {
@ -127,95 +52,37 @@ export class RadarChartBasicConfigComponent extends BasicWidgetConfigComponent {
{name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30'}];
}
protected onConfigSet(configData: WidgetConfigComponentData) {
const settings: RadarChartWidgetSettings = mergeDeep<RadarChartWidgetSettings>({} as RadarChartWidgetSettings,
radarChartWidgetDefaultSettings, configData.config.settings as RadarChartWidgetSettings);
this.radarChartWidgetConfigForm = this.fb.group({
timewindowConfig: [getTimewindowConfig(configData.config), []],
datasources: [configData.config.datasources, []],
series: [this.getSeries(configData.config.datasources), []],
showTitle: [configData.config.showTitle, []],
title: [configData.config.title, []],
titleFont: [configData.config.titleFont, []],
titleColor: [configData.config.titleColor, []],
showTitleIcon: [configData.config.showTitleIcon, []],
titleIcon: [configData.config.titleIcon, []],
iconColor: [configData.config.iconColor, []],
sortSeries: [settings.sortSeries, []],
units: [configData.config.units, []],
decimals: [configData.config.decimals, []],
shape: [settings.shape, []],
color: [settings.color, []],
showLine: [settings.showLine, []],
lineType: [settings.lineType, []],
lineWidth: [settings.lineWidth, [Validators.min(0)]],
showPoints: [settings.showPoints, []],
pointShape: [settings.pointShape, []],
pointSize: [settings.pointSize, [Validators.min(0)]],
showLabel: [settings.showLabel, []],
labelPosition: [settings.labelPosition, []],
labelFont: [settings.labelFont, []],
labelColor: [settings.labelColor, []],
fillAreaSettings: [settings.fillAreaSettings, []],
axisShowLabel: [settings.axisShowLabel, []],
axisLabelFont: [settings.axisLabelFont, []],
axisShowTickLabels: [settings.axisShowTickLabels, []],
axisTickLabelFont: [settings.axisTickLabelFont, []],
axisTickLabelColor: [settings.axisTickLabelColor, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []],
cardButtons: [this.getCardButtons(configData.config), []],
borderRadius: [configData.config.borderRadius, []],
actions: [configData.config.actions || {}, []]
});
protected defaultSettings() {
return radarChartWidgetDefaultSettings;
}
protected prepareOutputConfig(config: any): WidgetConfigComponentData {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig);
this.widgetConfig.config.datasources = config.datasources;
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.showTitle = config.showTitle;
this.widgetConfig.config.title = config.title;
this.widgetConfig.config.titleFont = config.titleFont;
this.widgetConfig.config.titleColor = config.titleColor;
this.widgetConfig.config.showTitleIcon = config.showTitleIcon;
this.widgetConfig.config.titleIcon = config.titleIcon;
this.widgetConfig.config.iconColor = config.iconColor;
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {};
public latestChartConfigTemplate(): TemplateRef<any> {
return this.radarChartConfigTemplate;
}
this.widgetConfig.config.settings.sortSeries = config.sortSeries;
protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: RadarChartWidgetSettings) {
latestChartWidgetConfigForm.addControl('shape', this.fb.control(settings.shape, []));
latestChartWidgetConfigForm.addControl('color', this.fb.control(settings.color, []));
latestChartWidgetConfigForm.addControl('showLine', this.fb.control(settings.showLine, []));
latestChartWidgetConfigForm.addControl('lineType', this.fb.control(settings.lineType, []));
latestChartWidgetConfigForm.addControl('lineWidth', this.fb.control(settings.lineWidth, [Validators.min(0)]));
latestChartWidgetConfigForm.addControl('showPoints', this.fb.control(settings.showPoints, []));
latestChartWidgetConfigForm.addControl('pointShape', this.fb.control(settings.pointShape, []));
latestChartWidgetConfigForm.addControl('pointSize', this.fb.control(settings.pointSize, [Validators.min(0)]));
latestChartWidgetConfigForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
latestChartWidgetConfigForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
latestChartWidgetConfigForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
latestChartWidgetConfigForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
latestChartWidgetConfigForm.addControl('fillAreaSettings', this.fb.control(settings.fillAreaSettings, []));
this.widgetConfig.config.units = config.units;
this.widgetConfig.config.decimals = config.decimals;
latestChartWidgetConfigForm.addControl('axisShowLabel', this.fb.control(settings.axisShowLabel, []));
latestChartWidgetConfigForm.addControl('axisLabelFont', this.fb.control(settings.axisLabelFont, []));
latestChartWidgetConfigForm.addControl('axisShowTickLabels', this.fb.control(settings.axisShowTickLabels, []));
latestChartWidgetConfigForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
latestChartWidgetConfigForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
}
protected prepareOutputLatestChartConfig(config: any) {
this.widgetConfig.config.settings.shape = config.shape;
this.widgetConfig.config.settings.color = config.color;
this.widgetConfig.config.settings.showLine = config.showLine;
@ -235,180 +102,58 @@ export class RadarChartBasicConfigComponent extends BasicWidgetConfigComponent {
this.widgetConfig.config.settings.axisShowTickLabels = config.axisShowTickLabels;
this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont;
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor;
this.widgetConfig.config.settings.animation = config.animation;
this.widgetConfig.config.settings.showLegend = config.showLegend;
this.widgetConfig.config.settings.legendPosition = config.legendPosition;
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont;
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor;
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont;
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor;
this.widgetConfig.config.settings.showTooltip = config.showTooltip;
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType;
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals;
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont;
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor;
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor;
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur;
this.widgetConfig.config.settings.background = config.background;
this.setCardButtons(config.cardButtons, this.widgetConfig.config);
this.widgetConfig.config.borderRadius = config.borderRadius;
this.widgetConfig.config.actions = config.actions;
return this.widgetConfig;
}
protected validatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon', 'showLine', 'showPoints', 'showLabel', 'axisShowLabel',
'axisShowTickLabels', 'showLegend', 'showTooltip'];
protected latestChartValidatorTriggers(): string[] {
return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel',
'axisShowTickLabels'];
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.radarChartWidgetConfigForm.get('showTitle').value;
const showTitleIcon: boolean = this.radarChartWidgetConfigForm.get('showTitleIcon').value;
const showLine: boolean = this.radarChartWidgetConfigForm.get('showLine').value;
const showPoints: boolean = this.radarChartWidgetConfigForm.get('showPoints').value;
const showLabel: boolean = this.radarChartWidgetConfigForm.get('showLabel').value;
const axisShowLabel: boolean = this.radarChartWidgetConfigForm.get('axisShowLabel').value;
const axisShowTickLabels: boolean = this.radarChartWidgetConfigForm.get('axisShowTickLabels').value;
const showLegend: boolean = this.radarChartWidgetConfigForm.get('showLegend').value;
const showTooltip: boolean = this.radarChartWidgetConfigForm.get('showTooltip').value;
if (showTitle) {
this.radarChartWidgetConfigForm.get('title').enable();
this.radarChartWidgetConfigForm.get('titleFont').enable();
this.radarChartWidgetConfigForm.get('titleColor').enable();
this.radarChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false});
if (showTitleIcon) {
this.radarChartWidgetConfigForm.get('titleIcon').enable();
this.radarChartWidgetConfigForm.get('iconColor').enable();
} else {
this.radarChartWidgetConfigForm.get('titleIcon').disable();
this.radarChartWidgetConfigForm.get('iconColor').disable();
}
} else {
this.radarChartWidgetConfigForm.get('title').disable();
this.radarChartWidgetConfigForm.get('titleFont').disable();
this.radarChartWidgetConfigForm.get('titleColor').disable();
this.radarChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false});
this.radarChartWidgetConfigForm.get('titleIcon').disable();
this.radarChartWidgetConfigForm.get('iconColor').disable();
}
protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLine: boolean = latestChartWidgetConfigForm.get('showLine').value;
const showPoints: boolean = latestChartWidgetConfigForm.get('showPoints').value;
const showLabel: boolean = latestChartWidgetConfigForm.get('showLabel').value;
const axisShowLabel: boolean = latestChartWidgetConfigForm.get('axisShowLabel').value;
const axisShowTickLabels: boolean = latestChartWidgetConfigForm.get('axisShowTickLabels').value;
if (showLine) {
this.radarChartWidgetConfigForm.get('lineType').enable();
this.radarChartWidgetConfigForm.get('lineWidth').enable();
latestChartWidgetConfigForm.get('lineType').enable();
latestChartWidgetConfigForm.get('lineWidth').enable();
} else {
this.radarChartWidgetConfigForm.get('lineType').disable();
this.radarChartWidgetConfigForm.get('lineWidth').disable();
latestChartWidgetConfigForm.get('lineType').disable();
latestChartWidgetConfigForm.get('lineWidth').disable();
}
if (showPoints) {
this.radarChartWidgetConfigForm.get('pointShape').enable();
this.radarChartWidgetConfigForm.get('pointSize').enable();
latestChartWidgetConfigForm.get('pointShape').enable();
latestChartWidgetConfigForm.get('pointSize').enable();
} else {
this.radarChartWidgetConfigForm.get('pointShape').disable();
this.radarChartWidgetConfigForm.get('pointSize').disable();
latestChartWidgetConfigForm.get('pointShape').disable();
latestChartWidgetConfigForm.get('pointSize').disable();
}
if (showLabel) {
this.radarChartWidgetConfigForm.get('labelPosition').enable();
this.radarChartWidgetConfigForm.get('labelFont').enable();
this.radarChartWidgetConfigForm.get('labelColor').enable();
latestChartWidgetConfigForm.get('labelPosition').enable();
latestChartWidgetConfigForm.get('labelFont').enable();
latestChartWidgetConfigForm.get('labelColor').enable();
} else {
this.radarChartWidgetConfigForm.get('labelPosition').disable();
this.radarChartWidgetConfigForm.get('labelFont').disable();
this.radarChartWidgetConfigForm.get('labelColor').disable();
latestChartWidgetConfigForm.get('labelPosition').disable();
latestChartWidgetConfigForm.get('labelFont').disable();
latestChartWidgetConfigForm.get('labelColor').disable();
}
if (axisShowLabel) {
this.radarChartWidgetConfigForm.get('axisLabelFont').enable();
latestChartWidgetConfigForm.get('axisLabelFont').enable();
} else {
this.radarChartWidgetConfigForm.get('axisLabelFont').disable();
latestChartWidgetConfigForm.get('axisLabelFont').disable();
}
if (axisShowTickLabels) {
this.radarChartWidgetConfigForm.get('axisTickLabelFont').enable();
this.radarChartWidgetConfigForm.get('axisTickLabelColor').enable();
} else {
this.radarChartWidgetConfigForm.get('axisTickLabelFont').disable();
this.radarChartWidgetConfigForm.get('axisTickLabelColor').disable();
}
if (showLegend) {
this.radarChartWidgetConfigForm.get('legendPosition').enable();
this.radarChartWidgetConfigForm.get('legendLabelFont').enable();
this.radarChartWidgetConfigForm.get('legendLabelColor').enable();
this.radarChartWidgetConfigForm.get('legendValueFont').enable();
this.radarChartWidgetConfigForm.get('legendValueColor').enable();
} else {
this.radarChartWidgetConfigForm.get('legendPosition').disable();
this.radarChartWidgetConfigForm.get('legendLabelFont').disable();
this.radarChartWidgetConfigForm.get('legendLabelColor').disable();
this.radarChartWidgetConfigForm.get('legendValueFont').disable();
this.radarChartWidgetConfigForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.radarChartWidgetConfigForm.get('tooltipValueType').enable();
this.radarChartWidgetConfigForm.get('tooltipValueDecimals').enable();
this.radarChartWidgetConfigForm.get('tooltipValueFont').enable();
this.radarChartWidgetConfigForm.get('tooltipValueColor').enable();
this.radarChartWidgetConfigForm.get('tooltipBackgroundColor').enable();
this.radarChartWidgetConfigForm.get('tooltipBackgroundBlur').enable();
} else {
this.radarChartWidgetConfigForm.get('tooltipValueType').disable();
this.radarChartWidgetConfigForm.get('tooltipValueDecimals').disable();
this.radarChartWidgetConfigForm.get('tooltipValueFont').disable();
this.radarChartWidgetConfigForm.get('tooltipValueColor').disable();
this.radarChartWidgetConfigForm.get('tooltipBackgroundColor').disable();
this.radarChartWidgetConfigForm.get('tooltipBackgroundBlur').disable();
}
}
private getSeries(datasources?: Datasource[]): DataKey[] {
if (datasources && datasources.length) {
return datasources[0].dataKeys || [];
}
return [];
}
private setSeries(series: DataKey[], datasources?: Datasource[]) {
if (datasources && datasources.length) {
datasources[0].dataKeys = series;
}
}
private getCardButtons(config: WidgetConfig): string[] {
const buttons: string[] = [];
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) {
buttons.push('fullscreen');
}
return buttons;
}
private setCardButtons(buttons: string[], config: WidgetConfig) {
config.enableFullscreen = buttons.includes('fullscreen');
}
private _valuePreviewFn(): string {
const units: string = this.radarChartWidgetConfigForm.get('units').value;
const decimals: number = this.radarChartWidgetConfigForm.get('decimals').value;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.radarChartWidgetConfigForm.get('tooltipValueType').value;
const decimals: number = this.radarChartWidgetConfigForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
latestChartWidgetConfigForm.get('axisTickLabelFont').enable();
latestChartWidgetConfigForm.get('axisTickLabelColor').enable();
} else {
const units: string = this.radarChartWidgetConfigForm.get('units').value;
return formatValue(110, decimals, units, false);
latestChartWidgetConfigForm.get('axisTickLabelFont').disable();
latestChartWidgetConfigForm.get('axisTickLabelColor').disable();
}
}
}

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

@ -1,169 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="barChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="barChartWidgetSettingsForm.get('showLegend').value" [disabled]="!barChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="barChartWidgetSettingsForm.get('showTooltip').value" [disabled]="!barChartWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

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

@ -14,147 +14,47 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import {
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { WidgetSettings } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
barChartWidgetDefaultSettings,
BarChartWidgetSettings
} from '@home/components/widget/lib/chart/bar-chart-widget.models';
import {
LatestChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
@Component({
selector: 'tb-bar-chart-widget-settings',
templateUrl: './bar-chart-widget-settings.component.html',
styleUrls: []
templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class BarChartWidgetSettingsComponent extends WidgetSettingsComponent {
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
export class BarChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<BarChartWidgetSettings> {
barChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('barChart')
barChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.barChartWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<BarChartWidgetSettings>({} as BarChartWidgetSettings, barChartWidgetDefaultSettings);
protected fb: UntypedFormBuilder) {
super(store, fb);
}
protected onSettingsSet(settings: WidgetSettings) {
this.barChartWidgetSettingsForm = this.fb.group({
sortSeries: [settings.sortSeries, []],
barSettings: [settings.barSettings, []],
axisMin: [settings.axisMin, []],
axisMax: [settings.axisMax, []],
axisTickLabelFont: [settings.axisTickLabelFont, []],
axisTickLabelColor: [settings.axisTickLabelColor, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
protected defaultLatestChartSettings() {
return barChartWidgetDefaultSettings;
}
protected validatorTriggers(): string[] {
return ['showLegend', 'showTooltip'];
public latestChartConfigTemplate(): TemplateRef<any> {
return this.barChartConfigTemplate;
}
protected updateValidators(emitEvent: boolean) {
const showLegend: boolean = this.barChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.barChartWidgetSettingsForm.get('showTooltip').value;
if (showLegend) {
this.barChartWidgetSettingsForm.get('legendPosition').enable();
this.barChartWidgetSettingsForm.get('legendLabelFont').enable();
this.barChartWidgetSettingsForm.get('legendLabelColor').enable();
this.barChartWidgetSettingsForm.get('legendValueFont').enable();
this.barChartWidgetSettingsForm.get('legendValueColor').enable();
} else {
this.barChartWidgetSettingsForm.get('legendPosition').disable();
this.barChartWidgetSettingsForm.get('legendLabelFont').disable();
this.barChartWidgetSettingsForm.get('legendLabelColor').disable();
this.barChartWidgetSettingsForm.get('legendValueFont').disable();
this.barChartWidgetSettingsForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.barChartWidgetSettingsForm.get('tooltipValueType').enable();
this.barChartWidgetSettingsForm.get('tooltipValueDecimals').enable();
this.barChartWidgetSettingsForm.get('tooltipValueFont').enable();
this.barChartWidgetSettingsForm.get('tooltipValueColor').enable();
this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
} else {
this.barChartWidgetSettingsForm.get('tooltipValueType').disable();
this.barChartWidgetSettingsForm.get('tooltipValueDecimals').disable();
this.barChartWidgetSettingsForm.get('tooltipValueFont').disable();
this.barChartWidgetSettingsForm.get('tooltipValueColor').disable();
this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
}
private _valuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
return formatValue(110, decimals, units, false);
protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
latestChartWidgetSettingsForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
latestChartWidgetSettingsForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
latestChartWidgetSettingsForm.addControl('axisMax', this.fb.control(settings.axisMax, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.barChartWidgetSettingsForm.get('tooltipValueType').value;
const decimals: number = this.barChartWidgetSettingsForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.widgetConfig.config.units;
return formatValue(110, decimals, units, false);
}
}
}

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

@ -1,166 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="doughnutWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.doughnut.doughnut-card-style</div>
<tb-image-cards-select rowHeight="{{ horizontal ? '8:5' : '5:4' }}"
[cols]="{columns: 2,
breakpoints: {
'lt-sm': 1
}}"
label="{{ 'widgets.doughnut.layout' | translate }}" formControlName="layout">
<tb-image-cards-select-option *ngFor="let layout of doughnutLayouts"
[value]="layout"
[image]="doughnutLayoutImageMap.get(layout)">
{{ doughnutLayoutTranslationMap.get(layout) | translate }}
</tb-image-cards-select-option>
</tb-image-cards-select>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="autoScale">
{{ 'widgets.latest-chart.auto-scale' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div [fxShow]="totalEnabled" class="tb-form-row space-between">
<div>{{ 'widgets.doughnut.central-total-value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="totalValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-settings formControlName="totalValueColor" settingsKey="{{'widgets.doughnut.central-total-value' | translate }}">
</tb-color-settings>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="doughnutWidgetSettingsForm.get('showLegend').value" [disabled]="!doughnutWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="doughnutWidgetSettingsForm.get('showTooltip').value" [disabled]="!doughnutWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

176
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/doughnut-widget-settings.component.ts

@ -14,180 +14,64 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import {
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { WidgetSettings } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, isDefinedAndNotNull, mergeDeep } from '@core/utils';
import {
doughnutDefaultSettings,
DoughnutLayout,
doughnutLayoutImages,
doughnutLayouts,
doughnutLayoutTranslations,
DoughnutWidgetSettings,
horizontalDoughnutLayoutImages
DoughnutWidgetSettings
} from '@home/components/widget/lib/chart/doughnut-widget.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
LatestChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
@Component({
selector: 'tb-doughnut-widget-settings',
templateUrl: './doughnut-widget-settings.component.html',
styleUrls: []
templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class DoughnutWidgetSettingsComponent extends WidgetSettingsComponent {
get totalEnabled(): boolean {
const layout: DoughnutLayout = this.doughnutWidgetSettingsForm.get('layout').value;
return layout === DoughnutLayout.with_total;
}
doughnutLayouts = doughnutLayouts;
doughnutLayoutTranslationMap = doughnutLayoutTranslations;
horizontal = false;
doughnutLayoutImageMap: Map<DoughnutLayout, string>;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
export class DoughnutWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<DoughnutWidgetSettings> {
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
doughnutWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('doughnutChart')
doughnutChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
protected fb: UntypedFormBuilder) {
super(store, fb);
}
protected settingsForm(): UntypedFormGroup {
return this.doughnutWidgetSettingsForm;
protected defaultLatestChartSettings() {
return doughnutDefaultSettings(this.doughnutHorizontal);
}
protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) {
const params = widgetConfig.typeParameters as any;
this.horizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false;
this.doughnutLayoutImageMap = this.horizontal ? horizontalDoughnutLayoutImages : doughnutLayoutImages;
public latestChartConfigTemplate(): TemplateRef<any> {
return this.doughnutChartConfigTemplate;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<DoughnutWidgetSettings>({} as DoughnutWidgetSettings, doughnutDefaultSettings(this.horizontal));
protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
latestChartWidgetSettingsForm.addControl('layout', this.fb.control(settings.layout, []));
latestChartWidgetSettingsForm.addControl('autoScale', this.fb.control(settings.autoScale, []));
latestChartWidgetSettingsForm.addControl('clockwise', this.fb.control(settings.clockwise, []));
latestChartWidgetSettingsForm.addControl('totalValueFont', this.fb.control(settings.totalValueFont, []));
latestChartWidgetSettingsForm.addControl('totalValueColor', this.fb.control(settings.totalValueColor, []));
}
protected onSettingsSet(settings: WidgetSettings) {
this.doughnutWidgetSettingsForm = this.fb.group({
layout: [settings.layout, []],
autoScale: [settings.autoScale, []],
clockwise: [settings.clockwise, []],
sortSeries: [settings.sortSeries, []],
totalValueFont: [settings.totalValueFont, []],
totalValueColor: [settings.totalValueColor, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
}
protected validatorTriggers(): string[] {
return ['layout', 'showLegend', 'showTooltip'];
protected latestChartValidatorTriggers(): string[] {
return ['layout'];
}
protected updateValidators(emitEvent: boolean) {
const layout: DoughnutLayout = this.doughnutWidgetSettingsForm.get('layout').value;
const showLegend: boolean = this.doughnutWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.doughnutWidgetSettingsForm.get('showTooltip').value;
protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const layout: DoughnutLayout = latestChartWidgetSettingsForm.get('layout').value;
const totalEnabled = layout === DoughnutLayout.with_total;
if (showLegend) {
this.doughnutWidgetSettingsForm.get('legendPosition').enable();
this.doughnutWidgetSettingsForm.get('legendLabelFont').enable();
this.doughnutWidgetSettingsForm.get('legendLabelColor').enable();
this.doughnutWidgetSettingsForm.get('legendValueFont').enable();
this.doughnutWidgetSettingsForm.get('legendValueColor').enable();
} else {
this.doughnutWidgetSettingsForm.get('legendPosition').disable();
this.doughnutWidgetSettingsForm.get('legendLabelFont').disable();
this.doughnutWidgetSettingsForm.get('legendLabelColor').disable();
this.doughnutWidgetSettingsForm.get('legendValueFont').disable();
this.doughnutWidgetSettingsForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.doughnutWidgetSettingsForm.get('tooltipValueType').enable();
this.doughnutWidgetSettingsForm.get('tooltipValueDecimals').enable();
this.doughnutWidgetSettingsForm.get('tooltipValueFont').enable();
this.doughnutWidgetSettingsForm.get('tooltipValueColor').enable();
this.doughnutWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.doughnutWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
} else {
this.doughnutWidgetSettingsForm.get('tooltipValueType').disable();
this.doughnutWidgetSettingsForm.get('tooltipValueDecimals').disable();
this.doughnutWidgetSettingsForm.get('tooltipValueFont').disable();
this.doughnutWidgetSettingsForm.get('tooltipValueColor').disable();
this.doughnutWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.doughnutWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
if (totalEnabled) {
this.doughnutWidgetSettingsForm.get('totalValueFont').enable();
this.doughnutWidgetSettingsForm.get('totalValueColor').enable();
} else {
this.doughnutWidgetSettingsForm.get('totalValueFont').disable();
this.doughnutWidgetSettingsForm.get('totalValueColor').disable();
}
}
private _valuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.doughnutWidgetSettingsForm.get('tooltipValueType').value;
const decimals: number = this.doughnutWidgetSettingsForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
latestChartWidgetSettingsForm.get('totalValueFont').enable();
latestChartWidgetSettingsForm.get('totalValueColor').enable();
} else {
const units: string = this.widgetConfig.config.units;
return formatValue(110, decimals, units, false);
latestChartWidgetSettingsForm.get('totalValueFont').disable();
latestChartWidgetSettingsForm.get('totalValueColor').disable();
}
}
}

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

@ -0,0 +1,463 @@
<!--
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.
-->
<ng-container [formGroup]="latestChartWidgetSettingsForm">
<ng-container *ngTemplateOutlet="latestChartConfigTemplate()"></ng-container>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="latestChartWidgetSettingsForm.get('showLegend').value" [disabled]="!latestChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="latestChartWidgetSettingsForm.get('showTooltip').value" [disabled]="!latestChartWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-panel no-padding">
<div class="tb-form-row no-border space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>
<ng-template #pieChart>
<ng-container [formGroup]="latestChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.pie-chart.pie-chart-card-style</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showLabel">
{{ 'widgets.pie-chart.label' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="labelPosition">
<mat-option *ngFor="let position of pieChartLabelPositions" [value]="position">
{{ pieChartLabelPositionTranslationMap.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
disabledLineHeight
forceSizeUnit="px"
[previewText]="'Wind<br/>55%'">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.border' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="borderWidth" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="borderColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.radius' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="radius" type="number" min="0" max="100" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>%</div>
</mat-form-field>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #doughnutChart>
<ng-container [formGroup]="latestChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.doughnut.doughnut-card-style</div>
<tb-image-cards-select rowHeight="{{ doughnutHorizontal ? '8:5' : '5:4' }}"
[cols]="{columns: 2,
breakpoints: {
'lt-sm': 1
}}"
label="{{ 'widgets.doughnut.layout' | translate }}" formControlName="layout">
<tb-image-cards-select-option *ngFor="let layout of doughnutLayouts"
[value]="layout"
[image]="doughnutLayoutImageMap.get(layout)">
{{ doughnutLayoutTranslationMap.get(layout) | translate }}
</tb-image-cards-select-option>
</tb-image-cards-select>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="autoScale">
{{ 'widgets.latest-chart.auto-scale' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div [fxShow]="doughnutTotalEnabled" class="tb-form-row space-between">
<div>{{ 'widgets.doughnut.central-total-value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="totalValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-settings formControlName="totalValueColor" settingsKey="{{'widgets.doughnut.central-total-value' | translate }}">
</tb-color-settings>
</div>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #barChart>
<ng-container [formGroup]="latestChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #polarAreaChart>
<ng-container [formGroup]="latestChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.polar-area-chart.polar-area-chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
pieLabelPosition
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.polar-area-chart.polar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.polar-area-chart.start-angle</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="angleAxisStartAngle" type="number" min="0" max="360" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
</div>
</ng-container>
</ng-template>
<ng-template #radarChart>
<ng-container [formGroup]="latestChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.radar-chart.shape' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="shape">
<mat-option *ngFor="let shape of radarChartShapes" [value]="shape">
{{ radarChartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.radar-chart.color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="color">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showLine">
{{ 'widgets.radar-chart.line' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="lineType">
<mat-option *ngFor="let type of chartLineTypes" [value]="type">
{{ chartLineTypeTranslations.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="lineWidth"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showPoints">
{{ 'widgets.radar-chart.points' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of chartShapes" [value]="shape">
{{ chartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="pointSize"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showLabel">
{{ 'widgets.radar-chart.points-label' | translate }}
</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="labelPosition">
<mat-option *ngFor="let position of chartLabelPositions" [value]="position">
{{ chartLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<tb-chart-fill-settings
formControlName="fillAreaSettings">
</tb-chart-fill-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-axis</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowLabel">
{{ 'widgets.radar-chart.axis-label' | translate }}
</mat-slide-toggle>
<tb-font-settings formControlName="axisLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="Wind">
</tb-font-settings>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowTickLabels">
{{ 'widgets.radar-chart.ticks-label' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
</div>
</ng-container>
</ng-template>

217
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/latest-chart-widget-settings.component.ts

@ -0,0 +1,217 @@
///
/// 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 { Directive, TemplateRef } from '@angular/core';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations,
LatestChartWidgetSettings
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import {
DoughnutLayout, doughnutLayoutImages,
doughnutLayouts,
doughnutLayoutTranslations, horizontalDoughnutLayoutImages
} from '@home/components/widget/lib/chart/doughnut-widget.models';
import {
chartLabelPositions,
chartLabelPositionTranslations,
chartLineTypes,
chartLineTypeTranslations,
chartShapes,
chartShapeTranslations,
pieChartLabelPositions,
pieChartLabelPositionTranslations
} from '@home/components/widget/lib/chart/chart.models';
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
import { formatValue, isDefinedAndNotNull, mergeDeep } from '@core/utils';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class LatestChartWidgetSettingsComponent<S extends LatestChartWidgetSettings> extends WidgetSettingsComponent {
doughnutLayouts = doughnutLayouts;
doughnutLayoutTranslationMap = doughnutLayoutTranslations;
doughnutHorizontal = false;
doughnutLayoutImageMap: Map<DoughnutLayout, string>;
pieChartLabelPositions = pieChartLabelPositions;
pieChartLabelPositionTranslationMap = pieChartLabelPositionTranslations;
radarChartShapes = radarChartShapes;
radarChartShapeTranslations = radarChartShapeTranslations;
chartLineTypes = chartLineTypes;
chartLineTypeTranslations = chartLineTypeTranslations;
chartShapes = chartShapes;
chartShapeTranslations = chartShapeTranslations;
chartLabelPositions = chartLabelPositions;
chartLabelPositionTranslations = chartLabelPositionTranslations;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
latestChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
get doughnutTotalEnabled(): boolean {
const layout: DoughnutLayout = this.latestChartWidgetSettingsForm.get('layout').value;
return layout === DoughnutLayout.with_total;
}
constructor(protected store: Store<AppState>,
protected fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.latestChartWidgetSettingsForm;
}
protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) {
const params = widgetConfig.typeParameters as any;
this.doughnutHorizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false;
this.doughnutLayoutImageMap = this.doughnutHorizontal ? horizontalDoughnutLayoutImages : doughnutLayoutImages;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<S>({} as S, this.defaultLatestChartSettings());
}
protected onSettingsSet(settings: WidgetSettings) {
this.latestChartWidgetSettingsForm = this.fb.group({
sortSeries: [settings.sortSeries, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
this.setupLatestChartControls(this.latestChartWidgetSettingsForm, settings);
}
protected validatorTriggers(): string[] {
return ['showLegend', 'showTooltip'].concat(this.latestChartValidatorTriggers());
}
protected updateValidators(emitEvent: boolean, trigger?: string) {
const showLegend: boolean = this.latestChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.latestChartWidgetSettingsForm.get('showTooltip').value;
if (showLegend) {
this.latestChartWidgetSettingsForm.get('legendPosition').enable();
this.latestChartWidgetSettingsForm.get('legendLabelFont').enable();
this.latestChartWidgetSettingsForm.get('legendLabelColor').enable();
this.latestChartWidgetSettingsForm.get('legendValueFont').enable();
this.latestChartWidgetSettingsForm.get('legendValueColor').enable();
} else {
this.latestChartWidgetSettingsForm.get('legendPosition').disable();
this.latestChartWidgetSettingsForm.get('legendLabelFont').disable();
this.latestChartWidgetSettingsForm.get('legendLabelColor').disable();
this.latestChartWidgetSettingsForm.get('legendValueFont').disable();
this.latestChartWidgetSettingsForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.latestChartWidgetSettingsForm.get('tooltipValueType').enable();
this.latestChartWidgetSettingsForm.get('tooltipValueDecimals').enable();
this.latestChartWidgetSettingsForm.get('tooltipValueFont').enable();
this.latestChartWidgetSettingsForm.get('tooltipValueColor').enable();
this.latestChartWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.latestChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
} else {
this.latestChartWidgetSettingsForm.get('tooltipValueType').disable();
this.latestChartWidgetSettingsForm.get('tooltipValueDecimals').disable();
this.latestChartWidgetSettingsForm.get('tooltipValueFont').disable();
this.latestChartWidgetSettingsForm.get('tooltipValueColor').disable();
this.latestChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.latestChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
this.updateLatestChartValidators(this.latestChartWidgetSettingsForm, emitEvent, trigger);
}
protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {}
protected latestChartValidatorTriggers(): string[] {
return [];
}
protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
}
protected abstract defaultLatestChartSettings(): S;
public abstract latestChartConfigTemplate(): TemplateRef<any>;
private _valuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.latestChartWidgetSettingsForm.get('tooltipValueType').value;
const decimals: number = this.latestChartWidgetSettingsForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.widgetConfig.config.units;
return formatValue(110, decimals, units, false);
}
}
}

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

@ -1,184 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="pieChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.pie-chart.pie-chart-card-style</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showLabel">
{{ 'widgets.pie-chart.label' | translate }}
</mat-slide-toggle>
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field fxFlex appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="labelPosition">
<mat-option *ngFor="let position of pieChartLabelPositions" [value]="position">
{{ pieChartLabelPositionTranslationMap.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
disabledLineHeight
forceSizeUnit="px"
[previewText]="'Wind<br/>55%'">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.border' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="borderWidth" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
<tb-color-input asBoxInput
colorClearButton
formControlName="borderColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.pie-chart.radius' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="radius" type="number" min="0" max="100" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>%</div>
</mat-form-field>
</div>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="clockwise">
{{ 'widgets.latest-chart.clockwise-layout' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="pieChartWidgetSettingsForm.get('showLegend').value" [disabled]="!pieChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="pieChartWidgetSettingsForm.get('showTooltip').value" [disabled]="!pieChartWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

172
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/pie-chart-widget-settings.component.ts

@ -14,169 +14,67 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import {
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { WidgetSettings } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
pieChartLabelPositions,
pieChartLabelPositionTranslations
} from '@home/components/widget/lib/chart/chart.models';
import {
pieChartWidgetDefaultSettings,
PieChartWidgetSettings
} from '@home/components/widget/lib/chart/pie-chart-widget.models';
import {
LatestChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
@Component({
selector: 'tb-pie-chart-widget-settings',
templateUrl: './pie-chart-widget-settings.component.html',
styleUrls: []
templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class PieChartWidgetSettingsComponent extends WidgetSettingsComponent {
pieChartLabelPositions = pieChartLabelPositions;
pieChartLabelPositionTranslationMap = pieChartLabelPositionTranslations;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
export class PieChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<PieChartWidgetSettings> {
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
pieChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('pieChart')
pieChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
protected fb: UntypedFormBuilder) {
super(store, fb);
}
protected settingsForm(): UntypedFormGroup {
return this.pieChartWidgetSettingsForm;
protected defaultLatestChartSettings() {
return pieChartWidgetDefaultSettings;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<PieChartWidgetSettings>({} as PieChartWidgetSettings, pieChartWidgetDefaultSettings);
public latestChartConfigTemplate(): TemplateRef<any> {
return this.pieChartConfigTemplate;
}
protected onSettingsSet(settings: WidgetSettings) {
this.pieChartWidgetSettingsForm = this.fb.group({
showLabel: [settings.showLabel, []],
labelPosition: [settings.labelPosition, []],
labelFont: [settings.labelFont, []],
labelColor: [settings.labelColor, []],
borderWidth: [settings.borderWidth, [Validators.min(0)]],
borderColor: [settings.borderColor, []],
radius: [settings.radius, [Validators.min(0), Validators.max(100)]],
clockwise: [settings.clockwise, []],
sortSeries: [settings.sortSeries, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
latestChartWidgetSettingsForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
latestChartWidgetSettingsForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
latestChartWidgetSettingsForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
latestChartWidgetSettingsForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
latestChartWidgetSettingsForm.addControl('borderWidth', this.fb.control(settings.borderWidth, [Validators.min(0)]));
latestChartWidgetSettingsForm.addControl('borderColor', this.fb.control(settings.borderColor, []));
latestChartWidgetSettingsForm.addControl('radius', this.fb.control(settings.radius, []));
latestChartWidgetSettingsForm.addControl('clockwise', this.fb.control(settings.clockwise, []));
}
protected validatorTriggers(): string[] {
return ['showLabel', 'showLegend', 'showTooltip'];
protected latestChartValidatorTriggers(): string[] {
return ['showLabel'];
}
protected updateValidators(emitEvent: boolean) {
const showLabel: boolean = this.pieChartWidgetSettingsForm.get('showLabel').value;
const showLegend: boolean = this.pieChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.pieChartWidgetSettingsForm.get('showTooltip').value;
protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLabel: boolean = latestChartWidgetSettingsForm.get('showLabel').value;
if (showLabel) {
this.pieChartWidgetSettingsForm.get('labelPosition').enable();
this.pieChartWidgetSettingsForm.get('labelFont').enable();
this.pieChartWidgetSettingsForm.get('labelColor').enable();
} else {
this.pieChartWidgetSettingsForm.get('labelPosition').disable();
this.pieChartWidgetSettingsForm.get('labelFont').disable();
this.pieChartWidgetSettingsForm.get('labelColor').disable();
}
if (showLegend) {
this.pieChartWidgetSettingsForm.get('legendPosition').enable();
this.pieChartWidgetSettingsForm.get('legendLabelFont').enable();
this.pieChartWidgetSettingsForm.get('legendLabelColor').enable();
this.pieChartWidgetSettingsForm.get('legendValueFont').enable();
this.pieChartWidgetSettingsForm.get('legendValueColor').enable();
} else {
this.pieChartWidgetSettingsForm.get('legendPosition').disable();
this.pieChartWidgetSettingsForm.get('legendLabelFont').disable();
this.pieChartWidgetSettingsForm.get('legendLabelColor').disable();
this.pieChartWidgetSettingsForm.get('legendValueFont').disable();
this.pieChartWidgetSettingsForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.pieChartWidgetSettingsForm.get('tooltipValueType').enable();
this.pieChartWidgetSettingsForm.get('tooltipValueDecimals').enable();
this.pieChartWidgetSettingsForm.get('tooltipValueFont').enable();
this.pieChartWidgetSettingsForm.get('tooltipValueColor').enable();
this.pieChartWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.pieChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
} else {
this.pieChartWidgetSettingsForm.get('tooltipValueType').disable();
this.pieChartWidgetSettingsForm.get('tooltipValueDecimals').disable();
this.pieChartWidgetSettingsForm.get('tooltipValueFont').disable();
this.pieChartWidgetSettingsForm.get('tooltipValueColor').disable();
this.pieChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.pieChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
}
private _valuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.pieChartWidgetSettingsForm.get('tooltipValueType').value;
const decimals: number = this.pieChartWidgetSettingsForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
latestChartWidgetSettingsForm.get('labelPosition').enable();
latestChartWidgetSettingsForm.get('labelFont').enable();
latestChartWidgetSettingsForm.get('labelColor').enable();
} else {
const units: string = this.widgetConfig.config.units;
return formatValue(110, decimals, units, false);
latestChartWidgetSettingsForm.get('labelPosition').disable();
latestChartWidgetSettingsForm.get('labelFont').disable();
latestChartWidgetSettingsForm.get('labelColor').disable();
}
}
}

176
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/polar-area-chart-widget-settings.component.html

@ -1,176 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="polarAreaChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.polar-area-chart.polar-area-chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div>
<tb-chart-bar-settings
formControlName="barSettings"
pieLabelPosition
[series]="false">
</tb-chart-bar-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.polar-area-chart.polar-axis</div>
<div class="tb-form-row space-between column-xs">
<div translate>widgets.chart.chart-axis.scale</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-min</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMin"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<div class="tb-small-label" translate>widgets.chart.chart-axis.scale-max</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="axisMax"
type="number" placeholder="{{ 'widgets.chart.chart-axis.scale-auto' | translate }}">
</mat-form-field>
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.polar-area-chart.start-angle</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="angleAxisStartAngle" type="number" min="0" max="360" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="polarAreaChartWidgetSettingsForm.get('showLegend').value" [disabled]="!polarAreaChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="polarAreaChartWidgetSettingsForm.get('showTooltip').value" [disabled]="!polarAreaChartWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

146
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/polar-area-chart-widget-settings.component.ts

@ -14,148 +14,48 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import {
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { WidgetSettings } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
polarAreaChartWidgetDefaultSettings,
PolarAreaChartWidgetSettings
} from '@home/components/widget/lib/chart/polar-area-widget.models';
import {
LatestChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
@Component({
selector: 'tb-polar-area-chart-widget-settings',
templateUrl: './polar-area-chart-widget-settings.component.html',
styleUrls: []
templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class PolarAreaChartWidgetSettingsComponent extends WidgetSettingsComponent {
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
export class PolarAreaChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<PolarAreaChartWidgetSettings> {
polarAreaChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('polarAreaChart')
polarAreaChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
}
protected settingsForm(): UntypedFormGroup {
return this.polarAreaChartWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<PolarAreaChartWidgetSettings>({} as PolarAreaChartWidgetSettings, polarAreaChartWidgetDefaultSettings);
protected fb: UntypedFormBuilder) {
super(store, fb);
}
protected onSettingsSet(settings: WidgetSettings) {
this.polarAreaChartWidgetSettingsForm = this.fb.group({
sortSeries: [settings.sortSeries, []],
barSettings: [settings.barSettings, []],
axisMin: [settings.axisMin, []],
axisMax: [settings.axisMax, []],
axisTickLabelFont: [settings.axisTickLabelFont, []],
axisTickLabelColor: [settings.axisTickLabelColor, []],
angleAxisStartAngle: [settings.angleAxisStartAngle, [Validators.min(0), Validators.max(360)]],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
protected defaultLatestChartSettings() {
return polarAreaChartWidgetDefaultSettings;
}
protected validatorTriggers(): string[] {
return ['showLegend', 'showTooltip'];
public latestChartConfigTemplate(): TemplateRef<any> {
return this.polarAreaChartConfigTemplate;
}
protected updateValidators(emitEvent: boolean) {
const showLegend: boolean = this.polarAreaChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.polarAreaChartWidgetSettingsForm.get('showTooltip').value;
if (showLegend) {
this.polarAreaChartWidgetSettingsForm.get('legendPosition').enable();
this.polarAreaChartWidgetSettingsForm.get('legendLabelFont').enable();
this.polarAreaChartWidgetSettingsForm.get('legendLabelColor').enable();
this.polarAreaChartWidgetSettingsForm.get('legendValueFont').enable();
this.polarAreaChartWidgetSettingsForm.get('legendValueColor').enable();
} else {
this.polarAreaChartWidgetSettingsForm.get('legendPosition').disable();
this.polarAreaChartWidgetSettingsForm.get('legendLabelFont').disable();
this.polarAreaChartWidgetSettingsForm.get('legendLabelColor').disable();
this.polarAreaChartWidgetSettingsForm.get('legendValueFont').disable();
this.polarAreaChartWidgetSettingsForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.polarAreaChartWidgetSettingsForm.get('tooltipValueType').enable();
this.polarAreaChartWidgetSettingsForm.get('tooltipValueDecimals').enable();
this.polarAreaChartWidgetSettingsForm.get('tooltipValueFont').enable();
this.polarAreaChartWidgetSettingsForm.get('tooltipValueColor').enable();
this.polarAreaChartWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.polarAreaChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
} else {
this.polarAreaChartWidgetSettingsForm.get('tooltipValueType').disable();
this.polarAreaChartWidgetSettingsForm.get('tooltipValueDecimals').disable();
this.polarAreaChartWidgetSettingsForm.get('tooltipValueFont').disable();
this.polarAreaChartWidgetSettingsForm.get('tooltipValueColor').disable();
this.polarAreaChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.polarAreaChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
}
private _valuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
return formatValue(110, decimals, units, false);
protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
latestChartWidgetSettingsForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
latestChartWidgetSettingsForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
latestChartWidgetSettingsForm.addControl('axisMax', this.fb.control(settings.axisMax, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, [Validators.min(0)]));
latestChartWidgetSettingsForm.addControl('angleAxisStartAngle', this.fb.control(settings.angleAxisStartAngle, []));
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.polarAreaChartWidgetSettingsForm.get('tooltipValueType').value;
const decimals: number = this.polarAreaChartWidgetSettingsForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.widgetConfig.config.units;
return formatValue(110, decimals, units, false);
}
}
}

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

@ -1,248 +0,0 @@
<!--
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.
-->
<ng-container [formGroup]="radarChartWidgetSettingsForm">
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-chart-style</div>
<div class="tb-form-row">
<mat-slide-toggle class="mat-slide" formControlName="sortSeries">
{{ 'widgets.latest-chart.sort-series' | translate }}
</mat-slide-toggle>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-appearance</div>
<div class="tb-form-row space-between">
<div>{{ 'widgets.radar-chart.shape' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="shape">
<mat-option *ngFor="let shape of radarChartShapes" [value]="shape">
{{ radarChartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div translate>widgets.radar-chart.color</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="color">
</tb-color-input>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showLine">
{{ 'widgets.radar-chart.line' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="lineType">
<mat-option *ngFor="let type of chartLineTypes" [value]="type">
{{ chartLineTypeTranslations.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="lineWidth"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-xs">
<mat-slide-toggle class="mat-slide" formControlName="showPoints">
{{ 'widgets.radar-chart.points' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" fxFlex.xs appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="pointShape">
<mat-option *ngFor="let shape of chartShapes" [value]="shape">
{{ chartShapeTranslations.get(shape) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number fixed-width" subscriptSizing="dynamic">
<input matInput formControlName="pointSize"
type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
</mat-form-field>
</div>
</div>
<div class="tb-form-row space-between column-lt-md">
<mat-slide-toggle class="mat-slide" formControlName="showLabel">
{{ 'widgets.radar-chart.points-label' | translate }}
</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="labelPosition">
<mat-option *ngFor="let position of chartLabelPositions" [value]="position">
{{ chartLabelPositionTranslations.get(position) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-font-settings formControlName="labelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="labelColor">
</tb-color-input>
</div>
</div>
<tb-chart-fill-settings
formControlName="fillAreaSettings">
</tb-chart-fill-settings>
</div>
<div class="tb-form-panel">
<div class="tb-form-panel-title" translate>widgets.radar-chart.radar-axis</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowLabel">
{{ 'widgets.radar-chart.axis-label' | translate }}
</mat-slide-toggle>
<tb-font-settings formControlName="axisLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="Wind">
</tb-font-settings>
</div>
<div class="tb-form-row space-between">
<mat-slide-toggle class="mat-slide" formControlName="axisShowTickLabels">
{{ 'widgets.radar-chart.ticks-label' | translate }}
</mat-slide-toggle>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="axisTickLabelFont"
clearButton
disabledLineHeight
forceSizeUnit="px"
previewText="100">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="axisTickLabelColor">
</tb-color-input>
</div>
</div>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="radarChartWidgetSettingsForm.get('showLegend').value" [disabled]="!radarChartWidgetSettingsForm.get('showLegend').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showLegend" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.legend' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between">
<div>{{ 'legend.position' | translate }}</div>
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="legendPosition">
<mat-option *ngFor="let pos of legendPositions" [value]="pos">
{{ legendPositionTranslationMap.get(pos) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.label' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendLabelFont"
previewText="Wind power">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendLabelColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'legend.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<tb-font-settings formControlName="legendValueFont"
[previewText]="valuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="legendValueColor">
</tb-color-input>
</div>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<div class="tb-form-panel tb-slide-toggle">
<mat-expansion-panel class="tb-settings" [expanded]="radarChartWidgetSettingsForm.get('showTooltip').value" [disabled]="!radarChartWidgetSettingsForm.get('showTooltip').value">
<mat-expansion-panel-header fxLayout="row wrap">
<mat-panel-title>
<mat-slide-toggle class="mat-slide" formControlName="showTooltip" (click)="$event.stopPropagation()"
fxLayoutAlign="center">
{{ 'widget-config.tooltip' | translate }}
</mat-slide-toggle>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-template matExpansionPanelContent>
<div class="tb-form-row space-between column-xs">
<div>{{ 'tooltip.value' | translate }}</div>
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px">
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic">
<mat-select formControlName="tooltipValueType">
<mat-option *ngFor="let type of latestChartTooltipValueTypes" [value]="type">
{{ latestChartTooltipValueTypeTranslationMap.get(type) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipValueDecimals" type="number" min="0" max="15" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix fxHide.lt-md translate>widget-config.decimals-suffix</div>
</mat-form-field>
<tb-font-settings formControlName="tooltipValueFont"
[previewText]="tooltipValuePreviewFn">
</tb-font-settings>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipValueColor">
</tb-color-input>
</div>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-color' | translate }}</div>
<tb-color-input asBoxInput
colorClearButton
formControlName="tooltipBackgroundColor">
</tb-color-input>
</div>
<div class="tb-form-row space-between">
<div>{{ 'tooltip.background-blur' | translate }}</div>
<mat-form-field appearance="outline" class="number" subscriptSizing="dynamic">
<input matInput formControlName="tooltipBackgroundBlur" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}">
<div matSuffix>px</div>
</mat-form-field>
</div>
</ng-template>
</mat-expansion-panel>
</div>
<tb-chart-animation-settings
formControlName="animation">
</tb-chart-animation-settings>
<div class="tb-form-row space-between">
<div>{{ 'widgets.background.background' | translate }}</div>
<tb-background-settings formControlName="background">
</tb-background-settings>
</div>
</div>
</ng-container>

244
ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/radar-chart-widget-settings.component.ts

@ -14,231 +14,113 @@
/// limitations under the License.
///
import { Component } from '@angular/core';
import {
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { Component, TemplateRef, ViewChild } from '@angular/core';
import { WidgetSettings } from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import {
radarChartWidgetDefaultSettings,
RadarChartWidgetSettings
} from '@home/components/widget/lib/chart/radar-chart-widget.models';
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
import {
chartLabelPositions,
chartLabelPositionTranslations,
chartLineTypes,
chartLineTypeTranslations,
chartShapes,
chartShapeTranslations
} from '@home/components/widget/lib/chart/chart.models';
LatestChartWidgetSettingsComponent
} from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
@Component({
selector: 'tb-radar-chart-widget-settings',
templateUrl: './radar-chart-widget-settings.component.html',
styleUrls: []
templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class RadarChartWidgetSettingsComponent extends WidgetSettingsComponent {
radarChartShapes = radarChartShapes;
radarChartShapeTranslations = radarChartShapeTranslations;
chartLineTypes = chartLineTypes;
chartLineTypeTranslations = chartLineTypeTranslations;
chartShapes = chartShapes;
chartShapeTranslations = chartShapeTranslations;
chartLabelPositions = chartLabelPositions;
export class RadarChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<RadarChartWidgetSettings> {
chartLabelPositionTranslations = chartLabelPositionTranslations;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
radarChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
@ViewChild('radarChart')
radarChartConfigTemplate: TemplateRef<any>;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) {
super(store);
protected fb: UntypedFormBuilder) {
super(store, fb);
}
protected settingsForm(): UntypedFormGroup {
return this.radarChartWidgetSettingsForm;
protected defaultLatestChartSettings() {
return radarChartWidgetDefaultSettings;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<RadarChartWidgetSettings>({} as RadarChartWidgetSettings, radarChartWidgetDefaultSettings);
public latestChartConfigTemplate(): TemplateRef<any> {
return this.radarChartConfigTemplate;
}
protected onSettingsSet(settings: WidgetSettings) {
this.radarChartWidgetSettingsForm = this.fb.group({
sortSeries: [settings.sortSeries, []],
shape: [settings.shape, []],
color: [settings.color, []],
showLine: [settings.showLine, []],
lineType: [settings.lineType, []],
lineWidth: [settings.lineWidth, [Validators.min(0)]],
showPoints: [settings.showPoints, []],
pointShape: [settings.pointShape, []],
pointSize: [settings.pointSize, [Validators.min(0)]],
showLabel: [settings.showLabel, []],
labelPosition: [settings.labelPosition, []],
labelFont: [settings.labelFont, []],
labelColor: [settings.labelColor, []],
fillAreaSettings: [settings.fillAreaSettings, []],
axisShowLabel: [settings.axisShowLabel, []],
axisLabelFont: [settings.axisLabelFont, []],
axisShowTickLabels: [settings.axisShowTickLabels, []],
axisTickLabelFont: [settings.axisTickLabelFont, []],
axisTickLabelColor: [settings.axisTickLabelColor, []],
animation: [settings.animation, []],
showLegend: [settings.showLegend, []],
legendPosition: [settings.legendPosition, []],
legendLabelFont: [settings.legendLabelFont, []],
legendLabelColor: [settings.legendLabelColor, []],
legendValueFont: [settings.legendValueFont, []],
legendValueColor: [settings.legendValueColor, []],
showTooltip: [settings.showTooltip, []],
tooltipValueType: [settings.tooltipValueType, []],
tooltipValueDecimals: [settings.tooltipValueDecimals, []],
tooltipValueFont: [settings.tooltipValueFont, []],
tooltipValueColor: [settings.tooltipValueColor, []],
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []],
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []],
background: [settings.background, []]
});
protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
latestChartWidgetSettingsForm.addControl('shape', this.fb.control(settings.shape, []));
latestChartWidgetSettingsForm.addControl('color', this.fb.control(settings.color, []));
latestChartWidgetSettingsForm.addControl('showLine', this.fb.control(settings.showLine, []));
latestChartWidgetSettingsForm.addControl('lineType', this.fb.control(settings.lineType, []));
latestChartWidgetSettingsForm.addControl('lineWidth', this.fb.control(settings.lineWidth, [Validators.min(0)]));
latestChartWidgetSettingsForm.addControl('showPoints', this.fb.control(settings.showPoints, []));
latestChartWidgetSettingsForm.addControl('pointShape', this.fb.control(settings.pointShape, []));
latestChartWidgetSettingsForm.addControl('pointSize', this.fb.control(settings.pointSize, [Validators.min(0)]));
latestChartWidgetSettingsForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
latestChartWidgetSettingsForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
latestChartWidgetSettingsForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
latestChartWidgetSettingsForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
latestChartWidgetSettingsForm.addControl('fillAreaSettings', this.fb.control(settings.fillAreaSettings, []));
latestChartWidgetSettingsForm.addControl('axisShowLabel', this.fb.control(settings.axisShowLabel, []));
latestChartWidgetSettingsForm.addControl('axisLabelFont', this.fb.control(settings.axisLabelFont, []));
latestChartWidgetSettingsForm.addControl('axisShowTickLabels', this.fb.control(settings.axisShowTickLabels, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
}
protected validatorTriggers(): string[] {
return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel',
'axisShowTickLabels', 'showLegend', 'showTooltip'];
protected latestChartValidatorTriggers(): string[] {
return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel', 'axisShowTickLabels'];
}
protected updateValidators(emitEvent: boolean) {
const showLine: boolean = this.radarChartWidgetSettingsForm.get('showLine').value;
const showPoints: boolean = this.radarChartWidgetSettingsForm.get('showPoints').value;
const showLabel: boolean = this.radarChartWidgetSettingsForm.get('showLabel').value;
const axisShowLabel: boolean = this.radarChartWidgetSettingsForm.get('axisShowLabel').value;
const axisShowTickLabels: boolean = this.radarChartWidgetSettingsForm.get('axisShowTickLabels').value;
const showLegend: boolean = this.radarChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.radarChartWidgetSettingsForm.get('showTooltip').value;
protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLine: boolean = latestChartWidgetSettingsForm.get('showLine').value;
const showPoints: boolean = latestChartWidgetSettingsForm.get('showPoints').value;
const showLabel: boolean = latestChartWidgetSettingsForm.get('showLabel').value;
const axisShowLabel: boolean = latestChartWidgetSettingsForm.get('axisShowLabel').value;
const axisShowTickLabels: boolean = latestChartWidgetSettingsForm.get('axisShowTickLabels').value;
if (showLine) {
this.radarChartWidgetSettingsForm.get('lineType').enable();
this.radarChartWidgetSettingsForm.get('lineWidth').enable();
latestChartWidgetSettingsForm.get('lineType').enable();
latestChartWidgetSettingsForm.get('lineWidth').enable();
} else {
this.radarChartWidgetSettingsForm.get('lineType').disable();
this.radarChartWidgetSettingsForm.get('lineWidth').disable();
latestChartWidgetSettingsForm.get('lineType').disable();
latestChartWidgetSettingsForm.get('lineWidth').disable();
}
if (showPoints) {
this.radarChartWidgetSettingsForm.get('pointShape').enable();
this.radarChartWidgetSettingsForm.get('pointSize').enable();
latestChartWidgetSettingsForm.get('pointShape').enable();
latestChartWidgetSettingsForm.get('pointSize').enable();
} else {
this.radarChartWidgetSettingsForm.get('pointShape').disable();
this.radarChartWidgetSettingsForm.get('pointSize').disable();
latestChartWidgetSettingsForm.get('pointShape').disable();
latestChartWidgetSettingsForm.get('pointSize').disable();
}
if (showLabel) {
this.radarChartWidgetSettingsForm.get('labelPosition').enable();
this.radarChartWidgetSettingsForm.get('labelFont').enable();
this.radarChartWidgetSettingsForm.get('labelColor').enable();
latestChartWidgetSettingsForm.get('labelPosition').enable();
latestChartWidgetSettingsForm.get('labelFont').enable();
latestChartWidgetSettingsForm.get('labelColor').enable();
} else {
this.radarChartWidgetSettingsForm.get('labelPosition').disable();
this.radarChartWidgetSettingsForm.get('labelFont').disable();
this.radarChartWidgetSettingsForm.get('labelColor').disable();
latestChartWidgetSettingsForm.get('labelPosition').disable();
latestChartWidgetSettingsForm.get('labelFont').disable();
latestChartWidgetSettingsForm.get('labelColor').disable();
}
if (axisShowLabel) {
this.radarChartWidgetSettingsForm.get('axisLabelFont').enable();
latestChartWidgetSettingsForm.get('axisLabelFont').enable();
} else {
this.radarChartWidgetSettingsForm.get('axisLabelFont').disable();
latestChartWidgetSettingsForm.get('axisLabelFont').disable();
}
if (axisShowTickLabels) {
this.radarChartWidgetSettingsForm.get('axisTickLabelFont').enable();
this.radarChartWidgetSettingsForm.get('axisTickLabelColor').enable();
latestChartWidgetSettingsForm.get('axisTickLabelFont').enable();
latestChartWidgetSettingsForm.get('axisTickLabelColor').enable();
} else {
this.radarChartWidgetSettingsForm.get('axisTickLabelFont').disable();
this.radarChartWidgetSettingsForm.get('axisTickLabelColor').disable();
}
if (showLegend) {
this.radarChartWidgetSettingsForm.get('legendPosition').enable();
this.radarChartWidgetSettingsForm.get('legendLabelFont').enable();
this.radarChartWidgetSettingsForm.get('legendLabelColor').enable();
this.radarChartWidgetSettingsForm.get('legendValueFont').enable();
this.radarChartWidgetSettingsForm.get('legendValueColor').enable();
} else {
this.radarChartWidgetSettingsForm.get('legendPosition').disable();
this.radarChartWidgetSettingsForm.get('legendLabelFont').disable();
this.radarChartWidgetSettingsForm.get('legendLabelColor').disable();
this.radarChartWidgetSettingsForm.get('legendValueFont').disable();
this.radarChartWidgetSettingsForm.get('legendValueColor').disable();
}
if (showTooltip) {
this.radarChartWidgetSettingsForm.get('tooltipValueType').enable();
this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').enable();
this.radarChartWidgetSettingsForm.get('tooltipValueFont').enable();
this.radarChartWidgetSettingsForm.get('tooltipValueColor').enable();
this.radarChartWidgetSettingsForm.get('tooltipBackgroundColor').enable();
this.radarChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable();
} else {
this.radarChartWidgetSettingsForm.get('tooltipValueType').disable();
this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').disable();
this.radarChartWidgetSettingsForm.get('tooltipValueFont').disable();
this.radarChartWidgetSettingsForm.get('tooltipValueColor').disable();
this.radarChartWidgetSettingsForm.get('tooltipBackgroundColor').disable();
this.radarChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable();
}
}
private _valuePreviewFn(): string {
const units: string = this.widgetConfig.config.units;
const decimals: number = this.widgetConfig.config.decimals;
return formatValue(110, decimals, units, false);
}
private _tooltipValuePreviewFn(): string {
const tooltipValueType: LatestChartTooltipValueType = this.radarChartWidgetSettingsForm.get('tooltipValueType').value;
const decimals: number = this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').value;
if (tooltipValueType === LatestChartTooltipValueType.percentage) {
return formatValue(35, decimals, '%', false);
} else {
const units: string = this.widgetConfig.config.units;
return formatValue(110, decimals, units, false);
latestChartWidgetSettingsForm.get('axisTickLabelFont').disable();
latestChartWidgetSettingsForm.get('axisTickLabelColor').disable();
}
}
}

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

@ -5773,6 +5773,7 @@
}
},
"doughnut": {
"doughnut-appearance": "Doughnut appearance",
"layout": "Layout",
"layout-default": "Default",
"layout-with-total": "With total",
@ -6802,6 +6803,7 @@
"tooltip-value-type-percentage": "Percentage"
},
"pie-chart": {
"pie-chart-appearance": "Pie chart appearance",
"label": "Label",
"border": "Border",
"radius": "Radius",

Loading…
Cancel
Save