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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { import { DataKey } from '@shared/models/widget.models';
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; 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 { import {
barChartWidgetDefaultSettings, barChartWidgetDefaultSettings,
BarChartWidgetSettings BarChartWidgetSettings
} from '@home/components/widget/lib/chart/bar-chart-widget.models'; } 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({ @Component({
selector: 'tb-bar-chart-basic-config', selector: 'tb-bar-chart-basic-config',
templateUrl: './bar-chart-basic-config.component.html', templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss'] styleUrls: ['../basic-config.scss']
}) })
export class BarChartBasicConfigComponent extends BasicWidgetConfigComponent { export class BarChartBasicConfigComponent extends LatestChartBasicConfigComponent<BarChartWidgetSettings> {
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;
valuePreviewFn = this._valuePreviewFn.bind(this); @ViewChild('barChart')
barChartConfigTemplate: TemplateRef<any>;
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent, protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent); super(store, widgetConfigComponent, fb);
}
protected configForm(): UntypedFormGroup {
return this.barChartWidgetConfigForm;
} }
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { 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' }]; { name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30' }];
} }
protected onConfigSet(configData: WidgetConfigComponentData) { protected defaultSettings() {
const settings: BarChartWidgetSettings = mergeDeep<BarChartWidgetSettings>({} as BarChartWidgetSettings, return barChartWidgetDefaultSettings;
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 prepareOutputConfig(config: any): WidgetConfigComponentData { public latestChartConfigTemplate(): TemplateRef<any> {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); return this.barChartConfigTemplate;
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; protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: BarChartWidgetSettings) {
latestChartWidgetConfigForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
this.widgetConfig.config.units = config.units; latestChartWidgetConfigForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
this.widgetConfig.config.decimals = config.decimals; 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.barSettings = config.barSettings;
this.widgetConfig.config.settings.axisMin = config.axisMin; this.widgetConfig.config.settings.axisMin = config.axisMin;
this.widgetConfig.config.settings.axisMax = config.axisMax; this.widgetConfig.config.settings.axisMax = config.axisMax;
this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont; this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont;
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor; 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { import { DataKey } from '@shared/models/widget.models';
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; 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 { import {
doughnutDefaultSettings, doughnutDefaultSettings,
DoughnutLayout, DoughnutLayout,
doughnutLayoutImages, DoughnutWidgetSettings
doughnutLayouts,
doughnutLayoutTranslations,
DoughnutWidgetSettings,
horizontalDoughnutLayoutImages
} from '@home/components/widget/lib/chart/doughnut-widget.models'; } from '@home/components/widget/lib/chart/doughnut-widget.models';
import { import {
LatestChartTooltipValueType, LatestChartBasicConfigComponent
latestChartTooltipValueTypes, } from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
@Component({ @Component({
selector: 'tb-doughnut-basic-config', selector: 'tb-doughnut-basic-config',
templateUrl: './doughnut-basic-config.component.html', templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss'] styleUrls: ['../basic-config.scss']
}) })
export class DoughnutBasicConfigComponent extends BasicWidgetConfigComponent { export class DoughnutBasicConfigComponent extends LatestChartBasicConfigComponent<DoughnutWidgetSettings> {
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;
valuePreviewFn = this._valuePreviewFn.bind(this); @ViewChild('doughnutChart')
doughnutChartConfigTemplate: TemplateRef<any>;
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
get totalEnabled(): boolean {
const layout: DoughnutLayout = this.doughnutWidgetConfigForm.get('layout').value;
return layout === DoughnutLayout.with_total;
}
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent, protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent); super(store, widgetConfigComponent, fb);
}
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 defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { 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' }]; { name: 'solarPower', label: 'Solar power', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FF4D5A' }];
} }
protected onConfigSet(configData: WidgetConfigComponentData) { protected defaultSettings() {
const settings: DoughnutWidgetSettings = mergeDeep<DoughnutWidgetSettings>({} as DoughnutWidgetSettings, return doughnutDefaultSettings(this.doughnutHorizontal);
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 prepareOutputConfig(config: any): WidgetConfigComponentData { public latestChartConfigTemplate(): TemplateRef<any> {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); return this.doughnutChartConfigTemplate;
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 || {}; 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.layout = config.layout;
this.widgetConfig.config.settings.autoScale = config.autoScale; this.widgetConfig.config.settings.autoScale = config.autoScale;
this.widgetConfig.config.settings.clockwise = config.clockwise; 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.totalValueFont = config.totalValueFont;
this.widgetConfig.config.settings.totalValueColor = config.totalValueColor; 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[] { protected latestChartValidatorTriggers(): string[] {
return ['layout', 'showTitle', 'showTitleIcon', 'showLegend', 'showTooltip']; return ['layout'];
} }
protected updateValidators(emitEvent: boolean, trigger?: string) { protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const layout: DoughnutLayout = this.doughnutWidgetConfigForm.get('layout').value; const layout: DoughnutLayout = latestChartWidgetConfigForm.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;
const totalEnabled = layout === DoughnutLayout.with_total; 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) { if (totalEnabled) {
this.doughnutWidgetConfigForm.get('totalValueFont').enable(); latestChartWidgetConfigForm.get('totalValueFont').enable();
this.doughnutWidgetConfigForm.get('totalValueColor').enable(); latestChartWidgetConfigForm.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);
} else { } else {
const units: string = this.doughnutWidgetConfigForm.get('units').value; latestChartWidgetConfigForm.get('totalValueFont').disable();
return formatValue(110, decimals, units, false); 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { import { DataKey } from '@shared/models/widget.models';
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; 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 { import {
pieChartWidgetDefaultSettings, pieChartWidgetDefaultSettings,
PieChartWidgetSettings PieChartWidgetSettings
} from '@home/components/widget/lib/chart/pie-chart-widget.models'; } from '@home/components/widget/lib/chart/pie-chart-widget.models';
import { import {
pieChartLabelPositions, LatestChartBasicConfigComponent
pieChartLabelPositionTranslations } from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
} from '@home/components/widget/lib/chart/chart.models';
@Component({ @Component({
selector: 'tb-pie-chart-basic-config', selector: 'tb-pie-chart-basic-config',
templateUrl: './pie-chart-basic-config.component.html', templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss'] styleUrls: ['../basic-config.scss']
}) })
export class PieChartBasicConfigComponent extends BasicWidgetConfigComponent { export class PieChartBasicConfigComponent extends LatestChartBasicConfigComponent<PieChartWidgetSettings> {
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;
valuePreviewFn = this._valuePreviewFn.bind(this); @ViewChild('pieChart')
pieChartConfigTemplate: TemplateRef<any>;
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent, protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent); super(store, widgetConfigComponent, fb);
}
protected configForm(): UntypedFormGroup {
return this.pieChartWidgetConfigForm;
} }
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { 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' }]; { name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30' }];
} }
protected onConfigSet(configData: WidgetConfigComponentData) { protected defaultSettings() {
const settings: PieChartWidgetSettings = mergeDeep<PieChartWidgetSettings>({} as PieChartWidgetSettings, return pieChartWidgetDefaultSettings;
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 prepareOutputConfig(config: any): WidgetConfigComponentData { public latestChartConfigTemplate(): TemplateRef<any> {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); return this.pieChartConfigTemplate;
this.widgetConfig.config.datasources = config.datasources; }
this.setSeries(config.series, this.widgetConfig.config.datasources);
this.widgetConfig.config.showTitle = config.showTitle; protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: PieChartWidgetSettings) {
this.widgetConfig.config.title = config.title; latestChartWidgetConfigForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
this.widgetConfig.config.titleFont = config.titleFont; latestChartWidgetConfigForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
this.widgetConfig.config.titleColor = config.titleColor; latestChartWidgetConfigForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
latestChartWidgetConfigForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
this.widgetConfig.config.showTitleIcon = config.showTitleIcon; latestChartWidgetConfigForm.addControl('borderWidth', this.fb.control(settings.borderWidth, []));
this.widgetConfig.config.titleIcon = config.titleIcon; latestChartWidgetConfigForm.addControl('borderColor', this.fb.control(settings.borderColor, []));
this.widgetConfig.config.iconColor = config.iconColor;
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.showLabel = config.showLabel;
this.widgetConfig.config.settings.labelPosition = config.labelPosition; this.widgetConfig.config.settings.labelPosition = config.labelPosition;
this.widgetConfig.config.settings.labelFont = config.labelFont; 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.borderColor = config.borderColor;
this.widgetConfig.config.settings.radius = config.radius; this.widgetConfig.config.settings.radius = config.radius;
this.widgetConfig.config.settings.clockwise = config.clockwise; 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[] { protected latestChartValidatorTriggers(): string[] {
return ['showLabel', 'showTitle', 'showTitleIcon', 'showLegend', 'showTooltip']; return ['showLabel'];
} }
protected updateValidators(emitEvent: boolean, trigger?: string) { protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLabel: boolean = this.pieChartWidgetConfigForm.get('showLabel').value; const showLabel: boolean = latestChartWidgetConfigForm.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;
if (showLabel) { if (showLabel) {
this.pieChartWidgetConfigForm.get('labelPosition').enable(); latestChartWidgetConfigForm.get('labelPosition').enable();
this.pieChartWidgetConfigForm.get('labelFont').enable(); latestChartWidgetConfigForm.get('labelFont').enable();
this.pieChartWidgetConfigForm.get('labelColor').enable(); latestChartWidgetConfigForm.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);
} else { } else {
const units: string = this.pieChartWidgetConfigForm.get('units').value; latestChartWidgetConfigForm.get('labelPosition').disable();
return formatValue(110, decimals, units, false); 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { import { DataKey } from '@shared/models/widget.models';
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; 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 { import {
polarAreaChartWidgetDefaultSettings, polarAreaChartWidgetDefaultSettings,
PolarAreaChartWidgetSettings PolarAreaChartWidgetSettings
} from '@home/components/widget/lib/chart/polar-area-widget.models'; } 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({ @Component({
selector: 'tb-polar-area-chart-basic-config', 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'] styleUrls: ['../basic-config.scss']
}) })
export class PolarAreaChartBasicConfigComponent extends BasicWidgetConfigComponent { export class PolarAreaChartBasicConfigComponent extends LatestChartBasicConfigComponent<PolarAreaChartWidgetSettings> {
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;
valuePreviewFn = this._valuePreviewFn.bind(this); @ViewChild('polarAreaChart')
polarAreaChartConfigTemplate: TemplateRef<any>;
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent, protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent); super(store, widgetConfigComponent, fb);
}
protected configForm(): UntypedFormGroup {
return this.polarAreaChartWidgetConfigForm;
} }
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { 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' }]; { name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30' }];
} }
protected onConfigSet(configData: WidgetConfigComponentData) { protected defaultSettings() {
const settings: PolarAreaChartWidgetSettings = mergeDeep<PolarAreaChartWidgetSettings>({} as PolarAreaChartWidgetSettings, return polarAreaChartWidgetDefaultSettings;
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 prepareOutputConfig(config: any): WidgetConfigComponentData { public latestChartConfigTemplate(): TemplateRef<any> {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); return this.polarAreaChartConfigTemplate;
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; protected setupLatestChartControls(latestChartWidgetConfigForm: UntypedFormGroup, settings: PolarAreaChartWidgetSettings) {
latestChartWidgetConfigForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
this.widgetConfig.config.units = config.units; latestChartWidgetConfigForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
this.widgetConfig.config.decimals = config.decimals; 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.barSettings = config.barSettings;
this.widgetConfig.config.settings.axisMin = config.axisMin; 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.axisTickLabelFont = config.axisTickLabelFont;
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor; this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor;
this.widgetConfig.config.settings.angleAxisStartAngle = config.angleAxisStartAngle; 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { import { DataKey } from '@shared/models/widget.models';
DataKey,
Datasource,
datasourcesHasAggregation,
datasourcesHasOnlyComparisonAggregation,
legendPositions,
legendPositionTranslationMap,
WidgetConfig
} from '@shared/models/widget.models';
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component';
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; 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 { import {
radarChartWidgetDefaultSettings, radarChartWidgetDefaultSettings,
RadarChartWidgetSettings RadarChartWidgetSettings
} from '@home/components/widget/lib/chart/radar-chart-widget.models'; } from '@home/components/widget/lib/chart/radar-chart-widget.models';
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
import { import {
chartLabelPositions, LatestChartBasicConfigComponent
chartLabelPositionTranslations, } from '@home/components/widget/config/basic/chart/latest-chart-basic-config.component';
chartLineTypes,
chartLineTypeTranslations,
chartShapes,
chartShapeTranslations
} from '@home/components/widget/lib/chart/chart.models';
@Component({ @Component({
selector: 'tb-radar-chart-basic-config', selector: 'tb-radar-chart-basic-config',
templateUrl: './radar-chart-basic-config.component.html', templateUrl: './latest-chart-basic-config.component.html',
styleUrls: ['../basic-config.scss'] styleUrls: ['../basic-config.scss']
}) })
export class RadarChartBasicConfigComponent extends BasicWidgetConfigComponent { export class RadarChartBasicConfigComponent extends LatestChartBasicConfigComponent<RadarChartWidgetSettings> {
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;
legendPositions = legendPositions; @ViewChild('radarChart')
radarChartConfigTemplate: TemplateRef<any>;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
radarChartWidgetConfigForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
protected widgetConfigComponent: WidgetConfigComponent, protected widgetConfigComponent: WidgetConfigComponent,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store, widgetConfigComponent); super(store, widgetConfigComponent, fb);
}
protected configForm(): UntypedFormGroup {
return this.radarChartWidgetConfigForm;
} }
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { 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'}]; {name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30'}];
} }
protected onConfigSet(configData: WidgetConfigComponentData) { protected defaultSettings() {
const settings: RadarChartWidgetSettings = mergeDeep<RadarChartWidgetSettings>({} as RadarChartWidgetSettings, return radarChartWidgetDefaultSettings;
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 prepareOutputConfig(config: any): WidgetConfigComponentData { public latestChartConfigTemplate(): TemplateRef<any> {
setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); return this.radarChartConfigTemplate;
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; 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; latestChartWidgetConfigForm.addControl('axisShowLabel', this.fb.control(settings.axisShowLabel, []));
this.widgetConfig.config.decimals = config.decimals; 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.shape = config.shape;
this.widgetConfig.config.settings.color = config.color; this.widgetConfig.config.settings.color = config.color;
this.widgetConfig.config.settings.showLine = config.showLine; 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.axisShowTickLabels = config.axisShowTickLabels;
this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont; this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont;
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor; 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[] { protected latestChartValidatorTriggers(): string[] {
return ['showTitle', 'showTitleIcon', 'showLine', 'showPoints', 'showLabel', 'axisShowLabel', return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel',
'axisShowTickLabels', 'showLegend', 'showTooltip']; 'axisShowTickLabels'];
} }
protected updateValidators(emitEvent: boolean, trigger?: string) { protected updateLatestChartValidators(latestChartWidgetConfigForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showTitle: boolean = this.radarChartWidgetConfigForm.get('showTitle').value; const showLine: boolean = latestChartWidgetConfigForm.get('showLine').value;
const showTitleIcon: boolean = this.radarChartWidgetConfigForm.get('showTitleIcon').value; const showPoints: boolean = latestChartWidgetConfigForm.get('showPoints').value;
const showLine: boolean = this.radarChartWidgetConfigForm.get('showLine').value; const showLabel: boolean = latestChartWidgetConfigForm.get('showLabel').value;
const showPoints: boolean = this.radarChartWidgetConfigForm.get('showPoints').value; const axisShowLabel: boolean = latestChartWidgetConfigForm.get('axisShowLabel').value;
const showLabel: boolean = this.radarChartWidgetConfigForm.get('showLabel').value; const axisShowTickLabels: boolean = latestChartWidgetConfigForm.get('axisShowTickLabels').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();
}
if (showLine) { if (showLine) {
this.radarChartWidgetConfigForm.get('lineType').enable(); latestChartWidgetConfigForm.get('lineType').enable();
this.radarChartWidgetConfigForm.get('lineWidth').enable(); latestChartWidgetConfigForm.get('lineWidth').enable();
} else { } else {
this.radarChartWidgetConfigForm.get('lineType').disable(); latestChartWidgetConfigForm.get('lineType').disable();
this.radarChartWidgetConfigForm.get('lineWidth').disable(); latestChartWidgetConfigForm.get('lineWidth').disable();
} }
if (showPoints) { if (showPoints) {
this.radarChartWidgetConfigForm.get('pointShape').enable(); latestChartWidgetConfigForm.get('pointShape').enable();
this.radarChartWidgetConfigForm.get('pointSize').enable(); latestChartWidgetConfigForm.get('pointSize').enable();
} else { } else {
this.radarChartWidgetConfigForm.get('pointShape').disable(); latestChartWidgetConfigForm.get('pointShape').disable();
this.radarChartWidgetConfigForm.get('pointSize').disable(); latestChartWidgetConfigForm.get('pointSize').disable();
} }
if (showLabel) { if (showLabel) {
this.radarChartWidgetConfigForm.get('labelPosition').enable(); latestChartWidgetConfigForm.get('labelPosition').enable();
this.radarChartWidgetConfigForm.get('labelFont').enable(); latestChartWidgetConfigForm.get('labelFont').enable();
this.radarChartWidgetConfigForm.get('labelColor').enable(); latestChartWidgetConfigForm.get('labelColor').enable();
} else { } else {
this.radarChartWidgetConfigForm.get('labelPosition').disable(); latestChartWidgetConfigForm.get('labelPosition').disable();
this.radarChartWidgetConfigForm.get('labelFont').disable(); latestChartWidgetConfigForm.get('labelFont').disable();
this.radarChartWidgetConfigForm.get('labelColor').disable(); latestChartWidgetConfigForm.get('labelColor').disable();
} }
if (axisShowLabel) { if (axisShowLabel) {
this.radarChartWidgetConfigForm.get('axisLabelFont').enable(); latestChartWidgetConfigForm.get('axisLabelFont').enable();
} else { } else {
this.radarChartWidgetConfigForm.get('axisLabelFont').disable(); latestChartWidgetConfigForm.get('axisLabelFont').disable();
} }
if (axisShowTickLabels) { if (axisShowTickLabels) {
this.radarChartWidgetConfigForm.get('axisTickLabelFont').enable(); latestChartWidgetConfigForm.get('axisTickLabelFont').enable();
this.radarChartWidgetConfigForm.get('axisTickLabelColor').enable(); latestChartWidgetConfigForm.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);
} else { } else {
const units: string = this.radarChartWidgetConfigForm.get('units').value; latestChartWidgetConfigForm.get('axisTickLabelFont').disable();
return formatValue(110, decimals, units, false); 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { import { WidgetSettings } from '@shared/models/widget.models';
legendPositions, import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import { import {
barChartWidgetDefaultSettings, barChartWidgetDefaultSettings,
BarChartWidgetSettings BarChartWidgetSettings
} from '@home/components/widget/lib/chart/bar-chart-widget.models'; } 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({ @Component({
selector: 'tb-bar-chart-widget-settings', selector: 'tb-bar-chart-widget-settings',
templateUrl: './bar-chart-widget-settings.component.html', templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: [] styleUrls: ['./../widget-settings.scss']
}) })
export class BarChartWidgetSettingsComponent extends WidgetSettingsComponent { export class BarChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<BarChartWidgetSettings> {
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
barChartWidgetSettingsForm: UntypedFormGroup; @ViewChild('barChart')
barChartConfigTemplate: TemplateRef<any>;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store); super(store, fb);
}
protected settingsForm(): UntypedFormGroup {
return this.barChartWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<BarChartWidgetSettings>({} as BarChartWidgetSettings, barChartWidgetDefaultSettings);
} }
protected onSettingsSet(settings: WidgetSettings) { protected defaultLatestChartSettings() {
this.barChartWidgetSettingsForm = this.fb.group({ return barChartWidgetDefaultSettings;
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 validatorTriggers(): string[] { public latestChartConfigTemplate(): TemplateRef<any> {
return ['showLegend', 'showTooltip']; return this.barChartConfigTemplate;
} }
protected updateValidators(emitEvent: boolean) { protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
const showLegend: boolean = this.barChartWidgetSettingsForm.get('showLegend').value; latestChartWidgetSettingsForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
const showTooltip: boolean = this.barChartWidgetSettingsForm.get('showTooltip').value; latestChartWidgetSettingsForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
latestChartWidgetSettingsForm.addControl('axisMax', this.fb.control(settings.axisMax, []));
if (showLegend) { latestChartWidgetSettingsForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
this.barChartWidgetSettingsForm.get('legendPosition').enable(); latestChartWidgetSettingsForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
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);
} }
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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { import { WidgetSettings } from '@shared/models/widget.models';
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { formatValue, isDefinedAndNotNull, mergeDeep } from '@core/utils';
import { import {
doughnutDefaultSettings, doughnutDefaultSettings,
DoughnutLayout, DoughnutLayout,
doughnutLayoutImages, DoughnutWidgetSettings
doughnutLayouts,
doughnutLayoutTranslations,
DoughnutWidgetSettings,
horizontalDoughnutLayoutImages
} from '@home/components/widget/lib/chart/doughnut-widget.models'; } from '@home/components/widget/lib/chart/doughnut-widget.models';
import { WidgetConfigComponentData } from '@home/models/widget-component.models';
import { import {
LatestChartTooltipValueType, LatestChartWidgetSettingsComponent
latestChartTooltipValueTypes, } from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
@Component({ @Component({
selector: 'tb-doughnut-widget-settings', selector: 'tb-doughnut-widget-settings',
templateUrl: './doughnut-widget-settings.component.html', templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: [] styleUrls: ['./../widget-settings.scss']
}) })
export class DoughnutWidgetSettingsComponent extends WidgetSettingsComponent { export class DoughnutWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<DoughnutWidgetSettings> {
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;
latestChartTooltipValueTypes = latestChartTooltipValueTypes; @ViewChild('doughnutChart')
doughnutChartConfigTemplate: TemplateRef<any>;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
doughnutWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store); super(store, fb);
} }
protected settingsForm(): UntypedFormGroup { protected defaultLatestChartSettings() {
return this.doughnutWidgetSettingsForm; return doughnutDefaultSettings(this.doughnutHorizontal);
} }
protected onWidgetConfigSet(widgetConfig: WidgetConfigComponentData) { public latestChartConfigTemplate(): TemplateRef<any> {
const params = widgetConfig.typeParameters as any; return this.doughnutChartConfigTemplate;
this.horizontal = isDefinedAndNotNull(params.horizontal) ? params.horizontal : false;
this.doughnutLayoutImageMap = this.horizontal ? horizontalDoughnutLayoutImages : doughnutLayoutImages;
} }
protected defaultSettings(): WidgetSettings { protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
return mergeDeep<DoughnutWidgetSettings>({} as DoughnutWidgetSettings, doughnutDefaultSettings(this.horizontal)); 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) { protected latestChartValidatorTriggers(): string[] {
this.doughnutWidgetSettingsForm = this.fb.group({ return ['layout'];
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 updateValidators(emitEvent: boolean) { protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const layout: DoughnutLayout = this.doughnutWidgetSettingsForm.get('layout').value; const layout: DoughnutLayout = latestChartWidgetSettingsForm.get('layout').value;
const showLegend: boolean = this.doughnutWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.doughnutWidgetSettingsForm.get('showTooltip').value;
const totalEnabled = layout === DoughnutLayout.with_total; 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) { if (totalEnabled) {
this.doughnutWidgetSettingsForm.get('totalValueFont').enable(); latestChartWidgetSettingsForm.get('totalValueFont').enable();
this.doughnutWidgetSettingsForm.get('totalValueColor').enable(); latestChartWidgetSettingsForm.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);
} else { } else {
const units: string = this.widgetConfig.config.units; latestChartWidgetSettingsForm.get('totalValueFont').disable();
return formatValue(110, decimals, units, false); 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { import { WidgetSettings } from '@shared/models/widget.models';
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { formatValue, 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 { import {
pieChartWidgetDefaultSettings, pieChartWidgetDefaultSettings,
PieChartWidgetSettings PieChartWidgetSettings
} from '@home/components/widget/lib/chart/pie-chart-widget.models'; } 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({ @Component({
selector: 'tb-pie-chart-widget-settings', selector: 'tb-pie-chart-widget-settings',
templateUrl: './pie-chart-widget-settings.component.html', templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: [] styleUrls: ['./../widget-settings.scss']
}) })
export class PieChartWidgetSettingsComponent extends WidgetSettingsComponent { export class PieChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<PieChartWidgetSettings> {
pieChartLabelPositions = pieChartLabelPositions;
pieChartLabelPositionTranslationMap = pieChartLabelPositionTranslations;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes; @ViewChild('pieChart')
pieChartConfigTemplate: TemplateRef<any>;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
pieChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store); super(store, fb);
} }
protected settingsForm(): UntypedFormGroup { protected defaultLatestChartSettings() {
return this.pieChartWidgetSettingsForm; return pieChartWidgetDefaultSettings;
} }
protected defaultSettings(): WidgetSettings { public latestChartConfigTemplate(): TemplateRef<any> {
return mergeDeep<PieChartWidgetSettings>({} as PieChartWidgetSettings, pieChartWidgetDefaultSettings); return this.pieChartConfigTemplate;
} }
protected onSettingsSet(settings: WidgetSettings) { protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
this.pieChartWidgetSettingsForm = this.fb.group({ latestChartWidgetSettingsForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
showLabel: [settings.showLabel, []], latestChartWidgetSettingsForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
labelPosition: [settings.labelPosition, []], latestChartWidgetSettingsForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
labelFont: [settings.labelFont, []], latestChartWidgetSettingsForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
labelColor: [settings.labelColor, []], latestChartWidgetSettingsForm.addControl('borderWidth', this.fb.control(settings.borderWidth, [Validators.min(0)]));
latestChartWidgetSettingsForm.addControl('borderColor', this.fb.control(settings.borderColor, []));
borderWidth: [settings.borderWidth, [Validators.min(0)]], latestChartWidgetSettingsForm.addControl('radius', this.fb.control(settings.radius, []));
borderColor: [settings.borderColor, []], latestChartWidgetSettingsForm.addControl('clockwise', this.fb.control(settings.clockwise, []));
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 validatorTriggers(): string[] { protected latestChartValidatorTriggers(): string[] {
return ['showLabel', 'showLegend', 'showTooltip']; return ['showLabel'];
} }
protected updateValidators(emitEvent: boolean) { protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLabel: boolean = this.pieChartWidgetSettingsForm.get('showLabel').value; const showLabel: boolean = latestChartWidgetSettingsForm.get('showLabel').value;
const showLegend: boolean = this.pieChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.pieChartWidgetSettingsForm.get('showTooltip').value;
if (showLabel) { if (showLabel) {
this.pieChartWidgetSettingsForm.get('labelPosition').enable(); latestChartWidgetSettingsForm.get('labelPosition').enable();
this.pieChartWidgetSettingsForm.get('labelFont').enable(); latestChartWidgetSettingsForm.get('labelFont').enable();
this.pieChartWidgetSettingsForm.get('labelColor').enable(); latestChartWidgetSettingsForm.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);
} else { } else {
const units: string = this.widgetConfig.config.units; latestChartWidgetSettingsForm.get('labelPosition').disable();
return formatValue(110, decimals, units, false); 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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { import { WidgetSettings } from '@shared/models/widget.models';
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import { import {
polarAreaChartWidgetDefaultSettings, polarAreaChartWidgetDefaultSettings,
PolarAreaChartWidgetSettings PolarAreaChartWidgetSettings
} from '@home/components/widget/lib/chart/polar-area-widget.models'; } 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({ @Component({
selector: 'tb-polar-area-chart-widget-settings', selector: 'tb-polar-area-chart-widget-settings',
templateUrl: './polar-area-chart-widget-settings.component.html', templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: [] styleUrls: ['./../widget-settings.scss']
}) })
export class PolarAreaChartWidgetSettingsComponent extends WidgetSettingsComponent { export class PolarAreaChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<PolarAreaChartWidgetSettings> {
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
polarAreaChartWidgetSettingsForm: UntypedFormGroup; @ViewChild('polarAreaChart')
polarAreaChartConfigTemplate: TemplateRef<any>;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store); super(store, fb);
}
protected settingsForm(): UntypedFormGroup {
return this.polarAreaChartWidgetSettingsForm;
}
protected defaultSettings(): WidgetSettings {
return mergeDeep<PolarAreaChartWidgetSettings>({} as PolarAreaChartWidgetSettings, polarAreaChartWidgetDefaultSettings);
} }
protected onSettingsSet(settings: WidgetSettings) { protected defaultLatestChartSettings() {
this.polarAreaChartWidgetSettingsForm = this.fb.group({ return polarAreaChartWidgetDefaultSettings;
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 validatorTriggers(): string[] { public latestChartConfigTemplate(): TemplateRef<any> {
return ['showLegend', 'showTooltip']; return this.polarAreaChartConfigTemplate;
} }
protected updateValidators(emitEvent: boolean) { protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
const showLegend: boolean = this.polarAreaChartWidgetSettingsForm.get('showLegend').value; latestChartWidgetSettingsForm.addControl('barSettings', this.fb.control(settings.barSettings, []));
const showTooltip: boolean = this.polarAreaChartWidgetSettingsForm.get('showTooltip').value; latestChartWidgetSettingsForm.addControl('axisMin', this.fb.control(settings.axisMin, []));
latestChartWidgetSettingsForm.addControl('axisMax', this.fb.control(settings.axisMax, []));
if (showLegend) { latestChartWidgetSettingsForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
this.polarAreaChartWidgetSettingsForm.get('legendPosition').enable(); latestChartWidgetSettingsForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, [Validators.min(0)]));
this.polarAreaChartWidgetSettingsForm.get('legendLabelFont').enable(); latestChartWidgetSettingsForm.addControl('angleAxisStartAngle', this.fb.control(settings.angleAxisStartAngle, []));
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);
} }
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. /// limitations under the License.
/// ///
import { Component } from '@angular/core'; import { Component, TemplateRef, ViewChild } from '@angular/core';
import { import { WidgetSettings } from '@shared/models/widget.models';
legendPositions,
legendPositionTranslationMap,
WidgetSettings,
WidgetSettingsComponent
} from '@shared/models/widget.models';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Store } from '@ngrx/store'; import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state'; import { AppState } from '@core/core.state';
import { formatValue, mergeDeep } from '@core/utils';
import {
LatestChartTooltipValueType,
latestChartTooltipValueTypes,
latestChartTooltipValueTypeTranslations
} from '@home/components/widget/lib/chart/latest-chart.models';
import { import {
radarChartWidgetDefaultSettings, radarChartWidgetDefaultSettings,
RadarChartWidgetSettings RadarChartWidgetSettings
} from '@home/components/widget/lib/chart/radar-chart-widget.models'; } from '@home/components/widget/lib/chart/radar-chart-widget.models';
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models';
import { import {
chartLabelPositions, LatestChartWidgetSettingsComponent
chartLabelPositionTranslations, } from '@home/components/widget/lib/settings/chart/latest-chart-widget-settings.component';
chartLineTypes,
chartLineTypeTranslations,
chartShapes,
chartShapeTranslations
} from '@home/components/widget/lib/chart/chart.models';
@Component({ @Component({
selector: 'tb-radar-chart-widget-settings', selector: 'tb-radar-chart-widget-settings',
templateUrl: './radar-chart-widget-settings.component.html', templateUrl: './latest-chart-widget-settings.component.html',
styleUrls: [] styleUrls: ['./../widget-settings.scss']
}) })
export class RadarChartWidgetSettingsComponent extends WidgetSettingsComponent { export class RadarChartWidgetSettingsComponent extends LatestChartWidgetSettingsComponent<RadarChartWidgetSettings> {
radarChartShapes = radarChartShapes;
radarChartShapeTranslations = radarChartShapeTranslations;
chartLineTypes = chartLineTypes;
chartLineTypeTranslations = chartLineTypeTranslations;
chartShapes = chartShapes;
chartShapeTranslations = chartShapeTranslations;
chartLabelPositions = chartLabelPositions;
chartLabelPositionTranslations = chartLabelPositionTranslations; @ViewChild('radarChart')
radarChartConfigTemplate: TemplateRef<any>;
legendPositions = legendPositions;
legendPositionTranslationMap = legendPositionTranslationMap;
latestChartTooltipValueTypes = latestChartTooltipValueTypes;
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations;
radarChartWidgetSettingsForm: UntypedFormGroup;
valuePreviewFn = this._valuePreviewFn.bind(this);
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this);
constructor(protected store: Store<AppState>, constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder) { protected fb: UntypedFormBuilder) {
super(store); super(store, fb);
} }
protected settingsForm(): UntypedFormGroup { protected defaultLatestChartSettings() {
return this.radarChartWidgetSettingsForm; return radarChartWidgetDefaultSettings;
} }
protected defaultSettings(): WidgetSettings { public latestChartConfigTemplate(): TemplateRef<any> {
return mergeDeep<RadarChartWidgetSettings>({} as RadarChartWidgetSettings, radarChartWidgetDefaultSettings); return this.radarChartConfigTemplate;
} }
protected onSettingsSet(settings: WidgetSettings) { protected setupLatestChartControls(latestChartWidgetSettingsForm: UntypedFormGroup, settings: WidgetSettings) {
this.radarChartWidgetSettingsForm = this.fb.group({ latestChartWidgetSettingsForm.addControl('shape', this.fb.control(settings.shape, []));
latestChartWidgetSettingsForm.addControl('color', this.fb.control(settings.color, []));
sortSeries: [settings.sortSeries, []], latestChartWidgetSettingsForm.addControl('showLine', this.fb.control(settings.showLine, []));
latestChartWidgetSettingsForm.addControl('lineType', this.fb.control(settings.lineType, []));
shape: [settings.shape, []], latestChartWidgetSettingsForm.addControl('lineWidth', this.fb.control(settings.lineWidth, [Validators.min(0)]));
color: [settings.color, []], latestChartWidgetSettingsForm.addControl('showPoints', this.fb.control(settings.showPoints, []));
showLine: [settings.showLine, []], latestChartWidgetSettingsForm.addControl('pointShape', this.fb.control(settings.pointShape, []));
lineType: [settings.lineType, []], latestChartWidgetSettingsForm.addControl('pointSize', this.fb.control(settings.pointSize, [Validators.min(0)]));
lineWidth: [settings.lineWidth, [Validators.min(0)]], latestChartWidgetSettingsForm.addControl('showLabel', this.fb.control(settings.showLabel, []));
showPoints: [settings.showPoints, []], latestChartWidgetSettingsForm.addControl('labelPosition', this.fb.control(settings.labelPosition, []));
pointShape: [settings.pointShape, []], latestChartWidgetSettingsForm.addControl('labelFont', this.fb.control(settings.labelFont, []));
pointSize: [settings.pointSize, [Validators.min(0)]], latestChartWidgetSettingsForm.addControl('labelColor', this.fb.control(settings.labelColor, []));
showLabel: [settings.showLabel, []], latestChartWidgetSettingsForm.addControl('fillAreaSettings', this.fb.control(settings.fillAreaSettings, []));
labelPosition: [settings.labelPosition, []],
labelFont: [settings.labelFont, []], latestChartWidgetSettingsForm.addControl('axisShowLabel', this.fb.control(settings.axisShowLabel, []));
labelColor: [settings.labelColor, []], latestChartWidgetSettingsForm.addControl('axisLabelFont', this.fb.control(settings.axisLabelFont, []));
fillAreaSettings: [settings.fillAreaSettings, []], latestChartWidgetSettingsForm.addControl('axisShowTickLabels', this.fb.control(settings.axisShowTickLabels, []));
latestChartWidgetSettingsForm.addControl('axisTickLabelFont', this.fb.control(settings.axisTickLabelFont, []));
axisShowLabel: [settings.axisShowLabel, []], latestChartWidgetSettingsForm.addControl('axisTickLabelColor', this.fb.control(settings.axisTickLabelColor, []));
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 validatorTriggers(): string[] { protected latestChartValidatorTriggers(): string[] {
return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel', return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel', 'axisShowTickLabels'];
'axisShowTickLabels', 'showLegend', 'showTooltip'];
} }
protected updateValidators(emitEvent: boolean) { protected updateLatestChartValidators(latestChartWidgetSettingsForm: UntypedFormGroup, emitEvent: boolean, trigger?: string) {
const showLine: boolean = this.radarChartWidgetSettingsForm.get('showLine').value; const showLine: boolean = latestChartWidgetSettingsForm.get('showLine').value;
const showPoints: boolean = this.radarChartWidgetSettingsForm.get('showPoints').value; const showPoints: boolean = latestChartWidgetSettingsForm.get('showPoints').value;
const showLabel: boolean = this.radarChartWidgetSettingsForm.get('showLabel').value; const showLabel: boolean = latestChartWidgetSettingsForm.get('showLabel').value;
const axisShowLabel: boolean = this.radarChartWidgetSettingsForm.get('axisShowLabel').value; const axisShowLabel: boolean = latestChartWidgetSettingsForm.get('axisShowLabel').value;
const axisShowTickLabels: boolean = this.radarChartWidgetSettingsForm.get('axisShowTickLabels').value; const axisShowTickLabels: boolean = latestChartWidgetSettingsForm.get('axisShowTickLabels').value;
const showLegend: boolean = this.radarChartWidgetSettingsForm.get('showLegend').value;
const showTooltip: boolean = this.radarChartWidgetSettingsForm.get('showTooltip').value;
if (showLine) { if (showLine) {
this.radarChartWidgetSettingsForm.get('lineType').enable(); latestChartWidgetSettingsForm.get('lineType').enable();
this.radarChartWidgetSettingsForm.get('lineWidth').enable(); latestChartWidgetSettingsForm.get('lineWidth').enable();
} else { } else {
this.radarChartWidgetSettingsForm.get('lineType').disable(); latestChartWidgetSettingsForm.get('lineType').disable();
this.radarChartWidgetSettingsForm.get('lineWidth').disable(); latestChartWidgetSettingsForm.get('lineWidth').disable();
} }
if (showPoints) { if (showPoints) {
this.radarChartWidgetSettingsForm.get('pointShape').enable(); latestChartWidgetSettingsForm.get('pointShape').enable();
this.radarChartWidgetSettingsForm.get('pointSize').enable(); latestChartWidgetSettingsForm.get('pointSize').enable();
} else { } else {
this.radarChartWidgetSettingsForm.get('pointShape').disable(); latestChartWidgetSettingsForm.get('pointShape').disable();
this.radarChartWidgetSettingsForm.get('pointSize').disable(); latestChartWidgetSettingsForm.get('pointSize').disable();
} }
if (showLabel) { if (showLabel) {
this.radarChartWidgetSettingsForm.get('labelPosition').enable(); latestChartWidgetSettingsForm.get('labelPosition').enable();
this.radarChartWidgetSettingsForm.get('labelFont').enable(); latestChartWidgetSettingsForm.get('labelFont').enable();
this.radarChartWidgetSettingsForm.get('labelColor').enable(); latestChartWidgetSettingsForm.get('labelColor').enable();
} else { } else {
this.radarChartWidgetSettingsForm.get('labelPosition').disable(); latestChartWidgetSettingsForm.get('labelPosition').disable();
this.radarChartWidgetSettingsForm.get('labelFont').disable(); latestChartWidgetSettingsForm.get('labelFont').disable();
this.radarChartWidgetSettingsForm.get('labelColor').disable(); latestChartWidgetSettingsForm.get('labelColor').disable();
} }
if (axisShowLabel) { if (axisShowLabel) {
this.radarChartWidgetSettingsForm.get('axisLabelFont').enable(); latestChartWidgetSettingsForm.get('axisLabelFont').enable();
} else { } else {
this.radarChartWidgetSettingsForm.get('axisLabelFont').disable(); latestChartWidgetSettingsForm.get('axisLabelFont').disable();
} }
if (axisShowTickLabels) { if (axisShowTickLabels) {
this.radarChartWidgetSettingsForm.get('axisTickLabelFont').enable(); latestChartWidgetSettingsForm.get('axisTickLabelFont').enable();
this.radarChartWidgetSettingsForm.get('axisTickLabelColor').enable(); latestChartWidgetSettingsForm.get('axisTickLabelColor').enable();
} else { } else {
this.radarChartWidgetSettingsForm.get('axisTickLabelFont').disable(); latestChartWidgetSettingsForm.get('axisTickLabelFont').disable();
this.radarChartWidgetSettingsForm.get('axisTickLabelColor').disable(); latestChartWidgetSettingsForm.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);
} }
} }
} }

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

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

Loading…
Cancel
Save