45 changed files with 1818 additions and 213 deletions
@ -0,0 +1,89 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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]="animationSettingsFormGroup"> |
||||
|
<div class="tb-form-panel tb-slide-toggle"> |
||||
|
<mat-expansion-panel class="tb-settings" [(expanded)]="settingsExpanded" |
||||
|
[disabled]="!animationSettingsFormGroup.get('animation').value"> |
||||
|
<mat-expansion-panel-header fxLayout="row wrap"> |
||||
|
<mat-panel-title> |
||||
|
<mat-slide-toggle class="mat-slide" formControlName="animation" (click)="$event.stopPropagation()" |
||||
|
fxLayoutAlign="center"> |
||||
|
{{ 'widgets.time-series-chart.animation.animation' | translate }} |
||||
|
</mat-slide-toggle> |
||||
|
</mat-panel-title> |
||||
|
</mat-expansion-panel-header> |
||||
|
<ng-template matExpansionPanelContent> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div>{{ 'widgets.time-series-chart.animation.animation-threshold' | translate }}</div> |
||||
|
<mat-form-field appearance="outline" class="medium-width number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="animationThreshold" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
<div matSuffix>ms</div> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div>{{ 'widgets.time-series-chart.animation.animation-duration' | translate }}</div> |
||||
|
<mat-form-field appearance="outline" class="medium-width number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="animationDuration" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
<div matSuffix>ms</div> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div translate>widgets.time-series-chart.animation.animation-easing</div> |
||||
|
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic"> |
||||
|
<mat-select formControlName="animationEasing"> |
||||
|
<mat-option *ngFor="let easing of timeSeriesChartAnimationEasings" [value]="easing"> |
||||
|
{{ easing }} |
||||
|
</mat-option> |
||||
|
</mat-select> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div>{{ 'widgets.time-series-chart.animation.animation-delay' | translate }}</div> |
||||
|
<mat-form-field appearance="outline" class="medium-width number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="animationDelay" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
<div matSuffix>ms</div> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div>{{ 'widgets.time-series-chart.animation.update-animation-duration' | translate }}</div> |
||||
|
<mat-form-field appearance="outline" class="medium-width number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="animationDurationUpdate" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
<div matSuffix>ms</div> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div translate>widgets.time-series-chart.animation.update-animation-easing</div> |
||||
|
<mat-form-field class="medium-width" appearance="outline" subscriptSizing="dynamic"> |
||||
|
<mat-select formControlName="animationEasingUpdate"> |
||||
|
<mat-option *ngFor="let easing of timeSeriesChartAnimationEasings" [value]="easing"> |
||||
|
{{ easing }} |
||||
|
</mat-option> |
||||
|
</mat-select> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-form-row space-between column-xs"> |
||||
|
<div>{{ 'widgets.time-series-chart.animation.update-animation-delay' | translate }}</div> |
||||
|
<mat-form-field appearance="outline" class="medium-width number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="animationDelayUpdate" type="number" min="0" step="1" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
<div matSuffix>ms</div> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
</ng-template> |
||||
|
</mat-expansion-panel> |
||||
|
</div> |
||||
|
</ng-container> |
||||
@ -0,0 +1,124 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2024 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Component, forwardRef, Input, OnInit } from '@angular/core'; |
||||
|
import { |
||||
|
ControlValueAccessor, |
||||
|
NG_VALUE_ACCESSOR, |
||||
|
UntypedFormBuilder, |
||||
|
UntypedFormGroup, |
||||
|
Validators |
||||
|
} from '@angular/forms'; |
||||
|
import { |
||||
|
timeSeriesChartAnimationEasings, |
||||
|
TimeSeriesChartAnimationSettings |
||||
|
} from '@home/components/widget/lib/chart/time-series-chart.models'; |
||||
|
import { WidgetService } from '@core/http/widget.service'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-time-series-chart-animation-settings', |
||||
|
templateUrl: './time-series-chart-animation-settings.component.html', |
||||
|
styleUrls: ['./../../widget-settings.scss'], |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => TimeSeriesChartAnimationSettingsComponent), |
||||
|
multi: true |
||||
|
} |
||||
|
] |
||||
|
}) |
||||
|
export class TimeSeriesChartAnimationSettingsComponent implements OnInit, ControlValueAccessor { |
||||
|
|
||||
|
settingsExpanded = false; |
||||
|
|
||||
|
timeSeriesChartAnimationEasings = timeSeriesChartAnimationEasings; |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
private modelValue: TimeSeriesChartAnimationSettings; |
||||
|
|
||||
|
private propagateChange = null; |
||||
|
|
||||
|
public animationSettingsFormGroup: UntypedFormGroup; |
||||
|
|
||||
|
constructor(private fb: UntypedFormBuilder, |
||||
|
private widgetService: WidgetService,) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.animationSettingsFormGroup = this.fb.group({ |
||||
|
animation: [null, []], |
||||
|
animationThreshold: [null, [Validators.min(0)]], |
||||
|
animationDuration: [null, [Validators.min(0)]], |
||||
|
animationEasing: [null, []], |
||||
|
animationDelay: [null, [Validators.min(0)]], |
||||
|
animationDurationUpdate: [null, [Validators.min(0)]], |
||||
|
animationEasingUpdate: [null, []], |
||||
|
animationDelayUpdate: [null, [Validators.min(0)]] |
||||
|
}); |
||||
|
this.animationSettingsFormGroup.valueChanges.subscribe(() => { |
||||
|
this.updateModel(); |
||||
|
}); |
||||
|
this.animationSettingsFormGroup.get('animation').valueChanges |
||||
|
.subscribe(() => { |
||||
|
this.updateValidators(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(_fn: any): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (isDisabled) { |
||||
|
this.animationSettingsFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.animationSettingsFormGroup.enable({emitEvent: false}); |
||||
|
this.updateValidators(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: TimeSeriesChartAnimationSettings): void { |
||||
|
this.modelValue = value; |
||||
|
this.animationSettingsFormGroup.patchValue( |
||||
|
value, {emitEvent: false} |
||||
|
); |
||||
|
this.updateValidators(); |
||||
|
this.animationSettingsFormGroup.get('animation').valueChanges.subscribe((animation) => { |
||||
|
this.settingsExpanded = animation; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private updateValidators() { |
||||
|
const animation: boolean = this.animationSettingsFormGroup.get('animation').value; |
||||
|
if (animation) { |
||||
|
this.animationSettingsFormGroup.enable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.animationSettingsFormGroup.disable({emitEvent: false}); |
||||
|
this.animationSettingsFormGroup.get('animation').enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
this.modelValue = this.animationSettingsFormGroup.getRawValue(); |
||||
|
this.propagateChange(this.modelValue); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<div class="tb-form-panel tb-y-axes-panel"> |
||||
|
<div class="tb-form-panel-title">{{ 'widgets.time-series-chart.y-axes' | translate }}</div> |
||||
|
<div class="tb-form-table"> |
||||
|
<div class="tb-form-table-header no-padding-right"> |
||||
|
<div class="tb-form-table-header-cell tb-axis-id-header" translate>widgets.time-series-chart.axis.id</div> |
||||
|
<div class="tb-form-table-header-cell tb-show-header" translate>widgets.time-series-chart.axis.show</div> |
||||
|
<div class="tb-form-table-header-cell tb-label-header" translate>widgets.time-series-chart.axis.label</div> |
||||
|
<div class="tb-form-table-header-cell tb-position-header" translate>widgets.time-series-chart.axis.position</div> |
||||
|
<div class="tb-form-table-header-cell tb-min-header" translate>widgets.time-series-chart.axis.min</div> |
||||
|
<div class="tb-form-table-header-cell tb-max-header" translate>widgets.time-series-chart.axis.max</div> |
||||
|
<div class="tb-form-table-header-cell tb-units-header" translate>widget-config.units-short</div> |
||||
|
<div class="tb-form-table-header-cell tb-decimals-header" translate>widget-config.decimals-short</div> |
||||
|
<div class="tb-form-table-header-cell tb-actions-header"></div> |
||||
|
</div> |
||||
|
<div class="tb-form-table-body tb-drop-list" |
||||
|
cdkDropList cdkDropListOrientation="vertical" |
||||
|
[cdkDropListDisabled]="!dragEnabled" |
||||
|
(cdkDropListDropped)="axisDrop($event)"> |
||||
|
<div cdkDrag [cdkDragDisabled]="!dragEnabled" |
||||
|
class="tb-draggable-form-table-row" |
||||
|
*ngFor="let axisControl of axesFormArray().controls; trackBy: trackByAxis; let $index = index;"> |
||||
|
<tb-time-series-chart-y-axis-row fxFlex |
||||
|
[formControl]="axisControl" |
||||
|
[advanced]="advanced" |
||||
|
(axisRemoved)="removeAxis($index)"> |
||||
|
</tb-time-series-chart-y-axis-row> |
||||
|
<div class="tb-form-table-row-cell-buttons"> |
||||
|
<button fxHide.lt-lg |
||||
|
mat-icon-button |
||||
|
type="button" |
||||
|
cdkDragHandle |
||||
|
[ngClass]="{'tb-hidden': !dragEnabled}" |
||||
|
matTooltip="{{ 'action.drag' | translate }}" |
||||
|
matTooltipPosition="above"> |
||||
|
<mat-icon>drag_indicator</mat-icon> |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div> |
||||
|
<button type="button" mat-stroked-button color="primary" (click)="addAxis()"> |
||||
|
{{ 'widgets.time-series-chart.axis.add-y-axis' | translate }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,87 @@ |
|||||
|
/** |
||||
|
* 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 '../../../../../../../../../scss/constants'; |
||||
|
|
||||
|
.tb-y-axes-panel { |
||||
|
.tb-form-table-header-cell { |
||||
|
&.tb-axis-id-header { |
||||
|
width: 60px; |
||||
|
min-width: 60px; |
||||
|
} |
||||
|
|
||||
|
&.tb-label-header { |
||||
|
flex: 1 1 60%; |
||||
|
min-width: 100px; |
||||
|
} |
||||
|
|
||||
|
&.tb-position-header { |
||||
|
flex: 1; |
||||
|
min-width: 60px; |
||||
|
@media #{$mat-gt-md} { |
||||
|
flex: 1 1 40%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-units-header { |
||||
|
width: 80px; |
||||
|
min-width: 80px; |
||||
|
} |
||||
|
|
||||
|
&.tb-decimals-header { |
||||
|
width: 60px; |
||||
|
min-width: 60px; |
||||
|
} |
||||
|
|
||||
|
&.tb-min-header, &.tb-max-header { |
||||
|
width: 80px; |
||||
|
min-width: 80px; |
||||
|
} |
||||
|
|
||||
|
&.tb-show-header { |
||||
|
width: 40px; |
||||
|
min-width: 40px; |
||||
|
} |
||||
|
|
||||
|
&.tb-actions-header { |
||||
|
width: 80px; |
||||
|
min-width: 80px; |
||||
|
@media #{$mat-gt-md} { |
||||
|
width: 120px; |
||||
|
min-width: 120px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-label-header, &.tb-units-header, &.tb-decimals-header { |
||||
|
display: none; |
||||
|
@media #{$mat-gt-md} { |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
&.tb-min-header, &.tb-max-header { |
||||
|
display: none; |
||||
|
@media #{$mat-gt-xs} { |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-form-table-body { |
||||
|
tb-time-series-chart-y-axis-row { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,180 @@ |
|||||
|
///
|
||||
|
/// 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, EventEmitter, forwardRef, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; |
||||
|
import { |
||||
|
AbstractControl, |
||||
|
ControlValueAccessor, |
||||
|
NG_VALIDATORS, |
||||
|
NG_VALUE_ACCESSOR, |
||||
|
UntypedFormArray, |
||||
|
UntypedFormBuilder, |
||||
|
UntypedFormControl, |
||||
|
UntypedFormGroup, |
||||
|
Validator |
||||
|
} from '@angular/forms'; |
||||
|
import { |
||||
|
defaultTimeSeriesChartYAxisSettings, |
||||
|
getNextTimeSeriesYAxisId, |
||||
|
TimeSeriesChartYAxes, TimeSeriesChartYAxisId, |
||||
|
TimeSeriesChartYAxisSettings, |
||||
|
timeSeriesChartYAxisValid, |
||||
|
timeSeriesChartYAxisValidator |
||||
|
} from '@home/components/widget/lib/chart/time-series-chart.models'; |
||||
|
import { mergeDeep } from '@core/utils'; |
||||
|
import { CdkDragDrop } from '@angular/cdk/drag-drop'; |
||||
|
import { coerceBoolean } from '@shared/decorators/coercion'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-time-series-chart-y-axes-panel', |
||||
|
templateUrl: './time-series-chart-y-axes-panel.component.html', |
||||
|
styleUrls: ['./time-series-chart-y-axes-panel.component.scss'], |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => TimeSeriesChartYAxesPanelComponent), |
||||
|
multi: true |
||||
|
}, |
||||
|
{ |
||||
|
provide: NG_VALIDATORS, |
||||
|
useExisting: forwardRef(() => TimeSeriesChartYAxesPanelComponent), |
||||
|
multi: true |
||||
|
} |
||||
|
], |
||||
|
encapsulation: ViewEncapsulation.None |
||||
|
}) |
||||
|
export class TimeSeriesChartYAxesPanelComponent implements ControlValueAccessor, OnInit, Validator { |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
@Input() |
||||
|
@coerceBoolean() |
||||
|
advanced = false; |
||||
|
|
||||
|
@Output() |
||||
|
axisRemoved = new EventEmitter<TimeSeriesChartYAxisId>(); |
||||
|
|
||||
|
yAxesFormGroup: UntypedFormGroup; |
||||
|
|
||||
|
get dragEnabled(): boolean { |
||||
|
return this.axesFormArray().controls.length > 1; |
||||
|
} |
||||
|
|
||||
|
private propagateChange = (_val: any) => {}; |
||||
|
|
||||
|
constructor(private fb: UntypedFormBuilder) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.yAxesFormGroup = this.fb.group({ |
||||
|
axes: [this.fb.array([]), []] |
||||
|
}); |
||||
|
this.yAxesFormGroup.valueChanges.subscribe( |
||||
|
() => { |
||||
|
let axes: TimeSeriesChartYAxisSettings[] = this.yAxesFormGroup.get('axes').value; |
||||
|
for (let i = 0; i < axes.length; i++) { |
||||
|
axes[i].order = i; |
||||
|
} |
||||
|
if (axes) { |
||||
|
axes = axes.filter(axis => timeSeriesChartYAxisValid(axis)); |
||||
|
} |
||||
|
const yAxes: TimeSeriesChartYAxes = {}; |
||||
|
for (const axis of axes) { |
||||
|
yAxes[axis.id] = axis; |
||||
|
} |
||||
|
this.propagateChange(yAxes); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(fn: any): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (isDisabled) { |
||||
|
this.yAxesFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.yAxesFormGroup.enable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: TimeSeriesChartYAxes | undefined): void { |
||||
|
const yAxes: TimeSeriesChartYAxes = value || {}; |
||||
|
if (!yAxes.default) { |
||||
|
yAxes.default = mergeDeep({} as TimeSeriesChartYAxisSettings, defaultTimeSeriesChartYAxisSettings, |
||||
|
{id: 'default', order: 0} as TimeSeriesChartYAxisSettings); |
||||
|
} |
||||
|
const yAxisSettingsList = Object.values(yAxes); |
||||
|
yAxisSettingsList.sort((a1, a2) => a1.order - a2.order); |
||||
|
this.yAxesFormGroup.setControl('axes', this.prepareAxesFormArray(yAxisSettingsList), {emitEvent: false}); |
||||
|
} |
||||
|
|
||||
|
public validate(c: UntypedFormControl) { |
||||
|
const valid = this.yAxesFormGroup.valid; |
||||
|
return valid ? null : { |
||||
|
yAxes: { |
||||
|
valid: false, |
||||
|
}, |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
axisDrop(event: CdkDragDrop<string[]>) { |
||||
|
const axesArray = this.yAxesFormGroup.get('axes') as UntypedFormArray; |
||||
|
const axis = axesArray.at(event.previousIndex); |
||||
|
axesArray.removeAt(event.previousIndex); |
||||
|
axesArray.insert(event.currentIndex, axis); |
||||
|
} |
||||
|
|
||||
|
axesFormArray(): UntypedFormArray { |
||||
|
return this.yAxesFormGroup.get('axes') as UntypedFormArray; |
||||
|
} |
||||
|
|
||||
|
trackByAxis(index: number, axisControl: AbstractControl): any { |
||||
|
return axisControl; |
||||
|
} |
||||
|
|
||||
|
removeAxis(index: number) { |
||||
|
const axis = |
||||
|
(this.yAxesFormGroup.get('axes') as UntypedFormArray).at(index).value as TimeSeriesChartYAxisSettings; |
||||
|
(this.yAxesFormGroup.get('axes') as UntypedFormArray).removeAt(index); |
||||
|
this.axisRemoved.emit(axis.id); |
||||
|
} |
||||
|
|
||||
|
addAxis() { |
||||
|
const axis = mergeDeep<TimeSeriesChartYAxisSettings>({} as TimeSeriesChartYAxisSettings, |
||||
|
defaultTimeSeriesChartYAxisSettings); |
||||
|
const axes: TimeSeriesChartYAxisSettings[] = this.yAxesFormGroup.get('axes').value; |
||||
|
axis.id = getNextTimeSeriesYAxisId(axes); |
||||
|
axis.order = axes.length; |
||||
|
const axesArray = this.yAxesFormGroup.get('axes') as UntypedFormArray; |
||||
|
const axisControl = this.fb.control(axis, [timeSeriesChartYAxisValidator]); |
||||
|
axesArray.push(axisControl); |
||||
|
} |
||||
|
|
||||
|
private prepareAxesFormArray(axes: TimeSeriesChartYAxisSettings[]): UntypedFormArray { |
||||
|
const axesControls: Array<AbstractControl> = []; |
||||
|
axes.forEach((axis) => { |
||||
|
axesControls.push(this.fb.control(axis, [timeSeriesChartYAxisValidator])); |
||||
|
}); |
||||
|
return this.fb.array(axesControls); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,72 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<div [formGroup]="axisFormGroup" class="tb-form-table-row tb-axis-row"> |
||||
|
<div class="tb-axis-id-field"> |
||||
|
{{ modelValue.id }} |
||||
|
</div> |
||||
|
<mat-checkbox class="tb-show-field" formControlName="show"></mat-checkbox> |
||||
|
<mat-form-field class="tb-inline-field tb-label-field" appearance="outline" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="label" placeholder="{{ 'widget-config.set' | translate }}"> |
||||
|
</mat-form-field> |
||||
|
<mat-form-field class="tb-inline-field tb-position-field" appearance="outline" subscriptSizing="dynamic"> |
||||
|
<mat-select formControlName="position"> |
||||
|
<mat-option *ngFor="let position of axisPositions" [value]="position"> |
||||
|
{{ timeSeriesAxisPositionTranslations.get(position) | translate }} |
||||
|
</mat-option> |
||||
|
</mat-select> |
||||
|
</mat-form-field> |
||||
|
<div class="tb-min-field"> |
||||
|
<mat-form-field appearance="outline" class="tb-inline-field number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="min" type="number" placeholder="{{ 'widgets.time-series-chart.axis.scale-auto' | translate }}"> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-max-field"> |
||||
|
<mat-form-field appearance="outline" class="tb-inline-field number" subscriptSizing="dynamic"> |
||||
|
<input matInput formControlName="max" type="number" placeholder="{{ 'widgets.time-series-chart.axis.scale-auto' | translate }}"> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<div class="tb-units-field"> |
||||
|
<tb-unit-input formControlName="units"> |
||||
|
</tb-unit-input> |
||||
|
</div> |
||||
|
<div class="tb-decimals-field"> |
||||
|
<mat-form-field appearance="outline" class="tb-inline-field 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 class="tb-form-table-row-cell-buttons"> |
||||
|
<button type="button" |
||||
|
mat-icon-button |
||||
|
#matButton |
||||
|
(click)="editAxis($event, matButton)" |
||||
|
matTooltip="{{ 'widgets.time-series-chart.axis.y-axis-settings' | translate }}" |
||||
|
matTooltipPosition="above"> |
||||
|
<mat-icon>settings</mat-icon> |
||||
|
</button> |
||||
|
<div class="tb-remove-button"> |
||||
|
<button *ngIf="modelValue.id !== 'default'" |
||||
|
type="button" |
||||
|
mat-icon-button |
||||
|
(click)="axisRemoved.emit()" |
||||
|
matTooltip="{{ 'widgets.time-series-chart.axis.remove-y-axis' | translate }}" |
||||
|
matTooltipPosition="above"> |
||||
|
<mat-icon>delete</mat-icon> |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,95 @@ |
|||||
|
/** |
||||
|
* 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 '../../../../../../../../../scss/constants'; |
||||
|
|
||||
|
.tb-form-table-row.tb-axis-row { |
||||
|
|
||||
|
.tb-axis-id-field { |
||||
|
color: rgba(0, 0, 0, 0.76); |
||||
|
font-weight: 500; |
||||
|
font-size: 14px; |
||||
|
line-height: 20px; |
||||
|
letter-spacing: 0.2px; |
||||
|
width: 60px; |
||||
|
min-width: 60px; |
||||
|
} |
||||
|
|
||||
|
.tb-label-field { |
||||
|
flex: 1 1 60%; |
||||
|
min-width: 100px; |
||||
|
} |
||||
|
|
||||
|
.tb-position-field { |
||||
|
flex: 1; |
||||
|
min-width: 60px; |
||||
|
@media #{$mat-gt-md} { |
||||
|
flex: 1 1 40%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-units-field, .tb-decimals-field, .tb-min-field, .tb-max-field { |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
place-content: center; |
||||
|
align-items: center; |
||||
|
} |
||||
|
|
||||
|
.tb-units-field { |
||||
|
width: 80px; |
||||
|
min-width: 80px; |
||||
|
} |
||||
|
|
||||
|
.tb-decimals-field { |
||||
|
width: 60px; |
||||
|
min-width: 60px; |
||||
|
} |
||||
|
|
||||
|
.tb-min-field, .tb-max-field { |
||||
|
width: 80px; |
||||
|
min-width: 80px; |
||||
|
} |
||||
|
|
||||
|
.tb-show-field { |
||||
|
width: 40px; |
||||
|
min-width: 40px; |
||||
|
} |
||||
|
|
||||
|
.tb-label-field { |
||||
|
display: none; |
||||
|
@media #{$mat-gt-md} { |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-units-field, .tb-decimals-field { |
||||
|
display: none; |
||||
|
@media #{$mat-gt-md} { |
||||
|
display: flex; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-min-field, .tb-max-field { |
||||
|
display: none; |
||||
|
@media #{$mat-gt-xs} { |
||||
|
display: flex; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.tb-remove-button { |
||||
|
width: 40px; |
||||
|
min-width: 40px; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,201 @@ |
|||||
|
///
|
||||
|
/// 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 { |
||||
|
ChangeDetectorRef, |
||||
|
Component, |
||||
|
EventEmitter, |
||||
|
forwardRef, |
||||
|
Input, |
||||
|
OnInit, |
||||
|
Output, |
||||
|
Renderer2, |
||||
|
ViewContainerRef, |
||||
|
ViewEncapsulation |
||||
|
} from '@angular/core'; |
||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; |
||||
|
import { |
||||
|
AxisPosition, |
||||
|
timeSeriesAxisPositionTranslations, |
||||
|
TimeSeriesChartYAxisSettings |
||||
|
} from '@home/components/widget/lib/chart/time-series-chart.models'; |
||||
|
import { MatButton } from '@angular/material/button'; |
||||
|
import { TbPopoverService } from '@shared/components/popover.service'; |
||||
|
import { coerceBoolean } from '@shared/decorators/coercion'; |
||||
|
import { |
||||
|
TimeSeriesChartYAxisSettingsPanelComponent |
||||
|
} from '@home/components/widget/lib/settings/common/chart/time-series-chart-y-axis-settings-panel.component'; |
||||
|
import { deepClone } from '@core/utils'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-time-series-chart-y-axis-row', |
||||
|
templateUrl: './time-series-chart-y-axis-row.component.html', |
||||
|
styleUrls: ['./time-series-chart-y-axis-row.component.scss'], |
||||
|
providers: [ |
||||
|
{ |
||||
|
provide: NG_VALUE_ACCESSOR, |
||||
|
useExisting: forwardRef(() => TimeSeriesChartYAxisRowComponent), |
||||
|
multi: true |
||||
|
} |
||||
|
], |
||||
|
encapsulation: ViewEncapsulation.None |
||||
|
}) |
||||
|
export class TimeSeriesChartYAxisRowComponent implements ControlValueAccessor, OnInit { |
||||
|
|
||||
|
axisPositions = [AxisPosition.left, AxisPosition.right]; |
||||
|
|
||||
|
timeSeriesAxisPositionTranslations = timeSeriesAxisPositionTranslations; |
||||
|
|
||||
|
@Input() |
||||
|
disabled: boolean; |
||||
|
|
||||
|
@Input() |
||||
|
@coerceBoolean() |
||||
|
advanced = false; |
||||
|
|
||||
|
@Output() |
||||
|
axisRemoved = new EventEmitter(); |
||||
|
|
||||
|
axisFormGroup: UntypedFormGroup; |
||||
|
|
||||
|
modelValue: TimeSeriesChartYAxisSettings; |
||||
|
|
||||
|
private propagateChange = (_val: any) => {}; |
||||
|
|
||||
|
constructor(private fb: UntypedFormBuilder, |
||||
|
private popoverService: TbPopoverService, |
||||
|
private renderer: Renderer2, |
||||
|
private viewContainerRef: ViewContainerRef, |
||||
|
private cd: ChangeDetectorRef) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
this.axisFormGroup = this.fb.group({ |
||||
|
label: [null, []], |
||||
|
position: [null, []], |
||||
|
units: [null, []], |
||||
|
decimals: [null, []], |
||||
|
min: [null, []], |
||||
|
max: [null, []], |
||||
|
show: [null, []] |
||||
|
}); |
||||
|
this.axisFormGroup.valueChanges.subscribe( |
||||
|
() => this.updateModel() |
||||
|
); |
||||
|
this.axisFormGroup.get('show').valueChanges.subscribe(() => { |
||||
|
this.updateValidators(); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
registerOnChange(fn: any): void { |
||||
|
this.propagateChange = fn; |
||||
|
} |
||||
|
|
||||
|
registerOnTouched(_fn: any): void { |
||||
|
} |
||||
|
|
||||
|
setDisabledState(isDisabled: boolean): void { |
||||
|
this.disabled = isDisabled; |
||||
|
if (isDisabled) { |
||||
|
this.axisFormGroup.disable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.axisFormGroup.enable({emitEvent: false}); |
||||
|
this.updateValidators(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
writeValue(value: TimeSeriesChartYAxisSettings): void { |
||||
|
this.modelValue = value; |
||||
|
this.axisFormGroup.patchValue( |
||||
|
{ |
||||
|
label: value.label, |
||||
|
position: value.position, |
||||
|
units: value.units, |
||||
|
decimals: value.decimals, |
||||
|
min: value.min, |
||||
|
max: value.max, |
||||
|
show: value.show, |
||||
|
}, {emitEvent: false} |
||||
|
); |
||||
|
this.updateValidators(); |
||||
|
this.cd.markForCheck(); |
||||
|
} |
||||
|
|
||||
|
editAxis($event: Event, matButton: MatButton) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
const trigger = matButton._elementRef.nativeElement; |
||||
|
if (this.popoverService.hasPopover(trigger)) { |
||||
|
this.popoverService.hidePopover(trigger); |
||||
|
} else { |
||||
|
const ctx: any = { |
||||
|
yAxisSettings: deepClone(this.modelValue), |
||||
|
advanced: this.advanced |
||||
|
}; |
||||
|
const yAxisSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer, |
||||
|
this.viewContainerRef, TimeSeriesChartYAxisSettingsPanelComponent, ['leftOnly', 'leftTopOnly', 'leftBottomOnly'], true, null, |
||||
|
ctx, |
||||
|
{}, |
||||
|
{}, {}, true); |
||||
|
yAxisSettingsPanelPopover.tbComponentRef.instance.popover = yAxisSettingsPanelPopover; |
||||
|
yAxisSettingsPanelPopover.tbComponentRef.instance.yAxisSettingsApplied.subscribe((yAxisSettings) => { |
||||
|
yAxisSettingsPanelPopover.hide(); |
||||
|
this.modelValue = {...this.modelValue, ...yAxisSettings}; |
||||
|
this.axisFormGroup.patchValue( |
||||
|
{ |
||||
|
label: this.modelValue.label, |
||||
|
position: this.modelValue.position, |
||||
|
units: this.modelValue.units, |
||||
|
decimals: this.modelValue.decimals, |
||||
|
min: this.modelValue.min, |
||||
|
max: this.modelValue.max, |
||||
|
show: this.modelValue.show |
||||
|
}, |
||||
|
{emitEvent: false}); |
||||
|
this.updateValidators(); |
||||
|
this.propagateChange(this.modelValue); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private updateValidators() { |
||||
|
const show: boolean = this.axisFormGroup.get('show').value; |
||||
|
if (show) { |
||||
|
this.axisFormGroup.get('label').enable({emitEvent: false}); |
||||
|
this.axisFormGroup.get('position').enable({emitEvent: false}); |
||||
|
this.axisFormGroup.get('units').enable({emitEvent: false}); |
||||
|
this.axisFormGroup.get('decimals').enable({emitEvent: false}); |
||||
|
} else { |
||||
|
this.axisFormGroup.get('label').disable({emitEvent: false}); |
||||
|
this.axisFormGroup.get('position').disable({emitEvent: false}); |
||||
|
this.axisFormGroup.get('units').disable({emitEvent: false}); |
||||
|
this.axisFormGroup.get('decimals').disable({emitEvent: false}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private updateModel() { |
||||
|
const value = this.axisFormGroup.value; |
||||
|
this.modelValue.label = value.label; |
||||
|
this.modelValue.position = value.position; |
||||
|
this.modelValue.units = value.units; |
||||
|
this.modelValue.decimals = value.decimals; |
||||
|
this.modelValue.min = value.min; |
||||
|
this.modelValue.max = value.max; |
||||
|
this.modelValue.show = value.show; |
||||
|
this.propagateChange(this.modelValue); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,43 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<div class="tb-y-axis-settings-panel" [formGroup]="yAxisSettingsFormGroup"> |
||||
|
<div class="tb-y-axis-settings-title">{{ 'widgets.time-series-chart.axis.y-axis-settings' | translate }}</div> |
||||
|
<div class="tb-y-axis-settings-panel-content"> |
||||
|
<tb-time-series-chart-axis-settings |
||||
|
formControlName="yAxis" |
||||
|
alwaysExpanded |
||||
|
[advanced]="advanced" |
||||
|
axisType="yAxis"> |
||||
|
</tb-time-series-chart-axis-settings> |
||||
|
</div> |
||||
|
<div class="tb-y-axis-settings-panel-buttons"> |
||||
|
<button mat-button |
||||
|
color="primary" |
||||
|
type="button" |
||||
|
(click)="cancel()"> |
||||
|
{{ 'action.cancel' | translate }} |
||||
|
</button> |
||||
|
<button mat-raised-button |
||||
|
color="primary" |
||||
|
type="button" |
||||
|
(click)="applyYAxisSettings()" |
||||
|
[disabled]="yAxisSettingsFormGroup.invalid || !yAxisSettingsFormGroup.dirty"> |
||||
|
{{ 'action.apply' | translate }} |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
@ -0,0 +1,49 @@ |
|||||
|
/** |
||||
|
* 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 '../../../../../../../../../scss/constants'; |
||||
|
|
||||
|
.tb-y-axis-settings-panel { |
||||
|
width: 530px; |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 16px; |
||||
|
@media #{$mat-lt-md} { |
||||
|
width: 90vw; |
||||
|
} |
||||
|
.tb-y-axis-settings-panel-content { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
gap: 16px; |
||||
|
overflow: auto; |
||||
|
margin: -10px; |
||||
|
padding: 10px; |
||||
|
} |
||||
|
.tb-y-axis-settings-title { |
||||
|
font-size: 16px; |
||||
|
font-weight: 500; |
||||
|
line-height: 24px; |
||||
|
letter-spacing: 0.25px; |
||||
|
color: rgba(0, 0, 0, 0.87); |
||||
|
} |
||||
|
.tb-y-axis-settings-panel-buttons { |
||||
|
height: 40px; |
||||
|
display: flex; |
||||
|
flex-direction: row; |
||||
|
gap: 16px; |
||||
|
justify-content: flex-end; |
||||
|
align-items: flex-end; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,66 @@ |
|||||
|
///
|
||||
|
/// 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, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; |
||||
|
import { TbPopoverComponent } from '@shared/components/popover.component'; |
||||
|
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; |
||||
|
import { TimeSeriesChartYAxisSettings } from '@home/components/widget/lib/chart/time-series-chart.models'; |
||||
|
import { coerceBoolean } from '@shared/decorators/coercion'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-time-series-chart-y-axis-settings-panel', |
||||
|
templateUrl: './time-series-chart-y-axis-settings-panel.component.html', |
||||
|
providers: [], |
||||
|
styleUrls: ['./time-series-chart-y-axis-settings-panel.component.scss'], |
||||
|
encapsulation: ViewEncapsulation.None |
||||
|
}) |
||||
|
export class TimeSeriesChartYAxisSettingsPanelComponent implements OnInit { |
||||
|
|
||||
|
@Input() |
||||
|
yAxisSettings: TimeSeriesChartYAxisSettings; |
||||
|
|
||||
|
@Input() |
||||
|
@coerceBoolean() |
||||
|
advanced = false; |
||||
|
|
||||
|
@Input() |
||||
|
popover: TbPopoverComponent<TimeSeriesChartYAxisSettingsPanelComponent>; |
||||
|
|
||||
|
@Output() |
||||
|
yAxisSettingsApplied = new EventEmitter<TimeSeriesChartYAxisSettings>(); |
||||
|
|
||||
|
yAxisSettingsFormGroup: UntypedFormGroup; |
||||
|
|
||||
|
constructor(private fb: UntypedFormBuilder) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
this.yAxisSettingsFormGroup = this.fb.group( |
||||
|
{ |
||||
|
yAxis: [this.yAxisSettings, []] |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
cancel() { |
||||
|
this.popover?.hide(); |
||||
|
} |
||||
|
|
||||
|
applyYAxisSettings() { |
||||
|
const yAxisSettings = this.yAxisSettingsFormGroup.get('yAxis').getRawValue(); |
||||
|
this.yAxisSettingsApplied.emit(yAxisSettings); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,19 @@ |
|||||
|
///
|
||||
|
/// 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.
|
||||
|
///
|
||||
|
|
||||
|
export type DeepPartial<T> = T extends object ? { |
||||
|
[P in keyof T]?: DeepPartial<T[P]>; |
||||
|
} : T; |
||||
Loading…
Reference in new issue