committed by
GitHub
6 changed files with 330 additions and 2 deletions
@ -0,0 +1,201 @@ |
|||||
|
/* |
||||
|
* 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 './led-indicator.scss'; |
||||
|
|
||||
|
import tinycolor from 'tinycolor2'; |
||||
|
|
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import ledIndicatorTemplate from './led-indicator.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.rpc.ledIndicator', []) |
||||
|
.directive('tbLedIndicator', LedIndicator) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function LedIndicator() { |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
scope: true, |
||||
|
bindToController: { |
||||
|
ctx: '=' |
||||
|
}, |
||||
|
controller: LedIndicatorController, |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: ledIndicatorTemplate |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function LedIndicatorController($element, $scope, $timeout) { |
||||
|
let vm = this; |
||||
|
|
||||
|
vm.showTitle = false; |
||||
|
vm.value = false; |
||||
|
vm.error = ''; |
||||
|
|
||||
|
var led = angular.element('.led', $element), |
||||
|
ledContainer = angular.element('#led-container', $element), |
||||
|
textMeasure = angular.element('#text-measure', $element), |
||||
|
ledTitleContainer = angular.element('.title-container', $element), |
||||
|
ledTitle = angular.element('.led-title', $element), |
||||
|
ledErrorContainer = angular.element('.error-container', $element), |
||||
|
ledError = angular.element('.led-error', $element); |
||||
|
|
||||
|
$scope.$watch('vm.ctx', () => { |
||||
|
if (vm.ctx) { |
||||
|
init(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
$scope.$on('$destroy', () => { |
||||
|
vm.destroyed = true; |
||||
|
if (vm.requestValueTimeoutHandle) { |
||||
|
$timeout.cancel(vm.requestValueTimeoutHandle); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
resize(); |
||||
|
|
||||
|
function init() { |
||||
|
|
||||
|
vm.title = angular.isDefined(vm.ctx.settings.title) ? vm.ctx.settings.title : ''; |
||||
|
vm.showTitle = vm.title && vm.title.length ? true : false; |
||||
|
|
||||
|
var origColor = angular.isDefined(vm.ctx.settings.ledColor) ? vm.ctx.settings.ledColor : 'green'; |
||||
|
|
||||
|
vm.ledColor = tinycolor(origColor).brighten(30).toHexString(); |
||||
|
vm.ledMiddleColor = tinycolor(origColor).toHexString(); |
||||
|
vm.disabledColor = tinycolor(origColor).darken(40).toHexString(); |
||||
|
vm.disabledMiddleColor = tinycolor(origColor).darken(60).toHexString(); |
||||
|
|
||||
|
vm.ctx.resize = resize; |
||||
|
$scope.$applyAsync(() => { |
||||
|
resize(); |
||||
|
}); |
||||
|
var initialValue = angular.isDefined(vm.ctx.settings.initialValue) ? vm.ctx.settings.initialValue : false; |
||||
|
setValue(initialValue, true); |
||||
|
|
||||
|
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.valuePollingInterval = 500; |
||||
|
if (vm.ctx.settings.valuePollingInterval) { |
||||
|
vm.valuePollingInterval = vm.ctx.settings.valuePollingInterval; |
||||
|
} |
||||
|
vm.getValueMethod = 'getValue'; |
||||
|
if (vm.ctx.settings.getValueMethod && vm.ctx.settings.getValueMethod.length) { |
||||
|
vm.getValueMethod = vm.ctx.settings.getValueMethod; |
||||
|
} |
||||
|
if (!rpcEnabled) { |
||||
|
onError('Target device is not set!'); |
||||
|
} else { |
||||
|
if (!vm.isSimulated) { |
||||
|
rpcRequestValue(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function resize() { |
||||
|
var width = ledContainer.width(); |
||||
|
var height = ledContainer.height(); |
||||
|
var size = Math.min(width, height); |
||||
|
|
||||
|
led.css({width: size, height: size}); |
||||
|
|
||||
|
if (vm.showTitle) { |
||||
|
setFontSize(ledTitle, vm.title, ledTitleContainer.height() * 2 / 3, ledTitleContainer.width()); |
||||
|
} |
||||
|
setFontSize(ledError, vm.error, ledErrorContainer.height(), ledErrorContainer.width()); |
||||
|
} |
||||
|
|
||||
|
function setValue(value, forceUpdate) { |
||||
|
if (vm.value != value || forceUpdate) { |
||||
|
vm.value = value; |
||||
|
updateColor(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function updateColor() { |
||||
|
var color = vm.value ? vm.ledColor : vm.disabledColor; |
||||
|
var middleColor = vm.value ? vm.ledMiddleColor : vm.disabledMiddleColor; |
||||
|
var boxShadow = `#000 0 -1px 6px 1px, inset ${middleColor} 0 -1px 8px, ${color} 0 3px 11px`; |
||||
|
led.css({'backgroundColor': color}); |
||||
|
led.css({'boxShadow': boxShadow}); |
||||
|
if (vm.value) { |
||||
|
led.removeClass( 'disabled' ); |
||||
|
} else { |
||||
|
led.addClass( 'disabled' ); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
function onError(error) { |
||||
|
$scope.$applyAsync(() => { |
||||
|
vm.error = error; |
||||
|
setFontSize(ledError, vm.error, ledErrorContainer.height(), ledErrorContainer.width()); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
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() { |
||||
|
if (vm.destroyed) { |
||||
|
return; |
||||
|
} |
||||
|
vm.error = ''; |
||||
|
vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then( |
||||
|
(responseBody) => { |
||||
|
var newValue = responseBody ? true : false; |
||||
|
setValue(newValue); |
||||
|
if (vm.requestValueTimeoutHandle) { |
||||
|
$timeout.cancel(vm.requestValueTimeoutHandle); |
||||
|
} |
||||
|
vm.requestValueTimeoutHandle = $timeout(rpcRequestValue, vm.valuePollingInterval); |
||||
|
}, |
||||
|
() => { |
||||
|
var errorText = vm.ctx.defaultSubscription.rpcErrorText; |
||||
|
onError(errorText); |
||||
|
if (vm.requestValueTimeoutHandle) { |
||||
|
$timeout.cancel(vm.requestValueTimeoutHandle); |
||||
|
} |
||||
|
vm.requestValueTimeoutHandle = $timeout(rpcRequestValue, vm.valuePollingInterval); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,78 @@ |
|||||
|
/** |
||||
|
* 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 "~compass-sass-mixins/lib/compass"; |
||||
|
|
||||
|
$error-height: 14px; |
||||
|
|
||||
|
$background-color: #e6e7e8; |
||||
|
|
||||
|
.tb-led-indicator { |
||||
|
width:100%; |
||||
|
height:100%; |
||||
|
background: $background-color; |
||||
|
|
||||
|
.title-container { |
||||
|
.led-title { |
||||
|
color: #757575; |
||||
|
font-weight: 500; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.error-container { |
||||
|
position:absolute; |
||||
|
top: 1%; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
z-index:4; |
||||
|
height: $error-height; |
||||
|
.led-error { |
||||
|
color: #ff3315; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
#text-measure { |
||||
|
position: absolute; |
||||
|
visibility: hidden; |
||||
|
height: auto; |
||||
|
width: auto; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
#led-container { |
||||
|
padding: 10px; |
||||
|
.led { |
||||
|
cursor: pointer; |
||||
|
position: relative; |
||||
|
border-radius: 50%; |
||||
|
background-image: -owg-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25)); |
||||
|
background-image: -webkit-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25)); |
||||
|
background-image: -moz-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25)); |
||||
|
background-image: -o-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25)); |
||||
|
background-image: radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25)); |
||||
|
transition: background-color 0.5s, box-shadow 0.5s; |
||||
|
&.disabled { |
||||
|
background-image: -owg-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1)); |
||||
|
background-image: -webkit-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1)); |
||||
|
background-image: -moz-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1)); |
||||
|
background-image: -o-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1)); |
||||
|
background-image: radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,32 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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-led-indicator" layout="column"> |
||||
|
<div flex="20" class="title-container" layout="row" layout-align="center center" ng-show="vm.showTitle"> |
||||
|
<span class="led-title">{{vm.title}}</span> |
||||
|
</div> |
||||
|
<div flex="{{vm.showTitle ? 80 : 100}}" |
||||
|
ng-style="{paddingTop: vm.showTitle ? '5px': '10px'}" id="led-container" layout="column" layout-align="center center"> |
||||
|
<div class="led"> |
||||
|
</div> |
||||
|
</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="led-error">{{ vm.error }}</span> |
||||
|
</div> |
||||
|
<div id="text-measure"></div> |
||||
|
</div> |
||||
Loading…
Reference in new issue