29 changed files with 1390 additions and 479 deletions
File diff suppressed because one or more lines are too long
@ -0,0 +1,248 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2023 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 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 }}" |
||||
|
hideSourceSelection |
||||
|
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.title' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<mat-form-field class="flex" 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 column-xs"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showIcon"> |
||||
|
{{ 'widget-config.card-icon' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<mat-form-field appearance="outline" class="flex number" subscriptSizing="dynamic"> |
||||
|
<input matInput type="number" min="0" formControlName="iconSize" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
</mat-form-field> |
||||
|
<tb-css-unit-select fxFlex formControlName="iconSizeUnit"></tb-css-unit-select> |
||||
|
<tb-material-icon-select asBoxInput |
||||
|
iconClearButton |
||||
|
[color]="barChartWidgetConfigForm.get('iconColor').value" |
||||
|
formControlName="icon"> |
||||
|
</tb-material-icon-select> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="iconColor"> |
||||
|
</tb-color-input> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="tb-form-panel"> |
||||
|
<div class="tb-form-panel-title" translate>widgets.bar-chart.bar-appearance</div> |
||||
|
<div class="tb-form-row space-between"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showBarLabel"> |
||||
|
{{ 'widgets.bar-chart.label-on-bar' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<tb-font-settings formControlName="barLabelFont" |
||||
|
disabledLineHeight |
||||
|
forceSizeUnit="px" |
||||
|
previewText="Humidity"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="barLabelColor"> |
||||
|
</tb-color-input> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showBarValue"> |
||||
|
{{ 'widgets.bar-chart.value-on-bar' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<tb-font-settings formControlName="barValueFont" |
||||
|
disabledLineHeight |
||||
|
forceSizeUnit="px" |
||||
|
previewText="45"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="barValueColor"> |
||||
|
</tb-color-input> |
||||
|
</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]="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="Humidity"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="legendLabelColor"> |
||||
|
</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"> |
||||
|
<div>{{ 'tooltip.value' | translate }}</div> |
||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<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 column-xs"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="tooltipShowDate"> |
||||
|
{{ 'tooltip.date' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<tb-date-format-select fxFlex excludeLastUpdateAgo formControlName="tooltipDateFormat"></tb-date-format-select> |
||||
|
<tb-font-settings formControlName="tooltipDateFont" |
||||
|
[previewText]="tooltipDatePreviewFn"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="tooltipDateColor"> |
||||
|
</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> |
||||
|
<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,323 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2023 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, Injector } 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, |
||||
|
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 { |
||||
|
getTimewindowConfig, |
||||
|
setTimewindowConfig |
||||
|
} from '@home/components/widget/config/timewindow-config-panel.component'; |
||||
|
import { formatValue, isUndefined } from '@core/utils'; |
||||
|
import { |
||||
|
cssSizeToStrSize, |
||||
|
DateFormatProcessor, |
||||
|
DateFormatSettings, |
||||
|
resolveCssSize |
||||
|
} from '@shared/models/widget-settings.models'; |
||||
|
import { |
||||
|
barChartWithLabelsDefaultSettings, |
||||
|
BarChartWithLabelsWidgetSettings |
||||
|
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-bar-chart-with-labels-basic-config', |
||||
|
templateUrl: './bar-chart-with-labels-basic-config.component.html', |
||||
|
styleUrls: ['../basic-config.scss'] |
||||
|
}) |
||||
|
export class BarChartWithLabelsBasicConfigComponent extends BasicWidgetConfigComponent { |
||||
|
|
||||
|
public get datasource(): Datasource { |
||||
|
const datasources: Datasource[] = this.barChartWidgetConfigForm.get('datasources').value; |
||||
|
if (datasources && datasources.length) { |
||||
|
return datasources[0]; |
||||
|
} else { |
||||
|
return null; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
legendPositions = legendPositions; |
||||
|
|
||||
|
legendPositionTranslationMap = legendPositionTranslationMap; |
||||
|
|
||||
|
barChartWidgetConfigForm: UntypedFormGroup; |
||||
|
|
||||
|
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); |
||||
|
|
||||
|
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
protected widgetConfigComponent: WidgetConfigComponent, |
||||
|
private $injector: Injector, |
||||
|
private fb: UntypedFormBuilder) { |
||||
|
super(store, widgetConfigComponent); |
||||
|
} |
||||
|
|
||||
|
protected configForm(): UntypedFormGroup { |
||||
|
return this.barChartWidgetConfigForm; |
||||
|
} |
||||
|
|
||||
|
protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { |
||||
|
return [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]; |
||||
|
} |
||||
|
|
||||
|
protected onConfigSet(configData: WidgetConfigComponentData) { |
||||
|
const settings: BarChartWithLabelsWidgetSettings = {...barChartWithLabelsDefaultSettings, ...(configData.config.settings || {})}; |
||||
|
const iconSize = resolveCssSize(configData.config.iconSize); |
||||
|
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, []], |
||||
|
|
||||
|
showIcon: [configData.config.showTitleIcon, []], |
||||
|
iconSize: [iconSize[0], [Validators.min(0)]], |
||||
|
iconSizeUnit: [iconSize[1], []], |
||||
|
icon: [configData.config.titleIcon, []], |
||||
|
iconColor: [configData.config.iconColor, []], |
||||
|
|
||||
|
showBarLabel: [settings.showBarLabel, []], |
||||
|
barLabelFont: [settings.barLabelFont, []], |
||||
|
barLabelColor: [settings.barLabelColor, []], |
||||
|
showBarValue: [settings.showBarValue, []], |
||||
|
barValueFont: [settings.barValueFont, []], |
||||
|
barValueColor: [settings.barValueColor, []], |
||||
|
|
||||
|
units: [configData.config.units, []], |
||||
|
decimals: [configData.config.decimals, []], |
||||
|
|
||||
|
showLegend: [settings.showLegend, []], |
||||
|
legendPosition: [settings.legendPosition, []], |
||||
|
legendLabelFont: [settings.legendLabelFont, []], |
||||
|
legendLabelColor: [settings.legendLabelColor, []], |
||||
|
|
||||
|
showTooltip: [settings.showTooltip, []], |
||||
|
tooltipValueFont: [settings.tooltipValueFont, []], |
||||
|
tooltipValueColor: [settings.tooltipValueColor, []], |
||||
|
tooltipShowDate: [settings.tooltipShowDate, []], |
||||
|
tooltipDateFormat: [settings.tooltipDateFormat, []], |
||||
|
tooltipDateFont: [settings.tooltipDateFont, []], |
||||
|
tooltipDateColor: [settings.tooltipDateColor, []], |
||||
|
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.showIcon; |
||||
|
this.widgetConfig.config.iconSize = cssSizeToStrSize(config.iconSize, config.iconSizeUnit); |
||||
|
this.widgetConfig.config.titleIcon = config.icon; |
||||
|
this.widgetConfig.config.iconColor = config.iconColor; |
||||
|
|
||||
|
this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; |
||||
|
|
||||
|
this.widgetConfig.config.settings.showBarLabel = config.showBarLabel; |
||||
|
this.widgetConfig.config.settings.barLabelFont = config.barLabelFont; |
||||
|
this.widgetConfig.config.settings.barLabelColor = config.barLabelColor; |
||||
|
this.widgetConfig.config.settings.showBarValue = config.showBarValue; |
||||
|
this.widgetConfig.config.settings.barValueFont = config.barValueFont; |
||||
|
this.widgetConfig.config.settings.barValueColor = config.barValueColor; |
||||
|
|
||||
|
this.widgetConfig.config.units = config.units; |
||||
|
this.widgetConfig.config.decimals = config.decimals; |
||||
|
|
||||
|
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.showTooltip = config.showTooltip; |
||||
|
this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont; |
||||
|
this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor; |
||||
|
this.widgetConfig.config.settings.tooltipShowDate = config.tooltipShowDate; |
||||
|
this.widgetConfig.config.settings.tooltipDateFormat = config.tooltipDateFormat; |
||||
|
this.widgetConfig.config.settings.tooltipDateFont = config.tooltipDateFont; |
||||
|
this.widgetConfig.config.settings.tooltipDateColor = config.tooltipDateColor; |
||||
|
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', 'showIcon', 'showBarLabel', 'showBarValue', 'showLegend', 'showTooltip', 'tooltipShowDate']; |
||||
|
} |
||||
|
|
||||
|
protected updateValidators(emitEvent: boolean, trigger?: string) { |
||||
|
const showTitle: boolean = this.barChartWidgetConfigForm.get('showTitle').value; |
||||
|
const showIcon: boolean = this.barChartWidgetConfigForm.get('showIcon').value; |
||||
|
const showBarLabel: boolean = this.barChartWidgetConfigForm.get('showBarLabel').value; |
||||
|
const showBarValue: boolean = this.barChartWidgetConfigForm.get('showBarValue').value; |
||||
|
const showLegend: boolean = this.barChartWidgetConfigForm.get('showLegend').value; |
||||
|
const showTooltip: boolean = this.barChartWidgetConfigForm.get('showTooltip').value; |
||||
|
const tooltipShowDate: boolean = this.barChartWidgetConfigForm.get('tooltipShowDate').value; |
||||
|
|
||||
|
if (showTitle) { |
||||
|
this.barChartWidgetConfigForm.get('title').enable(); |
||||
|
this.barChartWidgetConfigForm.get('titleFont').enable(); |
||||
|
this.barChartWidgetConfigForm.get('titleColor').enable(); |
||||
|
this.barChartWidgetConfigForm.get('showIcon').enable({emitEvent: false}); |
||||
|
if (showIcon) { |
||||
|
this.barChartWidgetConfigForm.get('iconSize').enable(); |
||||
|
this.barChartWidgetConfigForm.get('iconSizeUnit').enable(); |
||||
|
this.barChartWidgetConfigForm.get('icon').enable(); |
||||
|
this.barChartWidgetConfigForm.get('iconColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetConfigForm.get('iconSize').disable(); |
||||
|
this.barChartWidgetConfigForm.get('iconSizeUnit').disable(); |
||||
|
this.barChartWidgetConfigForm.get('icon').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('showIcon').disable({emitEvent: false}); |
||||
|
this.barChartWidgetConfigForm.get('iconSize').disable(); |
||||
|
this.barChartWidgetConfigForm.get('iconSizeUnit').disable(); |
||||
|
this.barChartWidgetConfigForm.get('icon').disable(); |
||||
|
this.barChartWidgetConfigForm.get('iconColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showBarLabel) { |
||||
|
this.barChartWidgetConfigForm.get('barLabelFont').enable(); |
||||
|
this.barChartWidgetConfigForm.get('barLabelColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetConfigForm.get('barLabelFont').disable(); |
||||
|
this.barChartWidgetConfigForm.get('barLabelColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showBarValue) { |
||||
|
this.barChartWidgetConfigForm.get('barValueFont').enable(); |
||||
|
this.barChartWidgetConfigForm.get('barValueColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetConfigForm.get('barValueFont').disable(); |
||||
|
this.barChartWidgetConfigForm.get('barValueColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showLegend) { |
||||
|
this.barChartWidgetConfigForm.get('legendPosition').enable(); |
||||
|
this.barChartWidgetConfigForm.get('legendLabelFont').enable(); |
||||
|
this.barChartWidgetConfigForm.get('legendLabelColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetConfigForm.get('legendPosition').disable(); |
||||
|
this.barChartWidgetConfigForm.get('legendLabelFont').disable(); |
||||
|
this.barChartWidgetConfigForm.get('legendLabelColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showTooltip) { |
||||
|
this.barChartWidgetConfigForm.get('tooltipValueFont').enable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipValueColor').enable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipShowDate').enable({emitEvent: false}); |
||||
|
this.barChartWidgetConfigForm.get('tooltipBackgroundColor').enable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipBackgroundBlur').enable(); |
||||
|
if (tooltipShowDate) { |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateFormat').enable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateFont').enable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateFormat').disable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateFont').disable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateColor').disable(); |
||||
|
} |
||||
|
} else { |
||||
|
this.barChartWidgetConfigForm.get('tooltipValueFont').disable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipValueColor').disable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipShowDate').disable({emitEvent: false}); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateFormat').disable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateFont').disable(); |
||||
|
this.barChartWidgetConfigForm.get('tooltipDateColor').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 _tooltipValuePreviewFn(): string { |
||||
|
const units: string = this.barChartWidgetConfigForm.get('units').value; |
||||
|
const decimals: number = this.barChartWidgetConfigForm.get('decimals').value; |
||||
|
return formatValue(22, decimals, units, false); |
||||
|
} |
||||
|
|
||||
|
private _tooltipDatePreviewFn(): string { |
||||
|
const dateFormat: DateFormatSettings = this.barChartWidgetConfigForm.get('tooltipDateFormat').value; |
||||
|
const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); |
||||
|
processor.update(Date.now()); |
||||
|
return processor.formatted; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,214 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2023 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 * as echarts from 'echarts/core'; |
||||
|
import { Axis } from 'echarts'; |
||||
|
import AxisModel from 'echarts/types/src/coord/cartesian/AxisModel'; |
||||
|
import { formatValue, isNumber } from '@core/utils'; |
||||
|
import TimeScale from 'echarts/types/src/scale/Time'; |
||||
|
import { |
||||
|
DataZoomComponent, DataZoomComponentOption, |
||||
|
GridComponent, GridComponentOption, |
||||
|
MarkLineComponent, MarkLineComponentOption, |
||||
|
TooltipComponent, TooltipComponentOption, |
||||
|
VisualMapComponent, VisualMapComponentOption |
||||
|
} from 'echarts/components'; |
||||
|
import { |
||||
|
BarChart, |
||||
|
LineChart, |
||||
|
CustomChart, |
||||
|
CustomSeriesOption, |
||||
|
LineSeriesOption, |
||||
|
BarSeriesOption, PieSeriesOption, PieChart |
||||
|
} from 'echarts/charts'; |
||||
|
import { LabelLayout } from 'echarts/features'; |
||||
|
import { CanvasRenderer, SVGRenderer } from 'echarts/renderers'; |
||||
|
import { DataSet } from '@shared/models/widget.models'; |
||||
|
import { CallbackDataParams } from 'echarts/types/dist/shared'; |
||||
|
import { Renderer2 } from '@angular/core'; |
||||
|
import { DateFormatProcessor, DateFormatSettings, Font } from '@shared/models/widget-settings.models'; |
||||
|
|
||||
|
class EChartsModule { |
||||
|
private initialized = false; |
||||
|
|
||||
|
init() { |
||||
|
if (!this.initialized) { |
||||
|
const axisGetBandWidth = Axis.prototype.getBandWidth; |
||||
|
|
||||
|
Axis.prototype.getBandWidth = function(){ |
||||
|
const model: AxisModel = this.model; |
||||
|
const axisOption = model.option; |
||||
|
const tbTimewindowInterval = (axisOption as any).tbTimewindowInterval; |
||||
|
if (this.scale.type === 'time' && isNumber(tbTimewindowInterval)) { |
||||
|
const timeScale: TimeScale = this.scale; |
||||
|
const axisExtent: [number, number] = this._extent; |
||||
|
const dataExtent = timeScale.getExtent(); |
||||
|
const size = Math.abs(axisExtent[1] - axisExtent[0]); |
||||
|
return tbTimewindowInterval * (size / (dataExtent[1] - dataExtent[0])); |
||||
|
} else { |
||||
|
return axisGetBandWidth.call(this); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
echarts.use([ |
||||
|
TooltipComponent, |
||||
|
GridComponent, |
||||
|
VisualMapComponent, |
||||
|
DataZoomComponent, |
||||
|
MarkLineComponent, |
||||
|
LineChart, |
||||
|
BarChart, |
||||
|
PieChart, |
||||
|
CustomChart, |
||||
|
LabelLayout, |
||||
|
CanvasRenderer, |
||||
|
SVGRenderer |
||||
|
]); |
||||
|
|
||||
|
this.initialized = true; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
export const echartsModule = new EChartsModule(); |
||||
|
|
||||
|
export type EChartsOption = echarts.ComposeOption< |
||||
|
| TooltipComponentOption |
||||
|
| GridComponentOption |
||||
|
| VisualMapComponentOption |
||||
|
| DataZoomComponentOption |
||||
|
| MarkLineComponentOption |
||||
|
| LineSeriesOption |
||||
|
| CustomSeriesOption |
||||
|
| BarSeriesOption |
||||
|
| PieSeriesOption |
||||
|
>; |
||||
|
|
||||
|
export type ECharts = echarts.ECharts; |
||||
|
|
||||
|
export type NamedDataSet = {name: string; value: [number, any]}[]; |
||||
|
|
||||
|
export const toNamedData = (data: DataSet): NamedDataSet => { |
||||
|
if (!data?.length) { |
||||
|
return []; |
||||
|
} else { |
||||
|
return data.map(d => ({ |
||||
|
name: d[0] + '', |
||||
|
value: d |
||||
|
})); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
export interface EChartsTooltipWidgetSettings { |
||||
|
showTooltip: boolean; |
||||
|
tooltipValueFont: Font; |
||||
|
tooltipValueColor: string; |
||||
|
tooltipShowDate: boolean; |
||||
|
tooltipDateFormat: DateFormatSettings; |
||||
|
tooltipDateFont: Font; |
||||
|
tooltipDateColor: string; |
||||
|
tooltipBackgroundColor: string; |
||||
|
tooltipBackgroundBlur: number; |
||||
|
} |
||||
|
|
||||
|
export const echartsTooltipFormatter = (renderer: Renderer2, |
||||
|
tooltipDateFormat: DateFormatProcessor, |
||||
|
settings: EChartsTooltipWidgetSettings, |
||||
|
params: CallbackDataParams[], |
||||
|
decimals: number, |
||||
|
units: string, |
||||
|
focusedSeriesIndex: number): null | HTMLElement => { |
||||
|
if (!params.length || !params[0]) { |
||||
|
return null; |
||||
|
} |
||||
|
const tooltipElement: HTMLElement = renderer.createElement('div'); |
||||
|
renderer.setStyle(tooltipElement, 'display', 'flex'); |
||||
|
renderer.setStyle(tooltipElement, 'flex-direction', 'column'); |
||||
|
renderer.setStyle(tooltipElement, 'align-items', 'flex-start'); |
||||
|
renderer.setStyle(tooltipElement, 'gap', '4px'); |
||||
|
if (settings.tooltipShowDate) { |
||||
|
const dateElement: HTMLElement = renderer.createElement('div'); |
||||
|
const ts = params[0].value[0]; |
||||
|
tooltipDateFormat.update(ts); |
||||
|
renderer.appendChild(dateElement, renderer.createText(tooltipDateFormat.formatted)); |
||||
|
renderer.setStyle(dateElement, 'font-family', settings.tooltipDateFont.family); |
||||
|
renderer.setStyle(dateElement, 'font-size', settings.tooltipDateFont.size + settings.tooltipDateFont.sizeUnit); |
||||
|
renderer.setStyle(dateElement, 'font-style', settings.tooltipDateFont.style); |
||||
|
renderer.setStyle(dateElement, 'font-weight', settings.tooltipDateFont.weight); |
||||
|
renderer.setStyle(dateElement, 'line-height', settings.tooltipDateFont.lineHeight); |
||||
|
renderer.setStyle(dateElement, 'color', settings.tooltipDateColor); |
||||
|
renderer.appendChild(tooltipElement, dateElement); |
||||
|
} |
||||
|
let seriesParams: CallbackDataParams = null; |
||||
|
if (focusedSeriesIndex > -1) { |
||||
|
seriesParams = params.find(param => param.seriesIndex === focusedSeriesIndex); |
||||
|
} |
||||
|
if (seriesParams) { |
||||
|
renderer.appendChild(tooltipElement, constructEchartsTooltipSeriesElement(renderer, settings, seriesParams, decimals, units)); |
||||
|
} else { |
||||
|
for (seriesParams of params) { |
||||
|
renderer.appendChild(tooltipElement, constructEchartsTooltipSeriesElement(renderer, settings, seriesParams, decimals, units)); |
||||
|
} |
||||
|
} |
||||
|
return tooltipElement; |
||||
|
}; |
||||
|
|
||||
|
const constructEchartsTooltipSeriesElement = (renderer: Renderer2, |
||||
|
settings: EChartsTooltipWidgetSettings, |
||||
|
seriesParams: CallbackDataParams, |
||||
|
decimals: number, |
||||
|
units: string): HTMLElement => { |
||||
|
const labelValueElement: HTMLElement = renderer.createElement('div'); |
||||
|
renderer.setStyle(labelValueElement, 'display', 'flex'); |
||||
|
renderer.setStyle(labelValueElement, 'flex-direction', 'row'); |
||||
|
renderer.setStyle(labelValueElement, 'align-items', 'center'); |
||||
|
renderer.setStyle(labelValueElement, 'align-self', 'stretch'); |
||||
|
renderer.setStyle(labelValueElement, 'gap', '12px'); |
||||
|
const labelElement: HTMLElement = renderer.createElement('div'); |
||||
|
renderer.setStyle(labelElement, 'display', 'flex'); |
||||
|
renderer.setStyle(labelElement, 'align-items', 'center'); |
||||
|
renderer.setStyle(labelElement, 'gap', '8px'); |
||||
|
renderer.appendChild(labelValueElement, labelElement); |
||||
|
const circleElement: HTMLElement = renderer.createElement('div'); |
||||
|
renderer.setStyle(circleElement, 'width', '8px'); |
||||
|
renderer.setStyle(circleElement, 'height', '8px'); |
||||
|
renderer.setStyle(circleElement, 'border-radius', '50%'); |
||||
|
renderer.setStyle(circleElement, 'background', seriesParams.color); |
||||
|
renderer.appendChild(labelElement, circleElement); |
||||
|
const labelTextElement: HTMLElement = renderer.createElement('div'); |
||||
|
renderer.appendChild(labelTextElement, renderer.createText(seriesParams.seriesName)); |
||||
|
renderer.setStyle(labelTextElement, 'font-family', 'Roboto'); |
||||
|
renderer.setStyle(labelTextElement, 'font-size', '12px'); |
||||
|
renderer.setStyle(labelTextElement, 'font-style', 'normal'); |
||||
|
renderer.setStyle(labelTextElement, 'font-weight', '400'); |
||||
|
renderer.setStyle(labelTextElement, 'line-height', '16px'); |
||||
|
renderer.setStyle(labelTextElement, 'letter-spacing', '0.4px'); |
||||
|
renderer.setStyle(labelTextElement, 'color', 'rgba(0, 0, 0, 0.76)'); |
||||
|
renderer.appendChild(labelElement, labelTextElement); |
||||
|
const valueElement: HTMLElement = renderer.createElement('div'); |
||||
|
const value = formatValue(seriesParams.value[1], decimals, units, false); |
||||
|
renderer.appendChild(valueElement, renderer.createText(value)); |
||||
|
renderer.setStyle(valueElement, 'flex', '1'); |
||||
|
renderer.setStyle(valueElement, 'text-align', 'end'); |
||||
|
renderer.setStyle(valueElement, 'font-family', settings.tooltipValueFont.family); |
||||
|
renderer.setStyle(valueElement, 'font-size', settings.tooltipValueFont.size + settings.tooltipValueFont.sizeUnit); |
||||
|
renderer.setStyle(valueElement, 'font-style', settings.tooltipValueFont.style); |
||||
|
renderer.setStyle(valueElement, 'font-weight', settings.tooltipValueFont.weight); |
||||
|
renderer.setStyle(valueElement, 'line-height', settings.tooltipValueFont.lineHeight); |
||||
|
renderer.setStyle(valueElement, 'color', settings.tooltipValueColor); |
||||
|
renderer.appendChild(labelValueElement, valueElement); |
||||
|
return labelValueElement; |
||||
|
}; |
||||
@ -0,0 +1,150 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2023 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-card-style</div> |
||||
|
<div class="tb-form-row space-between"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showBarLabel"> |
||||
|
{{ 'widgets.bar-chart.label-on-bar' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<tb-font-settings formControlName="barLabelFont" |
||||
|
disabledLineHeight |
||||
|
forceSizeUnit="px" |
||||
|
previewText="Humidity"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="barLabelColor"> |
||||
|
</tb-color-input> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="showBarValue"> |
||||
|
{{ 'widgets.bar-chart.value-on-bar' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<tb-font-settings formControlName="barValueFont" |
||||
|
disabledLineHeight |
||||
|
forceSizeUnit="px" |
||||
|
previewText="45"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="barValueColor"> |
||||
|
</tb-color-input> |
||||
|
</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="20 - 30"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="legendLabelColor"> |
||||
|
</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"> |
||||
|
<div>{{ 'tooltip.value' | translate }}</div> |
||||
|
<div fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<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 column-xs"> |
||||
|
<mat-slide-toggle class="mat-slide fixed-title-width" formControlName="tooltipShowDate"> |
||||
|
{{ 'tooltip.date' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
<div fxFlex.gt-xs fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="8px"> |
||||
|
<tb-date-format-select fxFlex excludeLastUpdateAgo formControlName="tooltipDateFormat"></tb-date-format-select> |
||||
|
<tb-font-settings formControlName="tooltipDateFont" |
||||
|
[previewText]="tooltipDatePreviewFn"> |
||||
|
</tb-font-settings> |
||||
|
<tb-color-input asBoxInput |
||||
|
colorClearButton |
||||
|
formControlName="tooltipDateColor"> |
||||
|
</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> |
||||
|
<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,170 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2023 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, Injector } from '@angular/core'; |
||||
|
import { |
||||
|
legendPositions, |
||||
|
legendPositionTranslationMap, |
||||
|
WidgetSettings, |
||||
|
WidgetSettingsComponent |
||||
|
} from '@shared/models/widget.models'; |
||||
|
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { formatValue } from '@core/utils'; |
||||
|
import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models'; |
||||
|
import { |
||||
|
barChartWithLabelsDefaultSettings |
||||
|
} from '@home/components/widget/lib/chart/bar-chart-with-labels-widget.models'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-bar-chart-with-labels-widget-settings', |
||||
|
templateUrl: './bar-chart-with-labels-widget-settings.component.html', |
||||
|
styleUrls: [] |
||||
|
}) |
||||
|
export class BarChartWithLabelsWidgetSettingsComponent extends WidgetSettingsComponent { |
||||
|
|
||||
|
legendPositions = legendPositions; |
||||
|
|
||||
|
legendPositionTranslationMap = legendPositionTranslationMap; |
||||
|
|
||||
|
barChartWidgetSettingsForm: UntypedFormGroup; |
||||
|
|
||||
|
tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); |
||||
|
|
||||
|
tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
private $injector: Injector, |
||||
|
private fb: UntypedFormBuilder) { |
||||
|
super(store); |
||||
|
} |
||||
|
|
||||
|
protected settingsForm(): UntypedFormGroup { |
||||
|
return this.barChartWidgetSettingsForm; |
||||
|
} |
||||
|
|
||||
|
protected defaultSettings(): WidgetSettings { |
||||
|
return {...barChartWithLabelsDefaultSettings}; |
||||
|
} |
||||
|
|
||||
|
protected onSettingsSet(settings: WidgetSettings) { |
||||
|
this.barChartWidgetSettingsForm = this.fb.group({ |
||||
|
|
||||
|
showBarLabel: [settings.showBarLabel, []], |
||||
|
barLabelFont: [settings.barLabelFont, []], |
||||
|
barLabelColor: [settings.barLabelColor, []], |
||||
|
showBarValue: [settings.showBarValue, []], |
||||
|
barValueFont: [settings.barValueFont, []], |
||||
|
barValueColor: [settings.barValueColor, []], |
||||
|
|
||||
|
showLegend: [settings.showLegend, []], |
||||
|
legendPosition: [settings.legendPosition, []], |
||||
|
legendLabelFont: [settings.legendLabelFont, []], |
||||
|
legendLabelColor: [settings.legendLabelColor, []], |
||||
|
|
||||
|
showTooltip: [settings.showTooltip, []], |
||||
|
tooltipValueFont: [settings.tooltipValueFont, []], |
||||
|
tooltipValueColor: [settings.tooltipValueColor, []], |
||||
|
tooltipShowDate: [settings.tooltipShowDate, []], |
||||
|
tooltipDateFormat: [settings.tooltipDateFormat, []], |
||||
|
tooltipDateFont: [settings.tooltipDateFont, []], |
||||
|
tooltipDateColor: [settings.tooltipDateColor, []], |
||||
|
tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], |
||||
|
tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], |
||||
|
|
||||
|
background: [settings.background, []] |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
protected validatorTriggers(): string[] { |
||||
|
return ['showBarLabel', 'showBarValue', 'showLegend', 'showTooltip', 'tooltipShowDate']; |
||||
|
} |
||||
|
|
||||
|
protected updateValidators(emitEvent: boolean) { |
||||
|
const showBarLabel: boolean = this.barChartWidgetSettingsForm.get('showBarLabel').value; |
||||
|
const showBarValue: boolean = this.barChartWidgetSettingsForm.get('showBarValue').value; |
||||
|
const showLegend: boolean = this.barChartWidgetSettingsForm.get('showLegend').value; |
||||
|
const showTooltip: boolean = this.barChartWidgetSettingsForm.get('showTooltip').value; |
||||
|
const tooltipShowDate: boolean = this.barChartWidgetSettingsForm.get('tooltipShowDate').value; |
||||
|
|
||||
|
if (showBarLabel) { |
||||
|
this.barChartWidgetSettingsForm.get('barLabelFont').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('barLabelColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetSettingsForm.get('barLabelFont').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('barLabelColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showBarValue) { |
||||
|
this.barChartWidgetSettingsForm.get('barValueFont').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('barValueColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetSettingsForm.get('barValueFont').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('barValueColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showLegend) { |
||||
|
this.barChartWidgetSettingsForm.get('legendPosition').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('legendLabelFont').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('legendLabelColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetSettingsForm.get('legendPosition').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('legendLabelFont').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('legendLabelColor').disable(); |
||||
|
} |
||||
|
|
||||
|
if (showTooltip) { |
||||
|
this.barChartWidgetSettingsForm.get('tooltipValueFont').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipValueColor').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipShowDate').enable({emitEvent: false}); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').enable(); |
||||
|
if (tooltipShowDate) { |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateFormat').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateFont').enable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateColor').enable(); |
||||
|
} else { |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateFormat').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateFont').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateColor').disable(); |
||||
|
} |
||||
|
} else { |
||||
|
this.barChartWidgetSettingsForm.get('tooltipValueFont').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipValueColor').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipShowDate').disable({emitEvent: false}); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateFormat').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateFont').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipDateColor').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipBackgroundColor').disable(); |
||||
|
this.barChartWidgetSettingsForm.get('tooltipBackgroundBlur').disable(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private _tooltipValuePreviewFn(): string { |
||||
|
const units: string = this.widgetConfig.config.units; |
||||
|
const decimals: number = this.widgetConfig.config.decimals; |
||||
|
return formatValue(22, decimals, units, false); |
||||
|
} |
||||
|
|
||||
|
private _tooltipDatePreviewFn(): string { |
||||
|
const dateFormat: DateFormatSettings = this.barChartWidgetSettingsForm.get('tooltipDateFormat').value; |
||||
|
const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); |
||||
|
processor.update(Date.now()); |
||||
|
return processor.formatted; |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue