thingsboard-aplcache

TB-70: Control knob widget.

7/18/2017 10:29:36 PM

Details

diff --git a/application/src/main/data/json/system/widget_bundles/control_widgets.json b/application/src/main/data/json/system/widget_bundles/control_widgets.json
index b06c979..a1cd3c9 100644
--- a/application/src/main/data/json/system/widget_bundles/control_widgets.json
+++ b/application/src/main/data/json/system/widget_bundles/control_widgets.json
@@ -42,11 +42,11 @@
       "name": "Shiny Knob Control",
       "descriptor": {
         "type": "rpc",
-        "sizeX": 2.5,
-        "sizeY": 3,
+        "sizeX": 4,
+        "sizeY": 3.5,
         "resources": [],
         "templateHtml": "<tb-shiny-knob ctx='ctx'></tb-shiny-knob>",
-        "templateCss": ".error {\n    font-size: 14px !important;\n    color: maroon;/*rgb(250,250,250);*/\n    background-color: transparent;\n    padding: 6px;\n}\n\n.error span {\n    margin: auto;\n}\n\n.gpio-panel {\n    padding-top: 10px;\n    white-space: nowrap;\n}\n\n.switch-panel {\n    margin: 0;\n    height: 32px;\n    width: 66px;\n    min-width: 66px;\n}\n\n.switch-panel md-switch {\n    margin: 0;\n    width: 36px;\n    min-width: 36px;\n}\n\n.switch-panel md-switch > div.md-container {\n    margin: 0;\n}\n\n.switch-panel.col-0 md-switch {\n    padding-left: 8px;\n    padding-right: 4px;\n}\n\n.switch-panel.col-1 md-switch {\n    padding-left: 4px;\n    padding-right: 8px;\n}\n\n.gpio-row {\n    height: 32px;\n}\n\n.pin {\n    margin-top: auto;\n    margin-bottom: auto;\n    color: white;\n    font-size: 12px;\n    width: 16px;\n    min-width: 16px;\n}\n\n.switch-panel.col-0 .pin {\n    margin-left: auto;\n    padding-left: 2px;\n    text-align: right;\n}\n\n.switch-panel.col-1 .pin {\n    margin-right: auto;\n    \n    text-align: left;\n}\n\n.gpio-left-label {\n    margin-right: 8px;\n}\n\n.gpio-right-label {\n    margin-left: 8px;\n}",
+        "templateCss": "",
         "controllerScript": "self.onInit = function() {\n    var scope = self.ctx.$scope;\n    scope.ctx = self.ctx;\n}\n\nself.onResize = function() {\n    if (self.ctx.resize) {\n        self.ctx.resize();\n    }\n}\n\nself.onDestroy = function() {\n}\n",
         "settingsSchema": "{\n    \"schema\": {\n        \"type\": \"object\",\n        \"title\": \"Settings\",\n        \"properties\": {\n            \"minValue\": {\n                \"title\": \"Minimum value\",\n                \"type\": \"number\",\n                \"default\": 0\n            },\n            \"maxValue\": {\n                \"title\": \"Maximum value\",\n                \"type\": \"number\",\n                \"default\": 100\n            },\n            \"initialValue\": {\n                \"title\": \"Initial value\",\n                \"type\": \"number\",\n                \"default\": 50\n            },\n            \"theme\": {\n                \"title\": \"Knob theme\",\n                \"type\": \"string\",\n                \"default\": \"light\"\n            },            \n            \"requestTimeout\": {\n                \"title\": \"RPC request timeout\",\n                \"type\": \"number\",\n                \"default\": 500\n            }\n        },\n        \"required\": [\"minValue\", \"maxValue\", \"requestTimeout\"]\n    },\n    \"form\": [\n        \"minValue\",\n        \"maxValue\",\n        \"initialValue\",\n        {\n            \"key\": \"theme\",\n            \"type\": \"rc-select\",\n            \"multiple\": false,\n            \"items\": [\n                {\n                    \"value\": \"light\",\n                    \"label\": \"Light\"\n                },\n                {\n                    \"value\": \"dark\",\n                    \"label\": \"Dark\"\n                }\n            ]\n        },\n        \"requestTimeout\"\n    ]\n}",
         "dataKeySettingsSchema": "{}\n",
diff --git a/ui/src/app/widget/lib/CanvasDigitalGauge.js b/ui/src/app/widget/lib/CanvasDigitalGauge.js
index e6c2e27..1a40235 100644
--- a/ui/src/app/widget/lib/CanvasDigitalGauge.js
+++ b/ui/src/app/widget/lib/CanvasDigitalGauge.js
@@ -238,6 +238,21 @@ export default class CanvasDigitalGauge extends canvasGauges.BaseGauge {
         return this;
     }
 
+    getValueColor() {
+        if (this.contextProgressClone) {
+            var color = this.contextProgressClone.currentColor;
+            if (!color) {
+                if (this.options.neonGlowBrightness) {
+                    color = getProgressColor(0, this.options.neonColorsRange);
+                } else {
+                    color = getProgressColor(0, this.options.colorsRange);
+                }
+            }
+            return color;
+        } else {
+            return '#000';
+        }
+    }
 }
 
 /* eslint-disable angular/document-service */
@@ -666,9 +681,9 @@ function drawBarGlow(context, startX, startY, endX, endY, color, strokeWidth, is
 function drawProgress(context, options, progress) {
     var neonColor;
     if (options.neonGlowBrightness) {
-        neonColor = getProgressColor(progress, options.neonColorsRange);
+        context.currentColor = neonColor = getProgressColor(progress, options.neonColorsRange);
     } else {
-        context.strokeStyle = getProgressColor(progress, options.colorsRange);
+        context.currentColor = context.strokeStyle = getProgressColor(progress, options.colorsRange);
     }
 
     let {barLeft, barRight, barTop, baseX, width, barBottom, Cx, Cy, Rm, Ro, Ri, strokeWidth} =
diff --git a/ui/src/app/widget/lib/rpc/knob.svg b/ui/src/app/widget/lib/rpc/knob.svg
new file mode 100644
index 0000000..d75c2b1
--- /dev/null
+++ b/ui/src/app/widget/lib/rpc/knob.svg
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg id="svg52850" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="28.222mm" width="28.222mm" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 99.999997 99.999997" xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <defs id="defs52852">
+  <radialGradient id="radialGradient52746-69" xlink:href="#linearGradient53063" gradientUnits="userSpaceOnUse" cy="990.69" cx="1006.1" gradientTransform="matrix(.0028197 -2.0966 3.8027 .0051141 -2863.2 3472.2)" r="86.621"/>
+  <linearGradient id="linearGradient53063">
+   <stop id="stop53065" stop-color="#b5b5b5" offset="0"/>
+   <stop id="stop53067" stop-color="#f5f5f5" offset="1"/>
+  </linearGradient>
+  <radialGradient id="radialGradient52746-69-7-0" gradientUnits="userSpaceOnUse" cy="990.69" cx="1006.1" gradientTransform="matrix(.0016764 -1.2465 2.2609 .0030406 -3150 20.652)" r="86.621">
+   <stop id="stop53119" stop-color="#808080" offset="0"/>
+   <stop id="stop53121" stop-color="#fdfdfd" offset="1"/>
+  </radialGradient>
+  <radialGradient id="radialGradient52746-69-7" xlink:href="#linearGradient53063" gradientUnits="userSpaceOnUse" cy="990.69" cx="1006.1" gradientTransform="matrix(.0016276 -1.2102 2.195 .002952 -3084.7 -17.281)" r="86.621"/>
+ </defs>
+ <metadata id="metadata52855">
+  <rdf:RDF>
+   <cc:Work rdf:about="">
+    <dc:format>image/svg+xml</dc:format>
+    <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+    <dc:title/>
+   </cc:Work>
+  </rdf:RDF>
+ </metadata>
+ <g id="layer1" transform="translate(-330.69 -606.32)">
+  <g id="g53154" transform="matrix(.40816 -.40816 .40816 .40816 -513.05 503.76)">
+   <circle id="path52738-5" cy="1281.7" cx="907.94" r="86.621" fill="url(#radialGradient52746-69)"/>
+   <circle id="path52738-5-3-6" transform="scale(-1)" cy="-1281.7" cx="-907.94" r="51.5" fill="url(#radialGradient52746-69-7-0)"/>
+   <circle id="path52738-5-3" transform="scale(-1)" cy="-1281.7" cx="-907.94" r="50" fill="url(#radialGradient52746-69-7)"/>
+  </g>
+ </g>
+</svg>
diff --git a/ui/src/app/widget/lib/rpc/shiny-knob.directive.js b/ui/src/app/widget/lib/rpc/shiny-knob.directive.js
index b186799..e79f03b 100644
--- a/ui/src/app/widget/lib/rpc/shiny-knob.directive.js
+++ b/ui/src/app/widget/lib/rpc/shiny-knob.directive.js
@@ -17,7 +17,6 @@
 import './shiny-knob.scss';
 
 import CanvasDigitalGauge from './../CanvasDigitalGauge';
-//import tinycolor from 'tinycolor2';
 
 /* eslint-disable import/no-unresolved, import/default */
 
@@ -53,7 +52,11 @@ function ShinyKnobController($element, $scope, $document) {
 
     var knob = angular.element('.knob', $element),
         knobContainer = angular.element('#knob-container', $element),
-        knobTop = knob.find('.top'),
+       // knobTop = knob.find('.top'),
+        knobTopPointerContainer = knob.find('.top-pointer-container'),
+        knobTopPointer = knob.find('.top-pointer'),
+        knobValueBackground = knob.find('.value-background'),
+        knobValue = knob.find('.knob-value'),
         startDeg = -1,
         currentDeg = 0,
         rotation = 0,
@@ -61,7 +64,7 @@ function ShinyKnobController($element, $scope, $document) {
 
     var canvasBarElement = angular.element('#canvasBar', $element);
 
-    var levelColors = ['rgb(0, 128, 0)', 'rgb(251, 192, 45)', 'rgb(244, 67, 54)'];
+    var levelColors = ['rgb(0, 128, 0)', 'rgb(251, 192, 45)', 'rgb(255, 0, 0)'];//['cyan'];//
     var canvasBar;
 
     $scope.$watch('vm.ctx', () => {
@@ -80,14 +83,14 @@ function ShinyKnobController($element, $scope, $document) {
         var canvasBarData = {
             renderTo: canvasBarElement[0],
             hideValue: true,
-            neonGlowBrightness: vm.darkTheme ? 40 : 0,
-            gaugeWidthScale: 0.5,
-            gaugeColor: vm.darkTheme ? 'rgb(23, 26, 28)' : 'rgba(0,0,0,0)',
+            neonGlowBrightness: 40,//40,//vm.darkTheme ? 40 : 0,
+            gaugeWidthScale: 0.2,
+            gaugeColor: vm.darkTheme ? 'rgb(23, 26, 28)' : 'rgba(0, 0, 0, 0.75)',
             levelColors: levelColors,
             minValue: vm.minValue,
             maxValue: vm.maxValue,
             gaugeType: 'donut',
-            dashThickness: 1.5,
+            dashThickness: 0,//1.5,
             donutStartAngle: Math.PI,
             animation: false,
             animationDuration: 250,
@@ -141,7 +144,7 @@ function ShinyKnobController($element, $scope, $document) {
                 currentDeg = tmp;
                 lastDeg = tmp;
 
-                knobTop.css('transform','rotate('+(currentDeg)+'deg)');
+                knobTopPointerContainer.css('transform','rotate('+(currentDeg)+'deg)');
                 turn(currentDeg/359);
             });
 
@@ -168,6 +171,8 @@ function ShinyKnobController($element, $scope, $document) {
         var size = Math.min(width, height);
         knob.css({width: size, height: size});
         canvasBar.update({width: size, height: size});
+        var valHeight = knobValueBackground.height()/3.3;
+        knobValue.css({'fontSize': valHeight+'px', 'lineHeight': valHeight+'px'});
     }
 
     function turn(ratio) {
@@ -175,16 +180,20 @@ function ShinyKnobController($element, $scope, $document) {
         if (canvasBar.value != value) {
             canvasBar.value = value;
         }
+        knobTopPointer.css({'backgroundColor': canvasBar.getValueColor()});
+        knobValue.css({'color': 'cyan'});//canvasBar.getValueColor()});
         onValue(value);
     }
 
     function setValue(value) {
         var ratio = (value-vm.minValue) / (vm.maxValue - vm.minValue);
         rotation = lastDeg = currentDeg = ratio*360;
-        knobTop.css('transform','rotate('+(currentDeg)+'deg)');
+        knobTopPointerContainer.css('transform','rotate('+(currentDeg)+'deg)');
         if (canvasBar.value != value) {
             canvasBar.value = value;
         }
+        knobTopPointer.css({'backgroundColor': canvasBar.getValueColor()});
+        knobValue.css({'color': 'cyan'});//canvasBar.getValueColor()});
         vm.value = value;
     }
 
diff --git a/ui/src/app/widget/lib/rpc/shiny-knob.scss b/ui/src/app/widget/lib/rpc/shiny-knob.scss
index 7ff204c..a636ec5 100644
--- a/ui/src/app/widget/lib/rpc/shiny-knob.scss
+++ b/ui/src/app/widget/lib/rpc/shiny-knob.scss
@@ -14,10 +14,11 @@
  * limitations under the License.
  */
 
-$knob-img: url('./knob.png');
+$knob-img: url('./knob.svg');
 
-$bars-margin-pct: percentage(0.2);
-$shadow-size: 5;
+$bars-margin-pct: percentage(0.08);
+$value-background-margin-pct: percentage(0.30);
+$shadow-size: 0;
 $shadow-size-px: $shadow-size+px;
 $shadow-offset-px: $shadow-size/2+px;
 
@@ -25,7 +26,7 @@ $shadow-offset-px: $shadow-size/2+px;
   width:100%;
   height:100%;
   &.dark {
-    background: #000;//$dark-bg-img #1f2129;
+    background: #000;
   }
 
   .knob {
@@ -42,30 +43,51 @@ $shadow-offset-px: $shadow-size/2+px;
       bottom: 0;
       right: 0;
     }
-    .top{
+    .value-background {
+      position:absolute;
+      top: $value-background-margin-pct;
+      left: $value-background-margin-pct;
+      bottom: $value-background-margin-pct;
+      right: $value-background-margin-pct;
+      border-radius: 50%;
+      background: #000;
+      color: #fff;
+      font-weight: 500;
+      z-index:4;
+    }
+    .top-pointer-container {
       position:absolute;
       top: calc(#{$bars-margin-pct} - #{$shadow-offset-px});
       left: $bars-margin-pct;
       bottom: calc(#{$bars-margin-pct} + #{$shadow-offset-px});
       right: $bars-margin-pct;
-      background:$knob-img no-repeat;
-      background-size: contain;
-      z-index:10;
+      z-index:3;
       cursor:default !important;
-      &:after {
+      .top-pointer {
         content:'';
-        width:10px;
-        height:10px;
-        background-color:#666;
+        width:5%;
+        height:5%;
+        background-color:#b5b5b5;
         position:absolute;
         top:50%;
-        left:10px;
-        margin-top:-5px;
+        left:5%;
+        margin-top:-2.5%;
         border-radius: 50%;
         cursor:default !important;
-        box-shadow: 0 0 1px #5a5a5a inset;
+        box-shadow: 1px 0 2px #040404;
       }
     }
+    .top{
+      position:absolute;
+      top: calc(#{$bars-margin-pct} - #{$shadow-offset-px});
+      left: $bars-margin-pct;
+      bottom: calc(#{$bars-margin-pct} + #{$shadow-offset-px});
+      right: $bars-margin-pct;
+      background:$knob-img no-repeat;
+      background-size: contain;
+      z-index:2;
+      cursor:default !important;
+    }
     .base{
       top: calc(#{$bars-margin-pct} - #{$shadow-offset-px});
       left: $bars-margin-pct;
diff --git a/ui/src/app/widget/lib/rpc/shiny-knob.tpl.html b/ui/src/app/widget/lib/rpc/shiny-knob.tpl.html
index 18094b3..be48067 100644
--- a/ui/src/app/widget/lib/rpc/shiny-knob.tpl.html
+++ b/ui/src/app/widget/lib/rpc/shiny-knob.tpl.html
@@ -17,12 +17,15 @@
 -->
 
 <div class="tb-shiny-knob" layout="column" ng-class="{'dark': vm.darkTheme}">
-    <div layout="row" layout-align="center start" class="md-padding">
-        <span>{{ vm.value }}</span>
-    </div>
     <div id="knob-container" flex layout="column" layout-align="center center">
         <div class="knob">
+            <div class="value-background" layout="row" layout-align="center center">
+                <span class="knob-value">{{ vm.value }}</span>
+            </div>
             <canvas id="canvasBar"></canvas>
+            <div class="top-pointer-container">
+                <div class="top-pointer"></div>
+            </div>
             <div class="top"></div>
             <div class="base"></div>
         </div>