Merge pull request #9484 from ArtemDzhereleiko/AD/imp/color-range-setting
Color range setting
This commit is contained in:
commit
410f67a55c
@ -0,0 +1,50 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<div *ngIf="panelTitle" class="tb-form-panel-title">{{ panelTitle }}</div>
|
||||||
|
<div class="tb-color-ranges" [formGroup]="colorRangeListFormGroup">
|
||||||
|
<div class="tb-form-row no-padding no-border" [formGroup]="rangeFormGroup" *ngFor="let rangeFormGroup of rangeListFormGroups; trackBy: trackByRange; let $index = index;">
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutGap="24px">
|
||||||
|
<div fxFlex fxLayout="row" fxLayoutGap="12px" fxLayoutAlign="start center">
|
||||||
|
<div class="tb-value-range-text" translate>widgets.color.from</div>
|
||||||
|
<mat-form-field fxFlex appearance="outline" class="center number" subscriptSizing="dynamic">
|
||||||
|
<input matInput type="number" formControlName="from" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
|
</mat-form-field>
|
||||||
|
<div class="tb-value-range-text tb-value-range-text-to" translate>widgets.color.to</div>
|
||||||
|
<mat-form-field fxFlex appearance="outline" class="center number" subscriptSizing="dynamic">
|
||||||
|
<input matInput type="number" formControlName="to" placeholder="{{ 'widget-config.set' | translate }}">
|
||||||
|
</mat-form-field>
|
||||||
|
<tb-color-input asBoxInput
|
||||||
|
formControlName="color">
|
||||||
|
</tb-color-input>
|
||||||
|
</div>
|
||||||
|
<button type="button"
|
||||||
|
mat-icon-button
|
||||||
|
class="tb-box-button"
|
||||||
|
(click)="removeRange($index)"
|
||||||
|
matTooltip="{{ 'action.remove' | translate }}"
|
||||||
|
matTooltipPosition="above">
|
||||||
|
<mat-icon>delete</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="tb-add-color-range"
|
||||||
|
mat-stroked-button
|
||||||
|
(click)="addRange()">
|
||||||
|
<mat-icon>add</mat-icon>
|
||||||
|
</button>
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
///
|
||||||
|
/// 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, forwardRef, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
|
import {
|
||||||
|
AbstractControl,
|
||||||
|
ControlValueAccessor,
|
||||||
|
FormGroup,
|
||||||
|
NG_VALUE_ACCESSOR,
|
||||||
|
UntypedFormArray,
|
||||||
|
UntypedFormBuilder,
|
||||||
|
UntypedFormGroup
|
||||||
|
} from '@angular/forms';
|
||||||
|
import { ColorRange } from '@shared/models/widget-settings.models';
|
||||||
|
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-color-range-list',
|
||||||
|
templateUrl: './color-range-list.component.html',
|
||||||
|
styleUrls: ['color-settings-panel.component.scss'],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => ColorRangeListComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class ColorRangeListComponent implements OnInit, ControlValueAccessor, OnDestroy {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
popover: TbPopoverComponent;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
panelTitle: string;
|
||||||
|
|
||||||
|
modelValue: any;
|
||||||
|
|
||||||
|
colorRangeListFormGroup: UntypedFormGroup;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
|
private propagateChange = null;
|
||||||
|
|
||||||
|
constructor(private fb: UntypedFormBuilder) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.colorRangeListFormGroup = this.fb.group({
|
||||||
|
rangeList: this.fb.array([])
|
||||||
|
});
|
||||||
|
|
||||||
|
this.colorRangeListFormGroup.valueChanges.pipe(
|
||||||
|
takeUntil(this.destroy$)
|
||||||
|
).subscribe(() => this.updateModel());
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: any): void {
|
||||||
|
if (value && value?.length) {
|
||||||
|
value.forEach((r) => this.rangeListFormArray.push(this.colorRangeControl(r), {emitEvent: false}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private colorRangeControl(range: ColorRange): UntypedFormGroup {
|
||||||
|
return this.fb.group({
|
||||||
|
from: [range?.from, []],
|
||||||
|
to: [range?.to, []],
|
||||||
|
color: [range?.color, []]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get rangeListFormArray(): UntypedFormArray {
|
||||||
|
return this.colorRangeListFormGroup.get('rangeList') as UntypedFormArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
get rangeListFormGroups(): FormGroup[] {
|
||||||
|
return this.rangeListFormArray.controls as FormGroup[];
|
||||||
|
}
|
||||||
|
|
||||||
|
trackByRange(index: number, rangeControl: AbstractControl): any {
|
||||||
|
return rangeControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
removeRange(index: number) {
|
||||||
|
this.rangeListFormArray.removeAt(index);
|
||||||
|
this.colorRangeListFormGroup.markAsDirty();
|
||||||
|
setTimeout(() => {this.popover?.updatePosition();}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
addRange() {
|
||||||
|
const newRange: ColorRange = {
|
||||||
|
color: 'rgba(0,0,0,0.87)'
|
||||||
|
};
|
||||||
|
this.rangeListFormArray.push(this.colorRangeControl(newRange));
|
||||||
|
this.colorRangeListFormGroup.markAsDirty();
|
||||||
|
setTimeout(() => {this.popover?.updatePosition();}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateModel() {
|
||||||
|
this.propagateChange(this.colorRangeListFormGroup.get('rangeList').value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<div class="tb-color-settings-panel" [formGroup]="colorRangeFormGroup">
|
||||||
|
<div class="tb-color-settings-title" translate>widgets.color.color-settings</div>
|
||||||
|
<div class="tb-color-settings-panel-body">
|
||||||
|
<tb-color-range-list fxFlex class="tb-color-ranges-panel"
|
||||||
|
formControlName="rangeList"
|
||||||
|
[popover]="popover">
|
||||||
|
</tb-color-range-list>
|
||||||
|
</div>
|
||||||
|
<div class="tb-color-settings-panel-buttons">
|
||||||
|
<button *ngIf="settingsComponents?.length"
|
||||||
|
#copySettingsButton
|
||||||
|
mat-stroked-button
|
||||||
|
color="primary"
|
||||||
|
type="button"
|
||||||
|
[matMenuTriggerFor]="settingsSourcesMenu" [matMenuTriggerData]="{menuWidth: copySettingsButton._elementRef.nativeElement.clientWidth}">
|
||||||
|
{{ 'widgets.color.copy-color-settings-from' | translate }}
|
||||||
|
</button>
|
||||||
|
<mat-menu #settingsSourcesMenu="matMenu">
|
||||||
|
<ng-template matMenuContent let-menuWidth="menuWidth">
|
||||||
|
<div [style.min-width.px]="menuWidth">
|
||||||
|
<button mat-menu-item *ngFor="let comp of settingsComponents" (click)="copyColorSettings(comp)">{{ comp.settingsKey }}</button>
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
</mat-menu>
|
||||||
|
<span fxFlex></span>
|
||||||
|
<button mat-button
|
||||||
|
color="primary"
|
||||||
|
type="button"
|
||||||
|
(click)="cancel()">
|
||||||
|
{{ 'action.cancel' | translate }}
|
||||||
|
</button>
|
||||||
|
<button mat-raised-button
|
||||||
|
color="primary"
|
||||||
|
type="button"
|
||||||
|
(click)="applyColorRangeSettings()"
|
||||||
|
[disabled]="colorRangeFormGroup.invalid || !colorRangeFormGroup.dirty">
|
||||||
|
{{ 'action.apply' | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
///
|
||||||
|
/// 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, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
|
import { ColorRange } from '@shared/models/widget-settings.models';
|
||||||
|
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||||
|
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { AppState } from '@core/core.state';
|
||||||
|
import { deepClone } from '@core/utils';
|
||||||
|
import {
|
||||||
|
ColorRangeSettingsComponent
|
||||||
|
} from '@home/components/widget/lib/settings/common/color-range-settings.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-color-range-panel',
|
||||||
|
templateUrl: './color-range-panel.component.html',
|
||||||
|
providers: [],
|
||||||
|
styleUrls: ['./color-settings-panel.component.scss'],
|
||||||
|
encapsulation: ViewEncapsulation.None
|
||||||
|
})
|
||||||
|
export class ColorRangePanelComponent extends PageComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
colorRangeSettings: Array<ColorRange>;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
popover: TbPopoverComponent<ColorRangePanelComponent>;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
settingsComponents: ColorRangeSettingsComponent[];
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
colorRangeApplied = new EventEmitter<Array<ColorRange>>();
|
||||||
|
|
||||||
|
colorRangeFormGroup: UntypedFormGroup;
|
||||||
|
|
||||||
|
constructor(private fb: UntypedFormBuilder,
|
||||||
|
protected store: Store<AppState>) {
|
||||||
|
super(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.colorRangeFormGroup = this.fb.group({
|
||||||
|
rangeList: [this.colorRangeSettings, []]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
copyColorSettings(comp: ColorRangeSettingsComponent) {
|
||||||
|
this.colorRangeSettings = deepClone(comp.modelValue);
|
||||||
|
this.colorRangeFormGroup.get('rangeList').patchValue(this.colorRangeSettings || [], {emitEvent: false});
|
||||||
|
this.colorRangeFormGroup.markAsDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.popover?.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
applyColorRangeSettings() {
|
||||||
|
const colorRangeSettings = this.colorRangeFormGroup.get('rangeList').value;
|
||||||
|
this.colorRangeApplied.emit(colorRangeSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<button type="button"
|
||||||
|
mat-stroked-button
|
||||||
|
class="tb-box-button"
|
||||||
|
[disabled]="disabled"
|
||||||
|
#matButton
|
||||||
|
(click)="openColorRangeSettingsPopup($event, matButton)">
|
||||||
|
<div class="tb-color-preview box" [ngClass]="{'disabled': disabled}">
|
||||||
|
<div class="tb-color-result" [style]="colorStyle"></div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
@ -0,0 +1,166 @@
|
|||||||
|
///
|
||||||
|
/// 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,
|
||||||
|
forwardRef,
|
||||||
|
Injectable,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Renderer2,
|
||||||
|
ViewContainerRef
|
||||||
|
} from '@angular/core';
|
||||||
|
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
|
||||||
|
import { ColorRange, ComponentStyle } from '@shared/models/widget-settings.models';
|
||||||
|
import { MatButton } from '@angular/material/button';
|
||||||
|
import { TbPopoverService } from '@shared/components/popover.service';
|
||||||
|
import { ColorRangePanelComponent } from '@home/components/widget/lib/settings/common/color-range-panel.component';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ColorRangeSettingsComponentService {
|
||||||
|
|
||||||
|
private colorSettingsComponents = new Set<ColorRangeSettingsComponent>();
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
public registerColorSettingsComponent(comp: ColorRangeSettingsComponent) {
|
||||||
|
this.colorSettingsComponents.add(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unregisterColorSettingsComponent(comp: ColorRangeSettingsComponent) {
|
||||||
|
this.colorSettingsComponents.delete(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getOtherColorSettingsComponents(comp: ColorRangeSettingsComponent): ColorRangeSettingsComponent[] {
|
||||||
|
const result: ColorRangeSettingsComponent[] = [];
|
||||||
|
for (const component of this.colorSettingsComponents.values()) {
|
||||||
|
if (component.settingsKey && component.modelValue && component !== comp) {
|
||||||
|
result.push(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'tb-color-range-settings',
|
||||||
|
templateUrl: './color-range-settings.component.html',
|
||||||
|
styleUrls: [],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: NG_VALUE_ACCESSOR,
|
||||||
|
useExisting: forwardRef(() => ColorRangeSettingsComponent),
|
||||||
|
multi: true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
export class ColorRangeSettingsComponent implements OnInit, ControlValueAccessor, OnDestroy {
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
settingsKey: string;
|
||||||
|
|
||||||
|
modelValue: Array<ColorRange>;
|
||||||
|
|
||||||
|
colorStyle: ComponentStyle = {};
|
||||||
|
|
||||||
|
private propagateChange = null;
|
||||||
|
|
||||||
|
constructor(private popoverService: TbPopoverService,
|
||||||
|
private renderer: Renderer2,
|
||||||
|
private viewContainerRef: ViewContainerRef,
|
||||||
|
private colorSettingsComponentService: ColorRangeSettingsComponentService) {}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.colorSettingsComponentService.registerColorSettingsComponent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy() {
|
||||||
|
this.colorSettingsComponentService.unregisterColorSettingsComponent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnChange(fn: any): void {
|
||||||
|
this.propagateChange = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
registerOnTouched(fn: any): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean): void {
|
||||||
|
this.disabled = isDisabled;
|
||||||
|
this.updateColorStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeValue(value: Array<ColorRange>): void {
|
||||||
|
this.modelValue = value;
|
||||||
|
this.updateColorStyle();
|
||||||
|
}
|
||||||
|
|
||||||
|
openColorRangeSettingsPopup($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 = {
|
||||||
|
colorRangeSettings: this.modelValue,
|
||||||
|
settingsComponents: this.colorSettingsComponentService.getOtherColorSettingsComponents(this)
|
||||||
|
};
|
||||||
|
const colorRangeSettingsPanelPopover = this.popoverService.displayPopover(trigger, this.renderer,
|
||||||
|
this.viewContainerRef, ColorRangePanelComponent, 'left', true, null,
|
||||||
|
ctx,
|
||||||
|
{},
|
||||||
|
{}, {}, true);
|
||||||
|
colorRangeSettingsPanelPopover.tbComponentRef.instance.popover = colorRangeSettingsPanelPopover;
|
||||||
|
colorRangeSettingsPanelPopover.tbComponentRef.instance.colorRangeApplied.subscribe((colorRangeSettings) => {
|
||||||
|
colorRangeSettingsPanelPopover.hide();
|
||||||
|
this.modelValue = colorRangeSettings;
|
||||||
|
this.updateColorStyle();
|
||||||
|
this.propagateChange(this.modelValue);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private updateColorStyle() {
|
||||||
|
if (!this.disabled && this.modelValue) {
|
||||||
|
let colors: string[] = [];
|
||||||
|
if (this.modelValue.length) {
|
||||||
|
const rangeColors = this.modelValue.slice(0, Math.min(3, this.modelValue.length)).map(r => r.color);
|
||||||
|
colors = colors.concat(rangeColors);
|
||||||
|
}
|
||||||
|
if (colors.length === 1) {
|
||||||
|
this.colorStyle = {backgroundColor: colors[0]};
|
||||||
|
} else {
|
||||||
|
const gradientValues: string[] = [];
|
||||||
|
const step = 100 / colors.length;
|
||||||
|
for (let i = 0; i < colors.length; i++) {
|
||||||
|
gradientValues.push(`${colors[i]} ${step*i}%`);
|
||||||
|
gradientValues.push(`${colors[i]} ${step*(i+1)}%`);
|
||||||
|
}
|
||||||
|
this.colorStyle = {background: `linear-gradient(90deg, ${gradientValues.join(', ')})`};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.colorStyle = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -34,7 +34,11 @@
|
|||||||
<div class="tb-color-settings-panel-body" [fxShow]="colorSettingsFormGroup.get('type').value === colorType.constant">
|
<div class="tb-color-settings-panel-body" [fxShow]="colorSettingsFormGroup.get('type').value === colorType.constant">
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-color-settings-panel-body" [fxShow]="colorSettingsFormGroup.get('type').value === colorType.range">
|
<div class="tb-color-settings-panel-body" [fxShow]="colorSettingsFormGroup.get('type').value === colorType.range">
|
||||||
<ng-container *ngTemplateOutlet="range"></ng-container>
|
<tb-color-range-list fxFlex class="tb-color-ranges-panel"
|
||||||
|
formControlName="rangeList"
|
||||||
|
panelTitle="{{ 'widgets.color.value-range' | translate }}"
|
||||||
|
[popover]="popover">
|
||||||
|
</tb-color-range-list>
|
||||||
</div>
|
</div>
|
||||||
<div class="tb-color-settings-panel-body" [fxShow]="colorSettingsFormGroup.get('type').value === colorType.function">
|
<div class="tb-color-settings-panel-body" [fxShow]="colorSettingsFormGroup.get('type').value === colorType.function">
|
||||||
<ng-container *ngTemplateOutlet="function"></ng-container>
|
<ng-container *ngTemplateOutlet="function"></ng-container>
|
||||||
@ -72,43 +76,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template #range>
|
|
||||||
<div fxFlex class="tb-color-ranges-panel">
|
|
||||||
<div class="tb-form-panel-title" translate>widgets.color.value-range</div>
|
|
||||||
<div class="tb-color-ranges" [formGroup]="colorSettingsFormGroup">
|
|
||||||
<div class="tb-form-row no-padding no-border" [formGroup]="rangeFormGroup" *ngFor="let rangeFormGroup of rangeListFormGroups; trackBy: trackByRange; let $index = index;">
|
|
||||||
<div fxFlex fxLayout="row" fxLayoutGap="24px">
|
|
||||||
<div fxFlex fxLayout="row" fxLayoutGap="12px" fxLayoutAlign="start center">
|
|
||||||
<div class="tb-value-range-text" translate>widgets.color.from</div>
|
|
||||||
<mat-form-field fxFlex appearance="outline" class="center number" subscriptSizing="dynamic">
|
|
||||||
<input matInput type="number" formControlName="from" placeholder="{{ 'widget-config.set' | translate }}">
|
|
||||||
</mat-form-field>
|
|
||||||
<div class="tb-value-range-text tb-value-range-text-to" translate>widgets.color.to</div>
|
|
||||||
<mat-form-field fxFlex appearance="outline" class="center number" subscriptSizing="dynamic">
|
|
||||||
<input matInput type="number" formControlName="to" placeholder="{{ 'widget-config.set' | translate }}">
|
|
||||||
</mat-form-field>
|
|
||||||
<tb-color-input asBoxInput
|
|
||||||
formControlName="color">
|
|
||||||
</tb-color-input>
|
|
||||||
</div>
|
|
||||||
<button type="button"
|
|
||||||
mat-icon-button
|
|
||||||
class="tb-box-button"
|
|
||||||
(click)="removeRange($index)"
|
|
||||||
matTooltip="{{ 'action.remove' | translate }}"
|
|
||||||
matTooltipPosition="above">
|
|
||||||
<mat-icon>delete</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<button class="tb-add-color-range"
|
|
||||||
mat-stroked-button
|
|
||||||
(click)="addRange()">
|
|
||||||
<mat-icon>add</mat-icon>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
<ng-template #function>
|
<ng-template #function>
|
||||||
<div class="tb-form-panel no-padding no-border" [formGroup]="colorSettingsFormGroup">
|
<div class="tb-form-panel no-padding no-border" [formGroup]="colorSettingsFormGroup">
|
||||||
<tb-js-func formControlName="colorFunction"
|
<tb-js-func formControlName="colorFunction"
|
||||||
|
|||||||
@ -16,9 +16,9 @@
|
|||||||
|
|
||||||
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
|
||||||
import { PageComponent } from '@shared/components/page.component';
|
import { PageComponent } from '@shared/components/page.component';
|
||||||
import { ColorRange, ColorSettings, ColorType, colorTypeTranslations } from '@shared/models/widget-settings.models';
|
import { ColorSettings, ColorType, colorTypeTranslations } from '@shared/models/widget-settings.models';
|
||||||
import { TbPopoverComponent } from '@shared/components/popover.component';
|
import { TbPopoverComponent } from '@shared/components/popover.component';
|
||||||
import { AbstractControl, FormGroup, UntypedFormArray, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { AppState } from '@core/core.state';
|
import { AppState } from '@core/core.state';
|
||||||
import { deepClone } from '@core/utils';
|
import { deepClone } from '@core/utils';
|
||||||
@ -67,7 +67,7 @@ export class ColorSettingsPanelComponent extends PageComponent implements OnInit
|
|||||||
{
|
{
|
||||||
type: [this.colorSettings?.type, []],
|
type: [this.colorSettings?.type, []],
|
||||||
color: [this.colorSettings?.color, []],
|
color: [this.colorSettings?.color, []],
|
||||||
rangeList: this.fb.array((this.colorSettings?.rangeList || []).map(r => this.colorRangeControl(r))),
|
rangeList: [this.colorSettings?.rangeList, []],
|
||||||
colorFunction: [this.colorSettings?.colorFunction, []]
|
colorFunction: [this.colorSettings?.colorFunction, []]
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -76,51 +76,15 @@ export class ColorSettingsPanelComponent extends PageComponent implements OnInit
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private colorRangeControl(range: ColorRange): AbstractControl {
|
|
||||||
return this.fb.group({
|
|
||||||
from: [range?.from, []],
|
|
||||||
to: [range?.to, []],
|
|
||||||
color: [range?.color, []]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
get rangeListFormArray(): UntypedFormArray {
|
|
||||||
return this.colorSettingsFormGroup.get('rangeList') as UntypedFormArray;
|
|
||||||
}
|
|
||||||
|
|
||||||
get rangeListFormGroups(): FormGroup[] {
|
|
||||||
return this.rangeListFormArray.controls as FormGroup[];
|
|
||||||
}
|
|
||||||
|
|
||||||
trackByRange(index: number, rangeControl: AbstractControl): any {
|
|
||||||
return rangeControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
removeRange(index: number) {
|
|
||||||
this.rangeListFormArray.removeAt(index);
|
|
||||||
this.colorSettingsFormGroup.markAsDirty();
|
|
||||||
setTimeout(() => {this.popover?.updatePosition();}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
addRange() {
|
|
||||||
const newRange: ColorRange = {
|
|
||||||
color: 'rgba(0,0,0,0.87)'
|
|
||||||
};
|
|
||||||
this.rangeListFormArray.push(this.colorRangeControl(newRange));
|
|
||||||
this.colorSettingsFormGroup.markAsDirty();
|
|
||||||
setTimeout(() => {this.popover?.updatePosition();}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
copyColorSettings(comp: ColorSettingsComponent) {
|
copyColorSettings(comp: ColorSettingsComponent) {
|
||||||
const sourceSettings = deepClone(comp.modelValue);
|
const sourceSettings = deepClone(comp.modelValue);
|
||||||
this.colorSettings = sourceSettings;
|
this.colorSettings = sourceSettings;
|
||||||
this.colorSettingsFormGroup.patchValue({
|
this.colorSettingsFormGroup.patchValue({
|
||||||
type: this.colorSettings.type,
|
type: this.colorSettings.type,
|
||||||
color: this.colorSettings.color,
|
color: this.colorSettings.color,
|
||||||
colorFunction: this.colorSettings.colorFunction
|
colorFunction: this.colorSettings.colorFunction,
|
||||||
|
rangeList: this.colorSettings.rangeList || []
|
||||||
}, {emitEvent: false});
|
}, {emitEvent: false});
|
||||||
this.colorSettingsFormGroup.setControl('rangeList',
|
|
||||||
this.fb.array((this.colorSettings.rangeList || []).map(r => this.colorRangeControl(r))), {emitEvent: false});
|
|
||||||
this.colorSettingsFormGroup.markAsDirty();
|
this.colorSettingsFormGroup.markAsDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -45,7 +45,12 @@ import {
|
|||||||
} from '@home/components/widget/lib/settings/common/background-settings-panel.component';
|
} from '@home/components/widget/lib/settings/common/background-settings-panel.component';
|
||||||
import {
|
import {
|
||||||
CountWidgetSettingsComponent
|
CountWidgetSettingsComponent
|
||||||
} from "@home/components/widget/lib/settings/common/count-widget-settings.component";
|
} from '@home/components/widget/lib/settings/common/count-widget-settings.component';
|
||||||
|
import { ColorRangeListComponent } from '@home/components/widget/lib/settings/common/color-range-list.component';
|
||||||
|
import { ColorRangePanelComponent } from '@home/components/widget/lib/settings/common/color-range-panel.component';
|
||||||
|
import {
|
||||||
|
ColorRangeSettingsComponent, ColorRangeSettingsComponentService
|
||||||
|
} from '@home/components/widget/lib/settings/common/color-range-settings.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@ -63,7 +68,10 @@ import {
|
|||||||
ValueSourceComponent,
|
ValueSourceComponent,
|
||||||
LegendConfigComponent,
|
LegendConfigComponent,
|
||||||
WidgetFontComponent,
|
WidgetFontComponent,
|
||||||
CountWidgetSettingsComponent
|
CountWidgetSettingsComponent,
|
||||||
|
ColorRangeListComponent,
|
||||||
|
ColorRangePanelComponent,
|
||||||
|
ColorRangeSettingsComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@ -85,10 +93,14 @@ import {
|
|||||||
ValueSourceComponent,
|
ValueSourceComponent,
|
||||||
LegendConfigComponent,
|
LegendConfigComponent,
|
||||||
WidgetFontComponent,
|
WidgetFontComponent,
|
||||||
CountWidgetSettingsComponent
|
CountWidgetSettingsComponent,
|
||||||
|
ColorRangeListComponent,
|
||||||
|
ColorRangePanelComponent,
|
||||||
|
ColorRangeSettingsComponent
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ColorSettingsComponentService
|
ColorSettingsComponentService,
|
||||||
|
ColorRangeSettingsComponentService
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class WidgetSettingsCommonModule {
|
export class WidgetSettingsCommonModule {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user