|
|
@ -14,37 +14,27 @@ |
|
|
/// limitations under the License.
|
|
|
/// limitations under the License.
|
|
|
///
|
|
|
///
|
|
|
|
|
|
|
|
|
import { Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; |
|
|
import { ChangeDetectorRef, Component, ElementRef, Input, OnDestroy, OnInit, ViewChild } from '@angular/core'; |
|
|
import { PageComponent } from '@shared/components/page.component'; |
|
|
|
|
|
import { WidgetContext } from '@home/models/widget-component.models'; |
|
|
import { WidgetContext } from '@home/models/widget-component.models'; |
|
|
import { UtilsService } from '@core/services/utils.service'; |
|
|
import { deepClone, isDefined } from '@core/utils'; |
|
|
import { Store } from '@ngrx/store'; |
|
|
|
|
|
import { AppState } from '@core/core.state'; |
|
|
|
|
|
import { isDefined, isNumber } from '@core/utils'; |
|
|
|
|
|
import { CanvasDigitalGaugeOptions } from '@home/components/widget/lib/canvas-digital-gauge'; |
|
|
import { CanvasDigitalGaugeOptions } from '@home/components/widget/lib/canvas-digital-gauge'; |
|
|
import tinycolor from 'tinycolor2'; |
|
|
import tinycolor from 'tinycolor2'; |
|
|
import { ColorProcessor, gradientColor } from '@shared/models/widget-settings.models'; |
|
|
import { ColorProcessor, gradientColor, ValueFormatProcessor } from '@shared/models/widget-settings.models'; |
|
|
import { getSourceTbUnitSymbol } from '@shared/models/unit.models'; |
|
|
import { |
|
|
|
|
|
KnobSettings, |
|
|
|
|
|
knobWidgetDefaultSettings, |
|
|
|
|
|
prepareKnobSettings |
|
|
|
|
|
} from '@shared/models/widget/rpc/knob.component.models'; |
|
|
|
|
|
import { ValueType } from '@shared/models/constants'; |
|
|
|
|
|
import { BasicActionWidgetComponent, ValueSetter } from '@home/components/widget/lib/action/action-widget.models'; |
|
|
import GenericOptions = CanvasGauges.GenericOptions; |
|
|
import GenericOptions = CanvasGauges.GenericOptions; |
|
|
|
|
|
|
|
|
interface KnobSettings { |
|
|
|
|
|
minValue: number; |
|
|
|
|
|
maxValue: number; |
|
|
|
|
|
initialValue: number; |
|
|
|
|
|
title: string; |
|
|
|
|
|
getValueMethod: string; |
|
|
|
|
|
setValueMethod: string; |
|
|
|
|
|
requestTimeout: number; |
|
|
|
|
|
requestPersistent: boolean; |
|
|
|
|
|
persistentPollingInterval: number; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Component({ |
|
|
@Component({ |
|
|
selector: 'tb-knob', |
|
|
selector: 'tb-knob', |
|
|
templateUrl: './knob.component.html', |
|
|
templateUrl: './knob.component.html', |
|
|
styleUrls: ['./knob.component.scss'] |
|
|
styleUrls: ['./knob.component.scss'] |
|
|
}) |
|
|
}) |
|
|
export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
export class KnobComponent extends BasicActionWidgetComponent implements OnInit, OnDestroy { |
|
|
|
|
|
|
|
|
@ViewChild('knob', {static: true}) knobRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knob', {static: true}) knobRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobContainer', {static: true}) knobContainerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobContainer', {static: true}) knobContainerRef: ElementRef<HTMLElement>; |
|
|
@ -52,8 +42,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
@ViewChild('knobTopPointer', {static: true}) knobTopPointerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobTopPointer', {static: true}) knobTopPointerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobValueContainer', {static: true}) knobValueContainerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobValueContainer', {static: true}) knobValueContainerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobValue', {static: true}) knobValueRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobValue', {static: true}) knobValueRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobErrorContainer', {static: true}) knobErrorContainerRef: ElementRef<HTMLElement>; |
|
|
|
|
|
@ViewChild('knobError', {static: true}) knobErrorRef: ElementRef<HTMLElement>; |
|
|
|
|
|
@ViewChild('knobTitleContainer', {static: true}) knobTitleContainerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobTitleContainer', {static: true}) knobTitleContainerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobTitle', {static: true}) knobTitleRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobTitle', {static: true}) knobTitleRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobMinmaxContainer', {static: true}) knobMinmaxContainerRef: ElementRef<HTMLElement>; |
|
|
@ViewChild('knobMinmaxContainer', {static: true}) knobMinmaxContainerRef: ElementRef<HTMLElement>; |
|
|
@ -64,7 +52,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
ctx: WidgetContext; |
|
|
ctx: WidgetContext; |
|
|
|
|
|
|
|
|
value = '0'; |
|
|
value = '0'; |
|
|
error = ''; |
|
|
|
|
|
title = ''; |
|
|
title = ''; |
|
|
minValue: number; |
|
|
minValue: number; |
|
|
maxValue: number; |
|
|
maxValue: number; |
|
|
@ -79,13 +66,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
private minDeg = -45; |
|
|
private minDeg = -45; |
|
|
private maxDeg = 225; |
|
|
private maxDeg = 225; |
|
|
|
|
|
|
|
|
private isSimulated: boolean; |
|
|
|
|
|
private requestTimeout: number; |
|
|
|
|
|
private requestPersistent: boolean; |
|
|
|
|
|
private persistentPollingInterval: number; |
|
|
|
|
|
private getValueMethod: string; |
|
|
|
|
|
private setValueMethod: string; |
|
|
|
|
|
|
|
|
|
|
|
private executingUpdateValue: boolean; |
|
|
private executingUpdateValue: boolean; |
|
|
private scheduledValue: number; |
|
|
private scheduledValue: number; |
|
|
private rpcValue: number; |
|
|
private rpcValue: number; |
|
|
@ -98,8 +78,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
private knobValue: JQuery<HTMLElement>; |
|
|
private knobValue: JQuery<HTMLElement>; |
|
|
private knobTitleContainer: JQuery<HTMLElement>; |
|
|
private knobTitleContainer: JQuery<HTMLElement>; |
|
|
private knobTitle: JQuery<HTMLElement>; |
|
|
private knobTitle: JQuery<HTMLElement>; |
|
|
private knobErrorContainer: JQuery<HTMLElement>; |
|
|
|
|
|
private knobError: JQuery<HTMLElement>; |
|
|
|
|
|
private knobMinmaxContainer: JQuery<HTMLElement>; |
|
|
private knobMinmaxContainer: JQuery<HTMLElement>; |
|
|
private minmaxLabel: JQuery<HTMLElement>; |
|
|
private minmaxLabel: JQuery<HTMLElement>; |
|
|
private textMeasure: JQuery<HTMLElement>; |
|
|
private textMeasure: JQuery<HTMLElement>; |
|
|
@ -109,9 +87,11 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
|
|
|
|
|
|
private knobResize$: ResizeObserver; |
|
|
private knobResize$: ResizeObserver; |
|
|
|
|
|
|
|
|
constructor(private utils: UtilsService, |
|
|
private valueSetter: ValueSetter<number>; |
|
|
protected store: Store<AppState>) { |
|
|
private valueFormat: ValueFormatProcessor; |
|
|
super(store); |
|
|
|
|
|
|
|
|
constructor(protected cd: ChangeDetectorRef) { |
|
|
|
|
|
super(cd); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ngOnInit(): void { |
|
|
ngOnInit(): void { |
|
|
@ -123,8 +103,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
this.knobValue = $(this.knobValueRef.nativeElement); |
|
|
this.knobValue = $(this.knobValueRef.nativeElement); |
|
|
this.knobTitleContainer = $(this.knobTitleContainerRef.nativeElement); |
|
|
this.knobTitleContainer = $(this.knobTitleContainerRef.nativeElement); |
|
|
this.knobTitle = $(this.knobTitleRef.nativeElement); |
|
|
this.knobTitle = $(this.knobTitleRef.nativeElement); |
|
|
this.knobErrorContainer = $(this.knobErrorContainerRef.nativeElement); |
|
|
|
|
|
this.knobError = $(this.knobErrorRef.nativeElement); |
|
|
|
|
|
this.knobMinmaxContainer = $(this.knobMinmaxContainerRef.nativeElement); |
|
|
this.knobMinmaxContainer = $(this.knobMinmaxContainerRef.nativeElement); |
|
|
this.minmaxLabel = this.knobMinmaxContainer.find<HTMLElement>('.minmax-label'); |
|
|
this.minmaxLabel = this.knobMinmaxContainer.find<HTMLElement>('.minmax-label'); |
|
|
this.textMeasure = $(this.textMeasureRef.nativeElement); |
|
|
this.textMeasure = $(this.textMeasureRef.nativeElement); |
|
|
@ -145,7 +123,31 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private init() { |
|
|
private init() { |
|
|
const settings: KnobSettings = this.ctx.settings; |
|
|
const settings: KnobSettings = prepareKnobSettings({...deepClone(knobWidgetDefaultSettings), ...this.ctx.settings}); |
|
|
|
|
|
|
|
|
|
|
|
let initialValue = isDefined(settings.initialValue) ? settings.initialValue : this.minValue; |
|
|
|
|
|
|
|
|
|
|
|
const getInitialStateSettings = |
|
|
|
|
|
{...settings.initialState, actionLabel: this.ctx.translate.instant('widgets.slider.initial-value')}; |
|
|
|
|
|
this.createValueGetter(getInitialStateSettings, ValueType.DOUBLE, { |
|
|
|
|
|
next: (value) => { |
|
|
|
|
|
if (this.canvasBar) { |
|
|
|
|
|
this.setValue(value); |
|
|
|
|
|
} else { |
|
|
|
|
|
initialValue = value; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
const valueChangeSettings = {...settings.valueChange, |
|
|
|
|
|
actionLabel: this.ctx.translate.instant('widgets.slider.on-value-change')}; |
|
|
|
|
|
this.valueSetter = this.createValueSetter(valueChangeSettings); |
|
|
|
|
|
|
|
|
|
|
|
this.valueFormat = ValueFormatProcessor.fromSettings(this.ctx.$injector, { |
|
|
|
|
|
units: this.ctx.units, |
|
|
|
|
|
decimals: this.ctx.decimals, |
|
|
|
|
|
showZeroDecimals: true |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
this.minValue = isDefined(settings.minValue) ? settings.minValue : 0; |
|
|
this.minValue = isDefined(settings.minValue) ? settings.minValue : 0; |
|
|
this.maxValue = isDefined(settings.maxValue) ? settings.maxValue : 100; |
|
|
this.maxValue = isDefined(settings.maxValue) ? settings.maxValue : 100; |
|
|
@ -279,44 +281,10 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
|
|
|
|
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const subscription = this.ctx.defaultSubscription; |
|
|
|
|
|
const rpcEnabled = subscription.rpcEnabled; |
|
|
|
|
|
|
|
|
|
|
|
this.isSimulated = this.utils.widgetEditMode; |
|
|
|
|
|
|
|
|
|
|
|
this.requestTimeout = 500; |
|
|
|
|
|
if (settings.requestTimeout) { |
|
|
|
|
|
this.requestTimeout = settings.requestTimeout; |
|
|
|
|
|
} |
|
|
|
|
|
this.requestPersistent = false; |
|
|
|
|
|
if (settings.requestPersistent) { |
|
|
|
|
|
this.requestPersistent = settings.requestPersistent; |
|
|
|
|
|
} |
|
|
|
|
|
this.persistentPollingInterval = 5000; |
|
|
|
|
|
if (settings.persistentPollingInterval) { |
|
|
|
|
|
this.persistentPollingInterval = settings.persistentPollingInterval; |
|
|
|
|
|
} |
|
|
|
|
|
this.getValueMethod = 'getValue'; |
|
|
|
|
|
if (settings.getValueMethod && settings.getValueMethod.length) { |
|
|
|
|
|
this.getValueMethod = settings.getValueMethod; |
|
|
|
|
|
} |
|
|
|
|
|
this.setValueMethod = 'setValue'; |
|
|
|
|
|
if (settings.setValueMethod && settings.setValueMethod.length) { |
|
|
|
|
|
this.setValueMethod = settings.setValueMethod; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
import('@home/components/widget/lib/canvas-digital-gauge').then( |
|
|
import('@home/components/widget/lib/canvas-digital-gauge').then( |
|
|
(gauge) => { |
|
|
(gauge) => { |
|
|
this.canvasBar = new gauge.CanvasDigitalGauge(canvasBarData).draw(); |
|
|
this.canvasBar = new gauge.CanvasDigitalGauge(canvasBarData).draw(); |
|
|
const initialValue = isDefined(settings.initialValue) ? settings.initialValue : this.minValue; |
|
|
|
|
|
this.setValue(initialValue); |
|
|
this.setValue(initialValue); |
|
|
if (!rpcEnabled) { |
|
|
|
|
|
this.onError('Target device is not set!'); |
|
|
|
|
|
} else { |
|
|
|
|
|
if (!this.isSimulated) { |
|
|
|
|
|
this.rpcRequestValue(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
); |
|
|
); |
|
|
|
|
|
|
|
|
@ -348,7 +316,6 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
this.canvasBar.update({width: size, height: size} as GenericOptions); |
|
|
this.canvasBar.update({width: size, height: size} as GenericOptions); |
|
|
} |
|
|
} |
|
|
this.setFontSize(this.knobTitle, this.title, this.knobTitleContainer.height(), this.knobTitleContainer.width()); |
|
|
this.setFontSize(this.knobTitle, this.title, this.knobTitleContainer.height(), this.knobTitleContainer.width()); |
|
|
this.setFontSize(this.knobError, this.error, this.knobErrorContainer.height(), this.knobErrorContainer.width()); |
|
|
|
|
|
const minmaxHeight = this.knobMinmaxContainer.height(); |
|
|
const minmaxHeight = this.knobMinmaxContainer.height(); |
|
|
this.minmaxLabel.css({fontSize: minmaxHeight + 'px', lineHeight: minmaxHeight + 'px'}); |
|
|
this.minmaxLabel.css({fontSize: minmaxHeight + 'px', lineHeight: minmaxHeight + 'px'}); |
|
|
this.checkValueSize(); |
|
|
this.checkValueSize(); |
|
|
@ -408,27 +375,7 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private formatValue(value: any): string { |
|
|
private formatValue(value: any): string { |
|
|
return this.ctx.utils.formatValue(value, this.ctx.decimals, getSourceTbUnitSymbol(this.ctx.units), true); |
|
|
return this.valueFormat.format(value); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private rpcRequestValue() { |
|
|
|
|
|
this.error = ''; |
|
|
|
|
|
this.ctx.controlApi.sendTwoWayCommand(this.getValueMethod, null, this.requestTimeout, |
|
|
|
|
|
this.requestPersistent, this.persistentPollingInterval).subscribe( |
|
|
|
|
|
(responseBody) => { |
|
|
|
|
|
if (isNumber(responseBody)) { |
|
|
|
|
|
const numValue = Number(Number(responseBody).toFixed(this.ctx.decimals)); |
|
|
|
|
|
this.setValue(numValue); |
|
|
|
|
|
} else { |
|
|
|
|
|
const errorText = `Unable to parse response: ${responseBody}`; |
|
|
|
|
|
this.onError(errorText); |
|
|
|
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
() => { |
|
|
|
|
|
const errorText = this.ctx.defaultSubscription.rpcErrorText; |
|
|
|
|
|
this.onError(errorText); |
|
|
|
|
|
} |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private rpcUpdateValue(value: number) { |
|
|
private rpcUpdateValue(value: number) { |
|
|
@ -440,27 +387,19 @@ export class KnobComponent extends PageComponent implements OnInit, OnDestroy { |
|
|
this.rpcValue = value; |
|
|
this.rpcValue = value; |
|
|
this.executingUpdateValue = true; |
|
|
this.executingUpdateValue = true; |
|
|
} |
|
|
} |
|
|
this.error = ''; |
|
|
if (!this.ctx.isEdit && !this.ctx.isPreview) { |
|
|
this.ctx.controlApi.sendOneWayCommand(this.setValueMethod, value, this.requestTimeout, |
|
|
this.updateValue(this.valueSetter, value, { |
|
|
this.requestPersistent, this.persistentPollingInterval).subscribe( |
|
|
next: () => { |
|
|
() => { |
|
|
this.executingUpdateValue = false; |
|
|
this.executingUpdateValue = false; |
|
|
if (this.scheduledValue != null && this.scheduledValue !== this.rpcValue) { |
|
|
if (this.scheduledValue != null && this.scheduledValue !== this.rpcValue) { |
|
|
this.rpcUpdateValue(this.scheduledValue); |
|
|
this.rpcUpdateValue(this.scheduledValue); |
|
|
} |
|
|
|
|
|
}, |
|
|
|
|
|
error: () => { |
|
|
|
|
|
this.executingUpdateValue = false; |
|
|
} |
|
|
} |
|
|
}, |
|
|
}); |
|
|
() => { |
|
|
} |
|
|
this.executingUpdateValue = false; |
|
|
|
|
|
const errorText = this.ctx.defaultSubscription.rpcErrorText; |
|
|
|
|
|
this.onError(errorText); |
|
|
|
|
|
} |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private onError(error: string) { |
|
|
|
|
|
this.error = error; |
|
|
|
|
|
this.setFontSize(this.knobError, this.error, this.knobErrorContainer.height(), this.knobErrorContainer.width()); |
|
|
|
|
|
this.ctx.detectChanges(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|