32 changed files with 2035 additions and 143 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,340 @@ |
|||
<!-- |
|||
|
|||
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> |
|||
@ -0,0 +1,414 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; |
|||
import { WidgetConfigComponentData } from '@home/models/widget-component.models'; |
|||
import { |
|||
DataKey, |
|||
Datasource, |
|||
datasourcesHasAggregation, |
|||
datasourcesHasOnlyComparisonAggregation, |
|||
legendPositions, |
|||
legendPositionTranslationMap, |
|||
WidgetConfig |
|||
} from '@shared/models/widget.models'; |
|||
import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; |
|||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; |
|||
import { formatValue, isUndefined, mergeDeep } from '@core/utils'; |
|||
import { |
|||
getTimewindowConfig, |
|||
setTimewindowConfig |
|||
} from '@home/components/widget/config/timewindow-config-panel.component'; |
|||
import { |
|||
LatestChartTooltipValueType, |
|||
latestChartTooltipValueTypes, |
|||
latestChartTooltipValueTypeTranslations |
|||
} from '@home/components/widget/lib/chart/latest-chart.models'; |
|||
import { |
|||
radarChartWidgetDefaultSettings, |
|||
RadarChartWidgetSettings |
|||
} from '@home/components/widget/lib/chart/radar-chart-widget.models'; |
|||
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models'; |
|||
import { |
|||
chartLabelPositions, |
|||
chartLabelPositionTranslations, |
|||
chartLineTypes, |
|||
chartLineTypeTranslations, |
|||
chartShapes, |
|||
chartShapeTranslations |
|||
} from '@home/components/widget/lib/chart/chart.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-radar-chart-basic-config', |
|||
templateUrl: './radar-chart-basic-config.component.html', |
|||
styleUrls: ['../basic-config.scss'] |
|||
}) |
|||
export class RadarChartBasicConfigComponent extends BasicWidgetConfigComponent { |
|||
|
|||
public get datasource(): Datasource { |
|||
const datasources: Datasource[] = this.radarChartWidgetConfigForm.get('datasources').value; |
|||
if (datasources && datasources.length) { |
|||
return datasources[0]; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
public get displayTimewindowConfig(): boolean { |
|||
const datasources = this.radarChartWidgetConfigForm.get('datasources').value; |
|||
return datasourcesHasAggregation(datasources); |
|||
} |
|||
|
|||
public onlyHistoryTimewindow(): boolean { |
|||
const datasources = this.radarChartWidgetConfigForm.get('datasources').value; |
|||
return datasourcesHasOnlyComparisonAggregation(datasources); |
|||
} |
|||
|
|||
radarChartShapes = radarChartShapes; |
|||
|
|||
radarChartShapeTranslations = radarChartShapeTranslations; |
|||
|
|||
chartLineTypes = chartLineTypes; |
|||
|
|||
chartLineTypeTranslations = chartLineTypeTranslations; |
|||
|
|||
chartShapes = chartShapes; |
|||
|
|||
chartShapeTranslations = chartShapeTranslations; |
|||
|
|||
chartLabelPositions = chartLabelPositions; |
|||
|
|||
chartLabelPositionTranslations = chartLabelPositionTranslations; |
|||
|
|||
legendPositions = legendPositions; |
|||
|
|||
legendPositionTranslationMap = legendPositionTranslationMap; |
|||
|
|||
latestChartTooltipValueTypes = latestChartTooltipValueTypes; |
|||
|
|||
latestChartTooltipValueTypeTranslationMap = latestChartTooltipValueTypeTranslations; |
|||
|
|||
radarChartWidgetConfigForm: UntypedFormGroup; |
|||
|
|||
valuePreviewFn = this._valuePreviewFn.bind(this); |
|||
|
|||
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); |
|||
|
|||
constructor(protected store: Store<AppState>, |
|||
protected widgetConfigComponent: WidgetConfigComponent, |
|||
private fb: UntypedFormBuilder) { |
|||
super(store, widgetConfigComponent); |
|||
} |
|||
|
|||
protected configForm(): UntypedFormGroup { |
|||
return this.radarChartWidgetConfigForm; |
|||
} |
|||
|
|||
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { |
|||
return [{name: 'windPower', label: 'Wind', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#08872B'}, |
|||
{name: 'solarPower', label: 'Solar', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FF4D5A'}, |
|||
{name: 'hydroelectricPower', label: 'Hydroelectric', type: DataKeyType.timeseries, units: '', decimals: 0, color: '#FFDE30'}]; |
|||
} |
|||
|
|||
protected onConfigSet(configData: WidgetConfigComponentData) { |
|||
const settings: RadarChartWidgetSettings = mergeDeep<RadarChartWidgetSettings>({} as RadarChartWidgetSettings, |
|||
radarChartWidgetDefaultSettings, configData.config.settings as RadarChartWidgetSettings); |
|||
this.radarChartWidgetConfigForm = this.fb.group({ |
|||
timewindowConfig: [getTimewindowConfig(configData.config), []], |
|||
datasources: [configData.config.datasources, []], |
|||
|
|||
series: [this.getSeries(configData.config.datasources), []], |
|||
|
|||
showTitle: [configData.config.showTitle, []], |
|||
title: [configData.config.title, []], |
|||
titleFont: [configData.config.titleFont, []], |
|||
titleColor: [configData.config.titleColor, []], |
|||
showTitleIcon: [configData.config.showTitleIcon, []], |
|||
titleIcon: [configData.config.titleIcon, []], |
|||
iconColor: [configData.config.iconColor, []], |
|||
|
|||
sortSeries: [settings.sortSeries, []], |
|||
|
|||
units: [configData.config.units, []], |
|||
decimals: [configData.config.decimals, []], |
|||
|
|||
shape: [settings.shape, []], |
|||
color: [settings.color, []], |
|||
showLine: [settings.showLine, []], |
|||
lineType: [settings.lineType, []], |
|||
lineWidth: [settings.lineWidth, [Validators.min(0)]], |
|||
showPoints: [settings.showPoints, []], |
|||
pointShape: [settings.pointShape, []], |
|||
pointSize: [settings.pointSize, [Validators.min(0)]], |
|||
showLabel: [settings.showLabel, []], |
|||
labelPosition: [settings.labelPosition, []], |
|||
labelFont: [settings.labelFont, []], |
|||
labelColor: [settings.labelColor, []], |
|||
fillAreaSettings: [settings.fillAreaSettings, []], |
|||
|
|||
axisShowLabel: [settings.axisShowLabel, []], |
|||
axisLabelFont: [settings.axisLabelFont, []], |
|||
axisShowTickLabels: [settings.axisShowTickLabels, []], |
|||
axisTickLabelFont: [settings.axisTickLabelFont, []], |
|||
axisTickLabelColor: [settings.axisTickLabelColor, []], |
|||
|
|||
animation: [settings.animation, []], |
|||
|
|||
showLegend: [settings.showLegend, []], |
|||
legendPosition: [settings.legendPosition, []], |
|||
legendLabelFont: [settings.legendLabelFont, []], |
|||
legendLabelColor: [settings.legendLabelColor, []], |
|||
legendValueFont: [settings.legendValueFont, []], |
|||
legendValueColor: [settings.legendValueColor, []], |
|||
|
|||
showTooltip: [settings.showTooltip, []], |
|||
tooltipValueType: [settings.tooltipValueType, []], |
|||
tooltipValueDecimals: [settings.tooltipValueDecimals, []], |
|||
tooltipValueFont: [settings.tooltipValueFont, []], |
|||
tooltipValueColor: [settings.tooltipValueColor, []], |
|||
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], |
|||
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], |
|||
|
|||
background: [settings.background, []], |
|||
|
|||
cardButtons: [this.getCardButtons(configData.config), []], |
|||
borderRadius: [configData.config.borderRadius, []], |
|||
|
|||
actions: [configData.config.actions || {}, []] |
|||
}); |
|||
} |
|||
|
|||
protected 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.shape = config.shape; |
|||
this.widgetConfig.config.settings.color = config.color; |
|||
this.widgetConfig.config.settings.showLine = config.showLine; |
|||
this.widgetConfig.config.settings.lineType = config.lineType; |
|||
this.widgetConfig.config.settings.lineWidth = config.lineWidth; |
|||
this.widgetConfig.config.settings.showPoints = config.showPoints; |
|||
this.widgetConfig.config.settings.pointShape = config.pointShape; |
|||
this.widgetConfig.config.settings.pointSize = config.pointSize; |
|||
this.widgetConfig.config.settings.showLabel = config.showLabel; |
|||
this.widgetConfig.config.settings.labelPosition = config.labelPosition; |
|||
this.widgetConfig.config.settings.labelFont = config.labelFont; |
|||
this.widgetConfig.config.settings.labelColor = config.labelColor; |
|||
this.widgetConfig.config.settings.fillAreaSettings = config.fillAreaSettings; |
|||
|
|||
this.widgetConfig.config.settings.axisShowLabel = config.axisShowLabel; |
|||
this.widgetConfig.config.settings.axisLabelFont = config.axisLabelFont; |
|||
this.widgetConfig.config.settings.axisShowTickLabels = config.axisShowTickLabels; |
|||
this.widgetConfig.config.settings.axisTickLabelFont = config.axisTickLabelFont; |
|||
this.widgetConfig.config.settings.axisTickLabelColor = config.axisTickLabelColor; |
|||
|
|||
this.widgetConfig.config.settings.animation = config.animation; |
|||
|
|||
this.widgetConfig.config.settings.showLegend = config.showLegend; |
|||
this.widgetConfig.config.settings.legendPosition = config.legendPosition; |
|||
this.widgetConfig.config.settings.legendLabelFont = config.legendLabelFont; |
|||
this.widgetConfig.config.settings.legendLabelColor = config.legendLabelColor; |
|||
this.widgetConfig.config.settings.legendValueFont = config.legendValueFont; |
|||
this.widgetConfig.config.settings.legendValueColor = config.legendValueColor; |
|||
|
|||
this.widgetConfig.config.settings.showTooltip = config.showTooltip; |
|||
this.widgetConfig.config.settings.tooltipValueType = config.tooltipValueType; |
|||
this.widgetConfig.config.settings.tooltipValueDecimals = config.tooltipValueDecimals; |
|||
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont; |
|||
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor; |
|||
this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor; |
|||
this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur; |
|||
|
|||
this.widgetConfig.config.settings.background = config.background; |
|||
|
|||
this.setCardButtons(config.cardButtons, this.widgetConfig.config); |
|||
this.widgetConfig.config.borderRadius = config.borderRadius; |
|||
|
|||
this.widgetConfig.config.actions = config.actions; |
|||
|
|||
return this.widgetConfig; |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['showTitle', 'showTitleIcon', 'showLine', 'showPoints', 'showLabel', 'axisShowLabel', |
|||
'axisShowTickLabels', 'showLegend', 'showTooltip']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean, trigger?: string) { |
|||
const showTitle: boolean = this.radarChartWidgetConfigForm.get('showTitle').value; |
|||
const showTitleIcon: boolean = this.radarChartWidgetConfigForm.get('showTitleIcon').value; |
|||
const showLine: boolean = this.radarChartWidgetConfigForm.get('showLine').value; |
|||
const showPoints: boolean = this.radarChartWidgetConfigForm.get('showPoints').value; |
|||
const showLabel: boolean = this.radarChartWidgetConfigForm.get('showLabel').value; |
|||
const axisShowLabel: boolean = this.radarChartWidgetConfigForm.get('axisShowLabel').value; |
|||
const axisShowTickLabels: boolean = this.radarChartWidgetConfigForm.get('axisShowTickLabels').value; |
|||
const showLegend: boolean = this.radarChartWidgetConfigForm.get('showLegend').value; |
|||
const showTooltip: boolean = this.radarChartWidgetConfigForm.get('showTooltip').value; |
|||
|
|||
if (showTitle) { |
|||
this.radarChartWidgetConfigForm.get('title').enable(); |
|||
this.radarChartWidgetConfigForm.get('titleFont').enable(); |
|||
this.radarChartWidgetConfigForm.get('titleColor').enable(); |
|||
this.radarChartWidgetConfigForm.get('showTitleIcon').enable({emitEvent: false}); |
|||
if (showTitleIcon) { |
|||
this.radarChartWidgetConfigForm.get('titleIcon').enable(); |
|||
this.radarChartWidgetConfigForm.get('iconColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('titleIcon').disable(); |
|||
this.radarChartWidgetConfigForm.get('iconColor').disable(); |
|||
} |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('title').disable(); |
|||
this.radarChartWidgetConfigForm.get('titleFont').disable(); |
|||
this.radarChartWidgetConfigForm.get('titleColor').disable(); |
|||
this.radarChartWidgetConfigForm.get('showTitleIcon').disable({emitEvent: false}); |
|||
this.radarChartWidgetConfigForm.get('titleIcon').disable(); |
|||
this.radarChartWidgetConfigForm.get('iconColor').disable(); |
|||
} |
|||
|
|||
if (showLine) { |
|||
this.radarChartWidgetConfigForm.get('lineType').enable(); |
|||
this.radarChartWidgetConfigForm.get('lineWidth').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('lineType').disable(); |
|||
this.radarChartWidgetConfigForm.get('lineWidth').disable(); |
|||
} |
|||
|
|||
if (showPoints) { |
|||
this.radarChartWidgetConfigForm.get('pointShape').enable(); |
|||
this.radarChartWidgetConfigForm.get('pointSize').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('pointShape').disable(); |
|||
this.radarChartWidgetConfigForm.get('pointSize').disable(); |
|||
} |
|||
|
|||
if (showLabel) { |
|||
this.radarChartWidgetConfigForm.get('labelPosition').enable(); |
|||
this.radarChartWidgetConfigForm.get('labelFont').enable(); |
|||
this.radarChartWidgetConfigForm.get('labelColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('labelPosition').disable(); |
|||
this.radarChartWidgetConfigForm.get('labelFont').disable(); |
|||
this.radarChartWidgetConfigForm.get('labelColor').disable(); |
|||
} |
|||
|
|||
if (axisShowLabel) { |
|||
this.radarChartWidgetConfigForm.get('axisLabelFont').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('axisLabelFont').disable(); |
|||
} |
|||
|
|||
if (axisShowTickLabels) { |
|||
this.radarChartWidgetConfigForm.get('axisTickLabelFont').enable(); |
|||
this.radarChartWidgetConfigForm.get('axisTickLabelColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('axisTickLabelFont').disable(); |
|||
this.radarChartWidgetConfigForm.get('axisTickLabelColor').disable(); |
|||
} |
|||
|
|||
if (showLegend) { |
|||
this.radarChartWidgetConfigForm.get('legendPosition').enable(); |
|||
this.radarChartWidgetConfigForm.get('legendLabelFont').enable(); |
|||
this.radarChartWidgetConfigForm.get('legendLabelColor').enable(); |
|||
this.radarChartWidgetConfigForm.get('legendValueFont').enable(); |
|||
this.radarChartWidgetConfigForm.get('legendValueColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('legendPosition').disable(); |
|||
this.radarChartWidgetConfigForm.get('legendLabelFont').disable(); |
|||
this.radarChartWidgetConfigForm.get('legendLabelColor').disable(); |
|||
this.radarChartWidgetConfigForm.get('legendValueFont').disable(); |
|||
this.radarChartWidgetConfigForm.get('legendValueColor').disable(); |
|||
} |
|||
if (showTooltip) { |
|||
this.radarChartWidgetConfigForm.get('tooltipValueType').enable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipValueDecimals').enable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipValueFont').enable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipValueColor').enable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipBackgroundColor').enable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipBackgroundBlur').enable(); |
|||
} else { |
|||
this.radarChartWidgetConfigForm.get('tooltipValueType').disable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipValueDecimals').disable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipValueFont').disable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipValueColor').disable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipBackgroundColor').disable(); |
|||
this.radarChartWidgetConfigForm.get('tooltipBackgroundBlur').disable(); |
|||
} |
|||
} |
|||
|
|||
private getSeries(datasources?: Datasource[]): DataKey[] { |
|||
if (datasources && datasources.length) { |
|||
return datasources[0].dataKeys || []; |
|||
} |
|||
return []; |
|||
} |
|||
|
|||
private setSeries(series: DataKey[], datasources?: Datasource[]) { |
|||
if (datasources && datasources.length) { |
|||
datasources[0].dataKeys = series; |
|||
} |
|||
} |
|||
|
|||
private getCardButtons(config: WidgetConfig): string[] { |
|||
const buttons: string[] = []; |
|||
if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { |
|||
buttons.push('fullscreen'); |
|||
} |
|||
return buttons; |
|||
} |
|||
|
|||
private setCardButtons(buttons: string[], config: WidgetConfig) { |
|||
config.enableFullscreen = buttons.includes('fullscreen'); |
|||
} |
|||
|
|||
private _valuePreviewFn(): string { |
|||
const units: string = this.radarChartWidgetConfigForm.get('units').value; |
|||
const decimals: number = this.radarChartWidgetConfigForm.get('decimals').value; |
|||
return formatValue(110, decimals, units, false); |
|||
} |
|||
|
|||
private _tooltipValuePreviewFn(): string { |
|||
const tooltipValueType: LatestChartTooltipValueType = this.radarChartWidgetConfigForm.get('tooltipValueType').value; |
|||
const decimals: number = this.radarChartWidgetConfigForm.get('tooltipValueDecimals').value; |
|||
if (tooltipValueType === LatestChartTooltipValueType.percentage) { |
|||
return formatValue(35, decimals, '%', false); |
|||
} else { |
|||
const units: string = this.radarChartWidgetConfigForm.get('units').value; |
|||
return formatValue(110, decimals, units, false); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component, Input, OnInit, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core'; |
|||
import { WidgetContext } from '@home/models/widget-component.models'; |
|||
import { WidgetComponent } from '@home/components/widget/widget.component'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { |
|||
LatestChartComponent, |
|||
LatestChartComponentCallbacks |
|||
} from '@home/components/widget/lib/chart/latest-chart.component'; |
|||
import { |
|||
radarChartWidgetDefaultSettings, |
|||
radarChartWidgetRadarChartSettings, |
|||
RadarChartWidgetSettings |
|||
} from '@home/components/widget/lib/chart/radar-chart-widget.models'; |
|||
import { TbRadarChart } from '@home/components/widget/lib/chart/radar-chart'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-radar-chart-widget', |
|||
templateUrl: './latest-chart-widget.component.html', |
|||
styleUrls: [], |
|||
encapsulation: ViewEncapsulation.None |
|||
}) |
|||
export class RadarChartWidgetComponent implements OnInit { |
|||
|
|||
@ViewChild('latestChart') |
|||
latestChart: LatestChartComponent; |
|||
|
|||
@Input() |
|||
ctx: WidgetContext; |
|||
|
|||
@Input() |
|||
widgetTitlePanel: TemplateRef<any>; |
|||
|
|||
settings: RadarChartWidgetSettings; |
|||
|
|||
callbacks: LatestChartComponentCallbacks; |
|||
|
|||
constructor(private widgetComponent: WidgetComponent, |
|||
private translate: TranslateService) { |
|||
} |
|||
|
|||
ngOnInit(): void { |
|||
this.ctx.$scope.radarChartWidget = this; |
|||
this.settings = {...radarChartWidgetDefaultSettings, ...this.ctx.settings}; |
|||
this.callbacks = { |
|||
createChart: (chartShape, renderer) => { |
|||
const settings = radarChartWidgetRadarChartSettings(this.settings); |
|||
return new TbRadarChart(this.ctx, settings, chartShape.nativeElement, renderer, this.translate, true); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
public onInit() { |
|||
this.latestChart?.onInit(); |
|||
} |
|||
|
|||
public onDataUpdated() { |
|||
this.latestChart?.onDataUpdated(); |
|||
} |
|||
} |
|||
@ -0,0 +1,142 @@ |
|||
///
|
|||
/// 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 { |
|||
latestChartWidgetDefaultSettings, |
|||
LatestChartWidgetSettings |
|||
} from '@home/components/widget/lib/chart/latest-chart.models'; |
|||
import { |
|||
ChartAnimationSettings, |
|||
chartColorScheme, |
|||
ChartFillSettings, |
|||
ChartFillType, |
|||
ChartLabelPosition, |
|||
ChartLineType, |
|||
ChartShape |
|||
} from '@home/components/widget/lib/chart/chart.models'; |
|||
import { Font } from '@shared/models/widget-settings.models'; |
|||
import { mergeDeep } from '@core/utils'; |
|||
import { |
|||
radarChartAnimationDefaultSettings, |
|||
RadarChartSettings, |
|||
RadarChartShape |
|||
} from '@home/components/widget/lib/chart/radar-chart.models'; |
|||
import { DeepPartial } from '@shared/models/common'; |
|||
|
|||
export interface RadarChartWidgetSettings extends LatestChartWidgetSettings { |
|||
shape: RadarChartShape; |
|||
color: string; |
|||
showLine: boolean; |
|||
lineType: ChartLineType; |
|||
lineWidth: number; |
|||
showPoints: boolean; |
|||
pointShape: ChartShape; |
|||
pointSize: number; |
|||
showLabel: boolean; |
|||
labelPosition: ChartLabelPosition; |
|||
labelFont: Font; |
|||
labelColor: string; |
|||
fillAreaSettings: ChartFillSettings; |
|||
axisShowLabel: boolean; |
|||
axisLabelFont: Font; |
|||
axisShowTickLabels: boolean; |
|||
axisTickLabelFont: Font; |
|||
axisTickLabelColor: string; |
|||
} |
|||
|
|||
export const radarChartWidgetDefaultSettings: RadarChartWidgetSettings = { |
|||
...latestChartWidgetDefaultSettings, |
|||
animation: mergeDeep({} as ChartAnimationSettings, |
|||
radarChartAnimationDefaultSettings), |
|||
shape: RadarChartShape.polygon, |
|||
color: '#3F52DD', |
|||
showLine: true, |
|||
lineType: ChartLineType.solid, |
|||
lineWidth: 2, |
|||
showPoints: true, |
|||
pointShape: ChartShape.circle, |
|||
pointSize: 4, |
|||
showLabel: false, |
|||
labelPosition: ChartLabelPosition.top, |
|||
labelFont: { |
|||
family: 'Roboto', |
|||
size: 11, |
|||
sizeUnit: 'px', |
|||
style: 'normal', |
|||
weight: '400', |
|||
lineHeight: '1' |
|||
}, |
|||
labelColor: chartColorScheme['series.label'].light, |
|||
fillAreaSettings: { |
|||
type: ChartFillType.none, |
|||
opacity: 0.4, |
|||
gradient: { |
|||
start: 80, |
|||
end: 20 |
|||
} |
|||
}, |
|||
axisShowLabel: true, |
|||
axisLabelFont: { |
|||
family: 'Roboto', |
|||
size: 12, |
|||
sizeUnit: 'px', |
|||
style: 'normal', |
|||
weight: '600', |
|||
lineHeight: '1' |
|||
}, |
|||
axisShowTickLabels: false, |
|||
axisTickLabelFont: { |
|||
family: 'Roboto', |
|||
size: 11, |
|||
sizeUnit: 'px', |
|||
style: 'normal', |
|||
weight: '400', |
|||
lineHeight: '1' |
|||
}, |
|||
axisTickLabelColor: chartColorScheme['axis.tickLabel'].light |
|||
}; |
|||
|
|||
export const radarChartWidgetRadarChartSettings = (settings: RadarChartWidgetSettings): DeepPartial<RadarChartSettings> => ({ |
|||
shape: settings.shape, |
|||
color: settings.color, |
|||
showLine: settings.showLine, |
|||
lineType: settings.lineType, |
|||
lineWidth: settings.lineWidth, |
|||
showPoints: settings.showPoints, |
|||
pointShape: settings.pointShape, |
|||
pointSize: settings.pointSize, |
|||
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, |
|||
sortSeries: settings.sortSeries, |
|||
showTotal: false, |
|||
animation: settings.animation, |
|||
showLegend: settings.showLegend, |
|||
showTooltip: settings.showTooltip, |
|||
tooltipValueType: settings.tooltipValueType, |
|||
tooltipValueDecimals: settings.tooltipValueDecimals, |
|||
tooltipValueFont: settings.tooltipValueFont, |
|||
tooltipValueColor: settings.tooltipValueColor, |
|||
tooltipBackgroundColor: settings.tooltipBackgroundColor, |
|||
tooltipBackgroundBlur: settings.tooltipBackgroundBlur |
|||
}); |
|||
@ -0,0 +1,122 @@ |
|||
///
|
|||
/// 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 { latestChartDefaultSettings, LatestChartSettings } from '@home/components/widget/lib/chart/latest-chart.models'; |
|||
import { |
|||
chartAnimationDefaultSettings, |
|||
ChartAnimationSettings, |
|||
chartColorScheme, |
|||
ChartFillSettings, |
|||
ChartFillType, |
|||
ChartLabelPosition, |
|||
ChartLineType, |
|||
ChartShape |
|||
} from '@home/components/widget/lib/chart/chart.models'; |
|||
import { Font } from '@shared/models/widget-settings.models'; |
|||
import { mergeDeep } from '@core/utils'; |
|||
|
|||
export enum RadarChartShape { |
|||
polygon = 'polygon', |
|||
circle = 'circle' |
|||
} |
|||
|
|||
export const radarChartShapes = Object.keys(RadarChartShape) as RadarChartShape[]; |
|||
|
|||
export const radarChartShapeTranslations = new Map<RadarChartShape, string>( |
|||
[ |
|||
[RadarChartShape.polygon, 'widgets.radar-chart.shape-polygon'], |
|||
[RadarChartShape.circle, 'widgets.radar-chart.shape-circle'] |
|||
] |
|||
); |
|||
|
|||
export interface RadarChartSettings extends LatestChartSettings { |
|||
shape: RadarChartShape; |
|||
color: string; |
|||
showLine: boolean; |
|||
lineType: ChartLineType; |
|||
lineWidth: number; |
|||
showPoints: boolean; |
|||
pointShape: ChartShape; |
|||
pointSize: number; |
|||
showLabel: boolean; |
|||
labelPosition: ChartLabelPosition; |
|||
labelFont: Font; |
|||
labelColor: string; |
|||
fillAreaSettings: ChartFillSettings; |
|||
axisShowLabel: boolean; |
|||
axisLabelFont: Font; |
|||
axisShowTickLabels: boolean; |
|||
axisTickLabelFont: Font; |
|||
axisTickLabelColor: string; |
|||
} |
|||
|
|||
export const radarChartAnimationDefaultSettings: ChartAnimationSettings = |
|||
mergeDeep({} as ChartAnimationSettings, chartAnimationDefaultSettings, { |
|||
animationDuration: 1000, |
|||
animationDurationUpdate: 500 |
|||
} as ChartAnimationSettings); |
|||
|
|||
export const radarChartDefaultSettings: RadarChartSettings = { |
|||
...latestChartDefaultSettings, |
|||
animation: mergeDeep({} as ChartAnimationSettings, |
|||
radarChartAnimationDefaultSettings), |
|||
shape: RadarChartShape.polygon, |
|||
color: '#3F52DD', |
|||
showLine: true, |
|||
lineType: ChartLineType.solid, |
|||
lineWidth: 2, |
|||
showPoints: true, |
|||
pointShape: ChartShape.circle, |
|||
pointSize: 4, |
|||
showLabel: false, |
|||
labelPosition: ChartLabelPosition.top, |
|||
labelFont: { |
|||
family: 'Roboto', |
|||
size: 11, |
|||
sizeUnit: 'px', |
|||
style: 'normal', |
|||
weight: '400', |
|||
lineHeight: '1' |
|||
}, |
|||
labelColor: chartColorScheme['series.label'].light, |
|||
fillAreaSettings: { |
|||
type: ChartFillType.none, |
|||
opacity: 0.4, |
|||
gradient: { |
|||
start: 80, |
|||
end: 20 |
|||
} |
|||
}, |
|||
axisShowLabel: true, |
|||
axisLabelFont: { |
|||
family: 'Roboto', |
|||
size: 12, |
|||
sizeUnit: 'px', |
|||
style: 'normal', |
|||
weight: '600', |
|||
lineHeight: '1' |
|||
}, |
|||
axisShowTickLabels: false, |
|||
axisTickLabelFont: { |
|||
family: 'Roboto', |
|||
size: 11, |
|||
sizeUnit: 'px', |
|||
style: 'normal', |
|||
weight: '400', |
|||
lineHeight: '1' |
|||
}, |
|||
axisTickLabelColor: chartColorScheme['axis.tickLabel'].light |
|||
}; |
|||
@ -0,0 +1,172 @@ |
|||
///
|
|||
/// 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 { TbLatestChart } from '@home/components/widget/lib/chart/latest-chart'; |
|||
import { radarChartDefaultSettings, RadarChartSettings } from '@home/components/widget/lib/chart/radar-chart.models'; |
|||
import { WidgetContext } from '@home/models/widget-component.models'; |
|||
import { DeepPartial } from '@shared/models/common'; |
|||
import { Renderer2 } from '@angular/core'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { |
|||
ChartFillType, |
|||
createChartTextStyle, |
|||
createLinearOpacityGradient, createRadialOpacityGradient, toAnimationOption |
|||
} from '@home/components/widget/lib/chart/chart.models'; |
|||
import { formatValue, isDefinedAndNotNull, isEqual } from '@core/utils'; |
|||
import { ComponentStyle } from '@shared/models/widget-settings.models'; |
|||
import { AreaStyleOption, SeriesLabelOption } from 'echarts/types/src/util/types'; |
|||
import { RadarIndicatorOption } from 'echarts/types/src/coord/radar/RadarModel'; |
|||
import { DataKey } from '@shared/models/widget.models'; |
|||
|
|||
export class TbRadarChart extends TbLatestChart<RadarChartSettings> { |
|||
|
|||
constructor(ctx: WidgetContext, |
|||
inputSettings: DeepPartial<RadarChartSettings>, |
|||
chartElement: HTMLElement, |
|||
renderer: Renderer2, |
|||
translate: TranslateService, |
|||
autoResize = true) { |
|||
|
|||
super(ctx, inputSettings, chartElement, renderer, translate, autoResize); |
|||
} |
|||
|
|||
protected defaultSettings(): RadarChartSettings { |
|||
return radarChartDefaultSettings; |
|||
} |
|||
|
|||
protected prepareLatestChartOption() { |
|||
|
|||
const axisNameStyle = createChartTextStyle(this.settings.axisLabelFont, |
|||
'#000', false, 'axis.label'); |
|||
const axisTickLabelStyle = createChartTextStyle(this.settings.axisTickLabelFont, |
|||
this.settings.axisTickLabelColor, false, 'axis.tickLabel'); |
|||
|
|||
this.latestChartOption.radar = [{ |
|||
shape: this.settings.shape, |
|||
radius: '85%', |
|||
indicator: [{}], |
|||
axisName: { |
|||
show: this.settings.axisShowLabel, |
|||
fontStyle: axisNameStyle.fontStyle, |
|||
fontWeight: axisNameStyle.fontWeight, |
|||
fontFamily: axisNameStyle.fontFamily, |
|||
fontSize: axisNameStyle.fontSize |
|||
}, |
|||
axisLabel: { |
|||
show: this.settings.axisShowTickLabels, |
|||
color: axisTickLabelStyle.color, |
|||
fontStyle: axisTickLabelStyle.fontStyle, |
|||
fontWeight: axisTickLabelStyle.fontWeight, |
|||
fontFamily: axisTickLabelStyle.fontFamily, |
|||
fontSize: axisTickLabelStyle.fontSize, |
|||
formatter: (value: any) => formatValue(value, this.decimals, this.units, false) |
|||
} |
|||
}]; |
|||
|
|||
let labelStyle: ComponentStyle = {}; |
|||
if (this.settings.showLabel) { |
|||
labelStyle = createChartTextStyle(this.settings.labelFont, this.settings.labelColor, false, 'series.label'); |
|||
} |
|||
|
|||
const labelOption: SeriesLabelOption = { |
|||
show: this.settings.showLabel, |
|||
position: this.settings.labelPosition, |
|||
formatter: (params) => { |
|||
let result = ''; |
|||
if (isDefinedAndNotNull(params.value)) { |
|||
result = formatValue(params.value, this.decimals, this.units, false); |
|||
} |
|||
return `{value|${result}}`; |
|||
}, |
|||
rich: { |
|||
value: labelStyle |
|||
} |
|||
}; |
|||
|
|||
let areaStyleOption: AreaStyleOption; |
|||
if (this.settings.fillAreaSettings.type !== ChartFillType.none) { |
|||
areaStyleOption = {}; |
|||
if (this.settings.fillAreaSettings.type === ChartFillType.opacity) { |
|||
areaStyleOption.opacity = this.settings.fillAreaSettings.opacity; |
|||
} else if (this.settings.fillAreaSettings.type === ChartFillType.gradient) { |
|||
areaStyleOption.opacity = 1; |
|||
areaStyleOption.color = createRadialOpacityGradient(this.settings.color, this.settings.fillAreaSettings.gradient); |
|||
} |
|||
} |
|||
|
|||
this.latestChartOption.series = [ |
|||
{ |
|||
type: 'radar', |
|||
data: [{ |
|||
id: 1, |
|||
itemStyle: { |
|||
color: this.settings.color |
|||
}, |
|||
label: labelOption, |
|||
symbol: this.settings.showPoints ? this.settings.pointShape : 'none', |
|||
symbolSize: this.settings.pointSize, |
|||
lineStyle: { |
|||
width: this.settings.showLine ? this.settings.lineWidth : 0, |
|||
type: this.settings.lineType |
|||
}, |
|||
areaStyle: areaStyleOption, |
|||
value: [] |
|||
}], |
|||
emphasis: { |
|||
focus: 'self' |
|||
}, |
|||
...toAnimationOption(this.ctx, this.settings.animation) |
|||
} |
|||
]; |
|||
} |
|||
|
|||
protected doUpdateSeriesData() { |
|||
const indicator: RadarIndicatorOption[] = []; |
|||
const value: number[] = []; |
|||
for (const dataItem of this.dataItems) { |
|||
if (dataItem.enabled && dataItem.hasValue) { |
|||
indicator.push({ |
|||
name: dataItem.dataKey.label, |
|||
color: dataItem.dataKey.color |
|||
}); |
|||
value.push(dataItem.value); |
|||
} |
|||
} |
|||
if (!indicator.length) { |
|||
indicator.push({}); |
|||
} |
|||
this.latestChartOption.radar[0].indicator = indicator; |
|||
this.latestChartOption.series[0].data[0].value = value; |
|||
} |
|||
|
|||
protected forceRedrawOnResize(): boolean { |
|||
return true; |
|||
} |
|||
|
|||
public keyEnter(dataKey: DataKey): void {} |
|||
|
|||
public keyLeave(dataKey: DataKey): void {} |
|||
|
|||
public toggleKey(dataKey: DataKey): void { |
|||
const enable = dataKey.hidden; |
|||
const dataItem = this.dataItems.find(d => d.dataKey === dataKey); |
|||
if (dataItem) { |
|||
dataItem.enabled = enable; |
|||
this.updateSeriesData(); |
|||
dataKey.hidden = !enable; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,248 @@ |
|||
<!-- |
|||
|
|||
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> |
|||
@ -0,0 +1,244 @@ |
|||
///
|
|||
/// Copyright © 2016-2024 The Thingsboard Authors
|
|||
///
|
|||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|||
/// you may not use this file except in compliance with the License.
|
|||
/// You may obtain a copy of the License at
|
|||
///
|
|||
/// http://www.apache.org/licenses/LICENSE-2.0
|
|||
///
|
|||
/// Unless required by applicable law or agreed to in writing, software
|
|||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
/// See the License for the specific language governing permissions and
|
|||
/// limitations under the License.
|
|||
///
|
|||
|
|||
import { Component } from '@angular/core'; |
|||
import { |
|||
legendPositions, |
|||
legendPositionTranslationMap, |
|||
WidgetSettings, |
|||
WidgetSettingsComponent |
|||
} from '@shared/models/widget.models'; |
|||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; |
|||
import { Store } from '@ngrx/store'; |
|||
import { AppState } from '@core/core.state'; |
|||
import { formatValue, mergeDeep } from '@core/utils'; |
|||
import { |
|||
LatestChartTooltipValueType, |
|||
latestChartTooltipValueTypes, |
|||
latestChartTooltipValueTypeTranslations |
|||
} from '@home/components/widget/lib/chart/latest-chart.models'; |
|||
import { |
|||
radarChartWidgetDefaultSettings, |
|||
RadarChartWidgetSettings |
|||
} from '@home/components/widget/lib/chart/radar-chart-widget.models'; |
|||
import { radarChartShapes, radarChartShapeTranslations } from '@home/components/widget/lib/chart/radar-chart.models'; |
|||
import { |
|||
chartLabelPositions, |
|||
chartLabelPositionTranslations, |
|||
chartLineTypes, |
|||
chartLineTypeTranslations, |
|||
chartShapes, |
|||
chartShapeTranslations |
|||
} from '@home/components/widget/lib/chart/chart.models'; |
|||
|
|||
@Component({ |
|||
selector: 'tb-radar-chart-widget-settings', |
|||
templateUrl: './radar-chart-widget-settings.component.html', |
|||
styleUrls: [] |
|||
}) |
|||
export class RadarChartWidgetSettingsComponent extends WidgetSettingsComponent { |
|||
|
|||
radarChartShapes = radarChartShapes; |
|||
|
|||
radarChartShapeTranslations = radarChartShapeTranslations; |
|||
|
|||
chartLineTypes = chartLineTypes; |
|||
|
|||
chartLineTypeTranslations = chartLineTypeTranslations; |
|||
|
|||
chartShapes = chartShapes; |
|||
|
|||
chartShapeTranslations = chartShapeTranslations; |
|||
|
|||
chartLabelPositions = chartLabelPositions; |
|||
|
|||
chartLabelPositionTranslations = chartLabelPositionTranslations; |
|||
|
|||
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>, |
|||
private fb: UntypedFormBuilder) { |
|||
super(store); |
|||
} |
|||
|
|||
protected settingsForm(): UntypedFormGroup { |
|||
return this.radarChartWidgetSettingsForm; |
|||
} |
|||
|
|||
protected defaultSettings(): WidgetSettings { |
|||
return mergeDeep<RadarChartWidgetSettings>({} as RadarChartWidgetSettings, radarChartWidgetDefaultSettings); |
|||
} |
|||
|
|||
protected onSettingsSet(settings: WidgetSettings) { |
|||
this.radarChartWidgetSettingsForm = this.fb.group({ |
|||
|
|||
sortSeries: [settings.sortSeries, []], |
|||
|
|||
shape: [settings.shape, []], |
|||
color: [settings.color, []], |
|||
showLine: [settings.showLine, []], |
|||
lineType: [settings.lineType, []], |
|||
lineWidth: [settings.lineWidth, [Validators.min(0)]], |
|||
showPoints: [settings.showPoints, []], |
|||
pointShape: [settings.pointShape, []], |
|||
pointSize: [settings.pointSize, [Validators.min(0)]], |
|||
showLabel: [settings.showLabel, []], |
|||
labelPosition: [settings.labelPosition, []], |
|||
labelFont: [settings.labelFont, []], |
|||
labelColor: [settings.labelColor, []], |
|||
fillAreaSettings: [settings.fillAreaSettings, []], |
|||
|
|||
axisShowLabel: [settings.axisShowLabel, []], |
|||
axisLabelFont: [settings.axisLabelFont, []], |
|||
axisShowTickLabels: [settings.axisShowTickLabels, []], |
|||
axisTickLabelFont: [settings.axisTickLabelFont, []], |
|||
axisTickLabelColor: [settings.axisTickLabelColor, []], |
|||
|
|||
animation: [settings.animation, []], |
|||
|
|||
showLegend: [settings.showLegend, []], |
|||
legendPosition: [settings.legendPosition, []], |
|||
legendLabelFont: [settings.legendLabelFont, []], |
|||
legendLabelColor: [settings.legendLabelColor, []], |
|||
legendValueFont: [settings.legendValueFont, []], |
|||
legendValueColor: [settings.legendValueColor, []], |
|||
|
|||
showTooltip: [settings.showTooltip, []], |
|||
tooltipValueType: [settings.tooltipValueType, []], |
|||
tooltipValueDecimals: [settings.tooltipValueDecimals, []], |
|||
tooltipValueFont: [settings.tooltipValueFont, []], |
|||
tooltipValueColor: [settings.tooltipValueColor, []], |
|||
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], |
|||
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], |
|||
|
|||
background: [settings.background, []] |
|||
}); |
|||
} |
|||
|
|||
protected validatorTriggers(): string[] { |
|||
return ['showLine', 'showPoints', 'showLabel', 'axisShowLabel', |
|||
'axisShowTickLabels', 'showLegend', 'showTooltip']; |
|||
} |
|||
|
|||
protected updateValidators(emitEvent: boolean) { |
|||
const showLine: boolean = this.radarChartWidgetSettingsForm.get('showLine').value; |
|||
const showPoints: boolean = this.radarChartWidgetSettingsForm.get('showPoints').value; |
|||
const showLabel: boolean = this.radarChartWidgetSettingsForm.get('showLabel').value; |
|||
const axisShowLabel: boolean = this.radarChartWidgetSettingsForm.get('axisShowLabel').value; |
|||
const axisShowTickLabels: boolean = this.radarChartWidgetSettingsForm.get('axisShowTickLabels').value; |
|||
const showLegend: boolean = this.radarChartWidgetSettingsForm.get('showLegend').value; |
|||
const showTooltip: boolean = this.radarChartWidgetSettingsForm.get('showTooltip').value; |
|||
|
|||
if (showLine) { |
|||
this.radarChartWidgetSettingsForm.get('lineType').enable(); |
|||
this.radarChartWidgetSettingsForm.get('lineWidth').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('lineType').disable(); |
|||
this.radarChartWidgetSettingsForm.get('lineWidth').disable(); |
|||
} |
|||
|
|||
if (showPoints) { |
|||
this.radarChartWidgetSettingsForm.get('pointShape').enable(); |
|||
this.radarChartWidgetSettingsForm.get('pointSize').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('pointShape').disable(); |
|||
this.radarChartWidgetSettingsForm.get('pointSize').disable(); |
|||
} |
|||
|
|||
if (showLabel) { |
|||
this.radarChartWidgetSettingsForm.get('labelPosition').enable(); |
|||
this.radarChartWidgetSettingsForm.get('labelFont').enable(); |
|||
this.radarChartWidgetSettingsForm.get('labelColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('labelPosition').disable(); |
|||
this.radarChartWidgetSettingsForm.get('labelFont').disable(); |
|||
this.radarChartWidgetSettingsForm.get('labelColor').disable(); |
|||
} |
|||
|
|||
if (axisShowLabel) { |
|||
this.radarChartWidgetSettingsForm.get('axisLabelFont').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('axisLabelFont').disable(); |
|||
} |
|||
|
|||
if (axisShowTickLabels) { |
|||
this.radarChartWidgetSettingsForm.get('axisTickLabelFont').enable(); |
|||
this.radarChartWidgetSettingsForm.get('axisTickLabelColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('axisTickLabelFont').disable(); |
|||
this.radarChartWidgetSettingsForm.get('axisTickLabelColor').disable(); |
|||
} |
|||
|
|||
if (showLegend) { |
|||
this.radarChartWidgetSettingsForm.get('legendPosition').enable(); |
|||
this.radarChartWidgetSettingsForm.get('legendLabelFont').enable(); |
|||
this.radarChartWidgetSettingsForm.get('legendLabelColor').enable(); |
|||
this.radarChartWidgetSettingsForm.get('legendValueFont').enable(); |
|||
this.radarChartWidgetSettingsForm.get('legendValueColor').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('legendPosition').disable(); |
|||
this.radarChartWidgetSettingsForm.get('legendLabelFont').disable(); |
|||
this.radarChartWidgetSettingsForm.get('legendLabelColor').disable(); |
|||
this.radarChartWidgetSettingsForm.get('legendValueFont').disable(); |
|||
this.radarChartWidgetSettingsForm.get('legendValueColor').disable(); |
|||
} |
|||
if (showTooltip) { |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueType').enable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').enable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueFont').enable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueColor').enable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipBackgroundColor').enable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable(); |
|||
} else { |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueType').disable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').disable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueFont').disable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipValueColor').disable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipBackgroundColor').disable(); |
|||
this.radarChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable(); |
|||
} |
|||
} |
|||
|
|||
private _valuePreviewFn(): string { |
|||
const units: string = this.widgetConfig.config.units; |
|||
const decimals: number = this.widgetConfig.config.decimals; |
|||
return formatValue(110, decimals, units, false); |
|||
} |
|||
|
|||
private _tooltipValuePreviewFn(): string { |
|||
const tooltipValueType: LatestChartTooltipValueType = this.radarChartWidgetSettingsForm.get('tooltipValueType').value; |
|||
const decimals: number = this.radarChartWidgetSettingsForm.get('tooltipValueDecimals').value; |
|||
if (tooltipValueType === LatestChartTooltipValueType.percentage) { |
|||
return formatValue(35, decimals, '%', false); |
|||
} else { |
|||
const units: string = this.widgetConfig.config.units; |
|||
return formatValue(110, decimals, units, false); |
|||
} |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue