committed by
GitHub
9 changed files with 703 additions and 10 deletions
@ -0,0 +1,21 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2017 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 tbKnob from './knob.directive'; |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.rpc', [ |
||||
|
tbKnob |
||||
|
]).name; |
||||
@ -0,0 +1,388 @@ |
|||||
|
/* |
||||
|
* Copyright © 2016-2017 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 './knob.scss'; |
||||
|
|
||||
|
import CanvasDigitalGauge from './../CanvasDigitalGauge'; |
||||
|
import tinycolor from 'tinycolor2'; |
||||
|
|
||||
|
import { isNumber } from '../widget-utils'; |
||||
|
|
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import knobTemplate from './knob.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.rpc.knob', []) |
||||
|
.directive('tbKnob', Knob) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function Knob() { |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
scope: true, |
||||
|
bindToController: { |
||||
|
ctx: '=' |
||||
|
}, |
||||
|
controller: KnobController, |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: knobTemplate |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function KnobController($element, $scope, $document) { |
||||
|
let vm = this; |
||||
|
|
||||
|
vm.value = 0; |
||||
|
vm.error = ''; |
||||
|
|
||||
|
var knob = angular.element('.knob', $element), |
||||
|
knobContainer = angular.element('#knob-container', $element), |
||||
|
knobTopPointerContainer = knob.find('.top-pointer-container'), |
||||
|
knobTopPointer = knob.find('.top-pointer'), |
||||
|
knobValueContainer = knob.find('.value-container'), |
||||
|
knobValue = knob.find('.knob-value'), |
||||
|
knobErrorContainer = knob.find('.error-container'), |
||||
|
knobError = knob.find('.knob-error'), |
||||
|
knobTitleContainer = knob.find('.title-container'), |
||||
|
knobTitle = knob.find('.knob-title'), |
||||
|
knobMinmaxContainer = knob.find('.minmax-container'), |
||||
|
minmaxLanel = knob.find('.minmax-label'), |
||||
|
textMeasure = knob.find('#text-measure'), |
||||
|
startDeg = -1, |
||||
|
currentDeg = 0, |
||||
|
rotation = 0, |
||||
|
lastDeg = 0, |
||||
|
moving = false; |
||||
|
|
||||
|
var minDeg = -45; |
||||
|
var maxDeg = 225; |
||||
|
|
||||
|
var canvasBarElement = angular.element('#canvasBar', $element); |
||||
|
|
||||
|
var levelColors = ['#19ff4b', '#ffff19', '#ff3232']; |
||||
|
|
||||
|
var canvasBar; |
||||
|
|
||||
|
$scope.$watch('vm.ctx', () => { |
||||
|
if (vm.ctx) { |
||||
|
init(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
function init() { |
||||
|
|
||||
|
vm.minValue = angular.isDefined(vm.ctx.settings.minValue) ? vm.ctx.settings.minValue : 0; |
||||
|
vm.maxValue = angular.isDefined(vm.ctx.settings.maxValue) ? vm.ctx.settings.maxValue : 100; |
||||
|
vm.title = angular.isDefined(vm.ctx.settings.title) ? vm.ctx.settings.title : ''; |
||||
|
|
||||
|
vm.darkTheme = vm.ctx.settings.theme == 'dark'; |
||||
|
|
||||
|
var canvasBarData = { |
||||
|
renderTo: canvasBarElement[0], |
||||
|
hideValue: true, |
||||
|
neonGlowBrightness: 0, |
||||
|
gaugeWidthScale: 0.4, |
||||
|
gaugeColor: 'rgba(0, 0, 0, 0)', |
||||
|
levelColors: levelColors, |
||||
|
minValue: vm.minValue, |
||||
|
maxValue: vm.maxValue, |
||||
|
gaugeType: 'donut', |
||||
|
dashThickness: 2, |
||||
|
donutStartAngle: 3/4*Math.PI, |
||||
|
donutEndAngle: 9/4*Math.PI, |
||||
|
animation: false |
||||
|
}; |
||||
|
|
||||
|
canvasBar = new CanvasDigitalGauge(canvasBarData).draw(); |
||||
|
|
||||
|
knob.on('click', (e) => { |
||||
|
if (moving) { |
||||
|
moving = false; |
||||
|
return false; |
||||
|
} |
||||
|
e.preventDefault(); |
||||
|
|
||||
|
var offset = knob.offset(); |
||||
|
var center = { |
||||
|
y : offset.top + knob.height()/2, |
||||
|
x: offset.left + knob.width()/2 |
||||
|
}; |
||||
|
var a, b, deg, |
||||
|
rad2deg = 180/Math.PI; |
||||
|
|
||||
|
e = (e.originalEvent.touches) ? e.originalEvent.touches[0] : e; |
||||
|
|
||||
|
a = center.y - e.pageY; |
||||
|
b = center.x - e.pageX; |
||||
|
deg = Math.atan2(a,b)*rad2deg; |
||||
|
if(deg < 0){ |
||||
|
deg = 360 + deg; |
||||
|
} |
||||
|
if (deg > maxDeg) { |
||||
|
if (deg - 360 > minDeg) { |
||||
|
deg = deg - 360; |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
currentDeg = deg; |
||||
|
lastDeg = deg; |
||||
|
knobTopPointerContainer.css('transform','rotate('+(currentDeg)+'deg)'); |
||||
|
turn(degreeToRatio(currentDeg)); |
||||
|
rotation = currentDeg; |
||||
|
startDeg = -1; |
||||
|
}); |
||||
|
|
||||
|
knob.on('mousedown touchstart', (e) => { |
||||
|
e.preventDefault(); |
||||
|
var offset = knob.offset(); |
||||
|
var center = { |
||||
|
y : offset.top + knob.height()/2, |
||||
|
x: offset.left + knob.width()/2 |
||||
|
}; |
||||
|
|
||||
|
var a, b, deg, tmp, |
||||
|
rad2deg = 180/Math.PI; |
||||
|
|
||||
|
knob.on('mousemove.rem touchmove.rem', (e) => { |
||||
|
moving = true; |
||||
|
e = (e.originalEvent.touches) ? e.originalEvent.touches[0] : e; |
||||
|
|
||||
|
a = center.y - e.pageY; |
||||
|
b = center.x - e.pageX; |
||||
|
deg = Math.atan2(a,b)*rad2deg; |
||||
|
if(deg < 0){ |
||||
|
deg = 360 + deg; |
||||
|
} |
||||
|
|
||||
|
if(startDeg == -1){ |
||||
|
startDeg = deg; |
||||
|
} |
||||
|
|
||||
|
tmp = Math.floor((deg-startDeg) + rotation); |
||||
|
|
||||
|
if(tmp < 0){ |
||||
|
tmp = 360 + tmp; |
||||
|
} |
||||
|
else if(tmp > 359){ |
||||
|
tmp = tmp % 360; |
||||
|
} |
||||
|
|
||||
|
if (tmp > maxDeg) { |
||||
|
if (tmp - 360 > minDeg) { |
||||
|
tmp = tmp - 360; |
||||
|
} else { |
||||
|
var deltaMax = Math.abs(maxDeg - lastDeg); |
||||
|
var deltaMin = Math.abs(minDeg - lastDeg); |
||||
|
if (deltaMax < deltaMin) { |
||||
|
tmp = maxDeg; |
||||
|
} else { |
||||
|
tmp = minDeg; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
if(Math.abs(tmp - lastDeg) > 180){ |
||||
|
startDeg = deg; |
||||
|
rotation = currentDeg; |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
currentDeg = tmp; |
||||
|
lastDeg = tmp; |
||||
|
|
||||
|
knobTopPointerContainer.css('transform','rotate('+(currentDeg)+'deg)'); |
||||
|
turn(degreeToRatio(currentDeg)); |
||||
|
}); |
||||
|
|
||||
|
$document.on('mouseup.rem touchend.rem',() => { |
||||
|
knob.off('.rem'); |
||||
|
$document.off('.rem'); |
||||
|
rotation = currentDeg; |
||||
|
startDeg = -1; |
||||
|
}); |
||||
|
|
||||
|
}); |
||||
|
vm.ctx.resize = resize; |
||||
|
resize(); |
||||
|
var initialValue = angular.isDefined(vm.ctx.settings.initialValue) ? vm.ctx.settings.initialValue : vm.minValue; |
||||
|
setValue(initialValue); |
||||
|
|
||||
|
var subscription = vm.ctx.defaultSubscription; |
||||
|
var rpcEnabled = subscription.rpcEnabled; |
||||
|
|
||||
|
vm.isSimulated = $scope.widgetEditMode; |
||||
|
|
||||
|
vm.requestTimeout = 500; |
||||
|
if (vm.ctx.settings.requestTimeout) { |
||||
|
vm.requestTimeout = vm.ctx.settings.requestTimeout; |
||||
|
} |
||||
|
vm.getValueMethod = 'getValue'; |
||||
|
if (vm.ctx.settings.getValueMethod && vm.ctx.settings.getValueMethod.length) { |
||||
|
vm.getValueMethod = vm.ctx.settings.getValueMethod; |
||||
|
} |
||||
|
vm.setValueMethod = 'setValue'; |
||||
|
if (vm.ctx.settings.setValueMethod && vm.ctx.settings.setValueMethod.length) { |
||||
|
vm.setValueMethod = vm.ctx.settings.setValueMethod; |
||||
|
} |
||||
|
if (!rpcEnabled) { |
||||
|
onError('Target device is not set!'); |
||||
|
} else { |
||||
|
if (!vm.isSimulated) { |
||||
|
rpcRequestValue(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function ratioToDegree(ratio) { |
||||
|
return minDeg + ratio*(maxDeg-minDeg); |
||||
|
} |
||||
|
|
||||
|
function degreeToRatio(degree) { |
||||
|
return (degree-minDeg)/(maxDeg-minDeg); |
||||
|
} |
||||
|
|
||||
|
function resize() { |
||||
|
var width = knobContainer.width(); |
||||
|
var height = knobContainer.height(); |
||||
|
var size = Math.min(width, height); |
||||
|
knob.css({width: size, height: size}); |
||||
|
canvasBar.update({width: size, height: size}); |
||||
|
setFontSize(knobTitle, vm.title, knobTitleContainer.height(), knobTitleContainer.width()); |
||||
|
setFontSize(knobError, vm.error, knobErrorContainer.height(), knobErrorContainer.width()); |
||||
|
var minmaxHeight = knobMinmaxContainer.height(); |
||||
|
minmaxLanel.css({'fontSize': minmaxHeight+'px', 'lineHeight': minmaxHeight+'px'}); |
||||
|
checkValueSize(); |
||||
|
} |
||||
|
|
||||
|
function turn(ratio) { |
||||
|
var value = (vm.minValue + (vm.maxValue - vm.minValue)*ratio).toFixed(vm.ctx.decimals); |
||||
|
if (canvasBar.value != value) { |
||||
|
canvasBar.value = value; |
||||
|
} |
||||
|
updateColor(canvasBar.getValueColor()); |
||||
|
onValue(value); |
||||
|
} |
||||
|
|
||||
|
function setValue(value) { |
||||
|
var ratio = (value-vm.minValue) / (vm.maxValue - vm.minValue); |
||||
|
rotation = lastDeg = currentDeg = ratioToDegree(ratio); |
||||
|
knobTopPointerContainer.css('transform','rotate('+(currentDeg)+'deg)'); |
||||
|
if (canvasBar.value != value) { |
||||
|
canvasBar.value = value; |
||||
|
} |
||||
|
updateColor(canvasBar.getValueColor()); |
||||
|
vm.value = formatValue(value); |
||||
|
checkValueSize(); |
||||
|
} |
||||
|
|
||||
|
function updateColor(color) { |
||||
|
var glowColor = tinycolor(color).brighten(30).toHexString(); |
||||
|
knobValue.css({'color': glowColor}); |
||||
|
var textShadow = `${color} 1px 1px 10px, ${glowColor} 1px 1px 10px`; |
||||
|
knobValue.css({'textShadow': textShadow}); |
||||
|
knobTopPointer.css({'backgroundColor': glowColor}); |
||||
|
var boxShadow = `inset 1px 0 2px #040404, 1px 1px 8px 2px ${glowColor}`; |
||||
|
knobTopPointer.css({'boxShadow': boxShadow}); |
||||
|
} |
||||
|
|
||||
|
function onValue(value) { |
||||
|
$scope.$applyAsync(() => { |
||||
|
vm.value = formatValue(value); |
||||
|
checkValueSize(); |
||||
|
rpcUpdateValue(value); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function onError(error) { |
||||
|
$scope.$applyAsync(() => { |
||||
|
vm.error = error; |
||||
|
setFontSize(knobError, vm.error, knobErrorContainer.height(), knobErrorContainer.width()); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
function formatValue(value) { |
||||
|
return vm.ctx.utils.formatValue(value, vm.ctx.decimals, vm.ctx.units, true); |
||||
|
} |
||||
|
|
||||
|
function checkValueSize() { |
||||
|
var fontSize = knobValueContainer.height()/3.3; |
||||
|
var containerWidth = knobValueContainer.width(); |
||||
|
setFontSize(knobValue, vm.value, fontSize, containerWidth); |
||||
|
} |
||||
|
|
||||
|
function setFontSize(element, text, fontSize, maxWidth) { |
||||
|
var textWidth = measureTextWidth(text, fontSize); |
||||
|
while (textWidth > maxWidth) { |
||||
|
fontSize--; |
||||
|
textWidth = measureTextWidth(text, fontSize); |
||||
|
} |
||||
|
element.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'}); |
||||
|
} |
||||
|
|
||||
|
function measureTextWidth(text, fontSize) { |
||||
|
textMeasure.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'}); |
||||
|
textMeasure.text(text); |
||||
|
return textMeasure.width(); |
||||
|
} |
||||
|
|
||||
|
function rpcRequestValue() { |
||||
|
vm.error = ''; |
||||
|
vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then( |
||||
|
(responseBody) => { |
||||
|
if (isNumber(responseBody)) { |
||||
|
var numValue = Number(responseBody).toFixed(vm.ctx.decimals); |
||||
|
setValue(numValue); |
||||
|
} else { |
||||
|
var errorText = `Unable to parse response: ${responseBody}`; |
||||
|
onError(errorText); |
||||
|
} |
||||
|
}, |
||||
|
() => { |
||||
|
var errorText = vm.ctx.defaultSubscription.rpcErrorText; |
||||
|
onError(errorText); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
function rpcUpdateValue(value) { |
||||
|
if (vm.executingUpdateValue) { |
||||
|
vm.scheduledValue = value; |
||||
|
return; |
||||
|
} else { |
||||
|
vm.scheduledValue = null; |
||||
|
vm.rpcValue = value; |
||||
|
vm.executingUpdateValue = true; |
||||
|
} |
||||
|
vm.error = ''; |
||||
|
vm.ctx.controlApi.sendOneWayCommand(vm.setValueMethod, value, vm.requestTimeout).then( |
||||
|
() => { |
||||
|
vm.executingUpdateValue = false; |
||||
|
if (vm.scheduledValue != null && vm.scheduledValue != vm.rpcValue) { |
||||
|
rpcUpdateValue(vm.scheduledValue); |
||||
|
} |
||||
|
}, |
||||
|
() => { |
||||
|
vm.executingUpdateValue = false; |
||||
|
var errorText = vm.ctx.defaultSubscription.rpcErrorText; |
||||
|
onError(errorText); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,157 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2017 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. |
||||
|
*/ |
||||
|
|
||||
|
$knob-img: url('./knob.svg'); |
||||
|
|
||||
|
$bars-margin-pct: percentage(0.033); |
||||
|
$background-margin-pct: percentage(0.05); |
||||
|
$value-container-margin-pct: percentage(0.35); |
||||
|
$error-height: percentage(0.05); |
||||
|
$title-height: percentage(0.066); |
||||
|
$title-container-margin-pct: percentage(0.2); |
||||
|
$title-container-margin-bottom-pct: percentage(0.05); |
||||
|
$minmax-height: percentage(0.04); |
||||
|
$minmax-container-margin-pct: percentage(0.18); |
||||
|
$minmax-container-margin-bottom-pct: percentage(0.12); |
||||
|
|
||||
|
$background-color: #e6e7e8; |
||||
|
|
||||
|
.tb-knob { |
||||
|
width:100%; |
||||
|
height:100%; |
||||
|
background: $background-color; |
||||
|
&.dark { |
||||
|
background: #000; |
||||
|
} |
||||
|
|
||||
|
.knob { |
||||
|
position: relative; |
||||
|
&[draggable] { |
||||
|
-moz-user-select: none; |
||||
|
-webkit-user-select: none; |
||||
|
user-select: none; |
||||
|
} |
||||
|
#canvasBar { |
||||
|
position:absolute; |
||||
|
top:0; |
||||
|
left:0; |
||||
|
bottom: 0; |
||||
|
right: 0; |
||||
|
z-index: 2; |
||||
|
} |
||||
|
.canvas-background { |
||||
|
position:absolute; |
||||
|
top: $background-margin-pct; |
||||
|
left: $background-margin-pct; |
||||
|
bottom: $background-margin-pct; |
||||
|
right: $background-margin-pct; |
||||
|
border-radius: 50%; |
||||
|
background: #3f4346; |
||||
|
z-index:2; |
||||
|
} |
||||
|
.value-container { |
||||
|
position:absolute; |
||||
|
top: $value-container-margin-pct; |
||||
|
left: $value-container-margin-pct; |
||||
|
bottom: $value-container-margin-pct; |
||||
|
right: $value-container-margin-pct; |
||||
|
z-index:4; |
||||
|
.knob-value { |
||||
|
color: #fff; |
||||
|
font-weight: 500; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
.error-container { |
||||
|
position:absolute; |
||||
|
top: 1%; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
z-index:4; |
||||
|
height: $error-height; |
||||
|
.knob-error { |
||||
|
color: #ff3315; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
.title-container { |
||||
|
position:absolute; |
||||
|
left: $title-container-margin-pct; |
||||
|
bottom: $title-container-margin-bottom-pct; |
||||
|
right: $title-container-margin-pct; |
||||
|
z-index:4; |
||||
|
height: $title-height; |
||||
|
.knob-title { |
||||
|
color: #757575; |
||||
|
font-weight: 500; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
.minmax-container { |
||||
|
position:absolute; |
||||
|
left: $minmax-container-margin-pct; |
||||
|
bottom: $minmax-container-margin-bottom-pct; |
||||
|
right: $minmax-container-margin-pct; |
||||
|
z-index:4; |
||||
|
height: $minmax-height; |
||||
|
.minmax-label { |
||||
|
color: #757575; |
||||
|
font-weight: 500; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
.top-pointer-container { |
||||
|
position:absolute; |
||||
|
top: $bars-margin-pct; |
||||
|
left: $bars-margin-pct; |
||||
|
bottom: $bars-margin-pct; |
||||
|
right: $bars-margin-pct; |
||||
|
z-index:3; |
||||
|
cursor:pointer !important; |
||||
|
.top-pointer { |
||||
|
content:''; |
||||
|
width:5%; |
||||
|
height:5%; |
||||
|
background-color:#b5b5b5; |
||||
|
position:absolute; |
||||
|
top:50%; |
||||
|
left:22%; |
||||
|
margin-top:-2.5%; |
||||
|
border-radius: 50%; |
||||
|
cursor:pointer !important; |
||||
|
box-shadow: 1px 0 2px #040404; |
||||
|
} |
||||
|
} |
||||
|
.top{ |
||||
|
position:absolute; |
||||
|
top: $bars-margin-pct; |
||||
|
left: $bars-margin-pct; |
||||
|
bottom: $bars-margin-pct; |
||||
|
right: $bars-margin-pct; |
||||
|
background:$knob-img no-repeat; |
||||
|
background-size: contain; |
||||
|
z-index:2; |
||||
|
cursor:pointer !important; |
||||
|
} |
||||
|
#text-measure { |
||||
|
position: absolute; |
||||
|
visibility: hidden; |
||||
|
height: auto; |
||||
|
width: auto; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,46 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2017 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-knob" layout="column" ng-class="{'dark': vm.darkTheme}" ng-style="{'pointerEvents': vm.ctx.isEdit ? 'none' : 'all'}"> |
||||
|
<div id="knob-container" flex layout="column" layout-align="center center"> |
||||
|
<div class="knob"> |
||||
|
<div class="value-container" layout="row" layout-align="center center"> |
||||
|
<span class="knob-value">{{ vm.value }}</span> |
||||
|
</div> |
||||
|
<div class="canvas-background"></div> |
||||
|
<canvas id="canvasBar"></canvas> |
||||
|
<div class="top-pointer-container"> |
||||
|
<div class="top-pointer"></div> |
||||
|
</div> |
||||
|
<div class="top"></div> |
||||
|
<div class="error-container" ng-style="{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}" |
||||
|
layout="row" layout-align="center center"> |
||||
|
<span class="knob-error">{{ vm.error }}</span> |
||||
|
</div> |
||||
|
<div class="title-container" layout="row" layout-align="center center"> |
||||
|
<span class="knob-title">{{ vm.title }}</span> |
||||
|
</div> |
||||
|
<div class="minmax-container" layout="row" layout-align="start center"> |
||||
|
<span class="minmax-label">min</span> |
||||
|
<span flex></span> |
||||
|
<span class="minmax-label">max</span> |
||||
|
</div> |
||||
|
<div id="text-measure"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
Loading…
Reference in new issue