8 changed files with 359 additions and 6 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 tbShinyKnob from './shiny-knob.directive'; |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.rpc', [ |
||||
|
tbShinyKnob |
||||
|
]).name; |
||||
|
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,198 @@ |
|||||
|
/* |
||||
|
* 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 './shiny-knob.scss'; |
||||
|
|
||||
|
import CanvasDigitalGauge from './../CanvasDigitalGauge'; |
||||
|
//import tinycolor from 'tinycolor2';
|
||||
|
|
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import shinyKnobTemplate from './shiny-knob.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.rpc.shinyKnob', []) |
||||
|
.directive('tbShinyKnob', ShinyKnob) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function ShinyKnob() { |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
scope: true, |
||||
|
bindToController: { |
||||
|
ctx: '=' |
||||
|
}, |
||||
|
controller: ShinyKnobController, |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: shinyKnobTemplate |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function ShinyKnobController($element, $scope, $document) { |
||||
|
let vm = this; |
||||
|
|
||||
|
vm.value = 0; |
||||
|
|
||||
|
var snap = 0; |
||||
|
|
||||
|
var knob = angular.element('.knob', $element), |
||||
|
knobContainer = angular.element('#knob-container', $element), |
||||
|
knobTop = knob.find('.top'), |
||||
|
startDeg = -1, |
||||
|
currentDeg = 0, |
||||
|
rotation = 0, |
||||
|
lastDeg = 0; |
||||
|
|
||||
|
var canvasBarElement = angular.element('#canvasBar', $element); |
||||
|
|
||||
|
var levelColors = ['rgb(0, 128, 0)', 'rgb(251, 192, 45)', 'rgb(244, 67, 54)']; |
||||
|
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.darkTheme = vm.ctx.settings.theme == 'dark'; |
||||
|
|
||||
|
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)', |
||||
|
levelColors: levelColors, |
||||
|
minValue: vm.minValue, |
||||
|
maxValue: vm.maxValue, |
||||
|
gaugeType: 'donut', |
||||
|
dashThickness: 1.5, |
||||
|
donutStartAngle: Math.PI, |
||||
|
animation: false, |
||||
|
animationDuration: 250, |
||||
|
animationRule: 'linear' |
||||
|
}; |
||||
|
|
||||
|
canvasBar = new CanvasDigitalGauge(canvasBarData).draw(); |
||||
|
|
||||
|
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) => { |
||||
|
|
||||
|
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(snap && tmp < snap){ |
||||
|
tmp = 0; |
||||
|
} |
||||
|
if(Math.abs(tmp - lastDeg) > 180){ |
||||
|
return false; |
||||
|
} |
||||
|
currentDeg = tmp; |
||||
|
lastDeg = tmp; |
||||
|
|
||||
|
knobTop.css('transform','rotate('+(currentDeg)+'deg)'); |
||||
|
turn(currentDeg/359); |
||||
|
}); |
||||
|
|
||||
|
$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); |
||||
|
} |
||||
|
|
||||
|
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}); |
||||
|
} |
||||
|
|
||||
|
function turn(ratio) { |
||||
|
var value = (vm.minValue + (vm.maxValue - vm.minValue)*ratio).toFixed(2); |
||||
|
if (canvasBar.value != value) { |
||||
|
canvasBar.value = value; |
||||
|
} |
||||
|
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)'); |
||||
|
if (canvasBar.value != value) { |
||||
|
canvasBar.value = value; |
||||
|
} |
||||
|
vm.value = value; |
||||
|
} |
||||
|
|
||||
|
function onValue(value) { |
||||
|
console.log(`onValue ${value}`); //eslint-disable-line
|
||||
|
$scope.$applyAsync(() => { |
||||
|
vm.value = value; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,80 @@ |
|||||
|
/** |
||||
|
* 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.png'); |
||||
|
|
||||
|
$bars-margin-pct: percentage(0.2); |
||||
|
$shadow-size: 5; |
||||
|
$shadow-size-px: $shadow-size+px; |
||||
|
$shadow-offset-px: $shadow-size/2+px; |
||||
|
|
||||
|
.tb-shiny-knob { |
||||
|
width:100%; |
||||
|
height:100%; |
||||
|
&.dark { |
||||
|
background: #000;//$dark-bg-img #1f2129; |
||||
|
} |
||||
|
|
||||
|
.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; |
||||
|
} |
||||
|
.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:10; |
||||
|
cursor:default !important; |
||||
|
&:after { |
||||
|
content:''; |
||||
|
width:10px; |
||||
|
height:10px; |
||||
|
background-color:#666; |
||||
|
position:absolute; |
||||
|
top:50%; |
||||
|
left:10px; |
||||
|
margin-top:-5px; |
||||
|
border-radius: 50%; |
||||
|
cursor:default !important; |
||||
|
box-shadow: 0 0 1px #5a5a5a inset; |
||||
|
} |
||||
|
} |
||||
|
.base{ |
||||
|
top: calc(#{$bars-margin-pct} - #{$shadow-offset-px}); |
||||
|
left: $bars-margin-pct; |
||||
|
bottom: calc(#{$bars-margin-pct} + #{$shadow-offset-px}); |
||||
|
right: $bars-margin-pct; |
||||
|
border-radius:50%; |
||||
|
box-shadow:0 $shadow-size-px 0 #4a5056,$shadow-size-px $shadow-size-px $shadow-size-px #000; |
||||
|
position:absolute; |
||||
|
z-index:1; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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-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"> |
||||
|
<canvas id="canvasBar"></canvas> |
||||
|
<div class="top"></div> |
||||
|
<div class="base"></div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
Loading…
Reference in new issue