committed by
GitHub
5 changed files with 451 additions and 1 deletions
@ -0,0 +1,199 @@ |
|||||
|
/* |
||||
|
* 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 './round-switch.scss'; |
||||
|
|
||||
|
/* eslint-disable import/no-unresolved, import/default */ |
||||
|
|
||||
|
import roundSwitchTemplate from './round-switch.tpl.html'; |
||||
|
|
||||
|
/* eslint-enable import/no-unresolved, import/default */ |
||||
|
|
||||
|
export default angular.module('thingsboard.widgets.rpc.roundSwitch', []) |
||||
|
.directive('tbRoundSwitch', RoundSwitch) |
||||
|
.name; |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function RoundSwitch() { |
||||
|
return { |
||||
|
restrict: "E", |
||||
|
scope: true, |
||||
|
bindToController: { |
||||
|
ctx: '=' |
||||
|
}, |
||||
|
controller: RoundSwitchController, |
||||
|
controllerAs: 'vm', |
||||
|
templateUrl: roundSwitchTemplate |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/*@ngInject*/ |
||||
|
function RoundSwitchController($element, $scope, utils) { |
||||
|
let vm = this; |
||||
|
|
||||
|
vm.showTitle = false; |
||||
|
vm.value = false; |
||||
|
vm.error = ''; |
||||
|
|
||||
|
vm.checkboxId = 'onoff-' + utils.guid(); |
||||
|
|
||||
|
var switchElement = angular.element('.switch', $element), |
||||
|
switchContainer = angular.element('#switch-container', $element), |
||||
|
onoff = angular.element('input', $element), |
||||
|
textMeasure = angular.element('#text-measure', $element), |
||||
|
switchTitleContainer = angular.element('.title-container', $element), |
||||
|
switchTitle = angular.element('.switch-title', $element), |
||||
|
switchErrorContainer = angular.element('.error-container', $element), |
||||
|
switchError = angular.element('.switch-error', $element); |
||||
|
|
||||
|
onoff.bind('change', () => { |
||||
|
vm.value = onoff.prop('checked') === false; |
||||
|
onValue(); |
||||
|
}); |
||||
|
|
||||
|
$scope.$watch('vm.ctx', () => { |
||||
|
if (vm.ctx) { |
||||
|
init(); |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
resize(); |
||||
|
|
||||
|
function init() { |
||||
|
|
||||
|
vm.title = angular.isDefined(vm.ctx.settings.title) ? vm.ctx.settings.title : ''; |
||||
|
vm.showTitle = vm.title && vm.title.length ? true : false; |
||||
|
vm.showOnOffLabels = angular.isDefined(vm.ctx.settings.showOnOffLabels) ? vm.ctx.settings.showOnOffLabels : true; |
||||
|
vm.ctx.resize = resize; |
||||
|
$scope.$applyAsync(() => { |
||||
|
resize(); |
||||
|
}); |
||||
|
var initialValue = angular.isDefined(vm.ctx.settings.initialValue) ? vm.ctx.settings.initialValue : false; |
||||
|
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 resize() { |
||||
|
var width = switchContainer.width(); |
||||
|
var height = switchContainer.height(); |
||||
|
var size = Math.min(width, height); |
||||
|
var scale = size/260; |
||||
|
switchElement.css({ |
||||
|
'-webkit-transform': `scale(${scale})`, |
||||
|
'-moz-transform': `scale(${scale})`, |
||||
|
'-ms-transform': `scale(${scale})`, |
||||
|
'-o-transform': `scale(${scale})`, |
||||
|
transform: `scale(${scale})` |
||||
|
}); |
||||
|
if (vm.showTitle) { |
||||
|
setFontSize(switchTitle, vm.title, switchTitleContainer.height() * 2 / 3, switchTitleContainer.width()); |
||||
|
} |
||||
|
setFontSize(switchError, vm.error, switchErrorContainer.height(), switchErrorContainer.width()); |
||||
|
} |
||||
|
|
||||
|
function setValue(value) { |
||||
|
vm.value = value ? true : false; |
||||
|
onoff.prop('checked', !vm.value); |
||||
|
} |
||||
|
|
||||
|
function onValue() { |
||||
|
rpcUpdateValue(vm.value); |
||||
|
} |
||||
|
|
||||
|
function onError(error) { |
||||
|
$scope.$applyAsync(() => { |
||||
|
vm.error = error; |
||||
|
setFontSize(switchError, vm.error, switchErrorContainer.height(), switchErrorContainer.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() { |
||||
|
vm.error = ''; |
||||
|
vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then( |
||||
|
(responseBody) => { |
||||
|
setValue(responseBody); |
||||
|
}, |
||||
|
() => { |
||||
|
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,195 @@ |
|||||
|
/** |
||||
|
* 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-round-switch { |
||||
|
width:100%; |
||||
|
height:100%; |
||||
|
background: $background-color; |
||||
|
|
||||
|
.title-container { |
||||
|
.switch-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; |
||||
|
.switch-error { |
||||
|
color: #ff3315; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
} |
||||
|
#text-measure { |
||||
|
position: absolute; |
||||
|
visibility: hidden; |
||||
|
height: auto; |
||||
|
width: auto; |
||||
|
white-space: nowrap; |
||||
|
} |
||||
|
|
||||
|
#switch-container { |
||||
|
padding: 10px; |
||||
|
.switch { |
||||
|
cursor: pointer; |
||||
|
position: relative; |
||||
|
background:#ddd; |
||||
|
background: -owg-linear-gradient(270deg, #bbb, #ddd); |
||||
|
background: -webkit-linear-gradient(270deg, #bbb, #ddd); |
||||
|
background: -moz-linear-gradient(270deg, #bbb, #ddd); |
||||
|
background: -o-linear-gradient(270deg, #bbb, #ddd); |
||||
|
-pie-background: -pie-linear-gradient(270deg, #bbb, #ddd); |
||||
|
background: linear-gradient(180deg, #bbb, #ddd); |
||||
|
border-radius:130px; |
||||
|
@include box-sizing(border-box); |
||||
|
@include box-shadow( |
||||
|
0px 0px 0px 8px rgba(0,0,0,.1) |
||||
|
,0px 0px 3px 1px rgba(0,0,0,.1) |
||||
|
,inset 0 8px 3px -8px rgba(255,255,255,.4)); |
||||
|
height: 260px; |
||||
|
min-height: 260px; |
||||
|
padding: 25px; |
||||
|
width: 260px; |
||||
|
min-width: 260px; |
||||
|
|
||||
|
color: #424242; |
||||
|
font-family:sans-serif; |
||||
|
font-size:48px; |
||||
|
|
||||
|
input { |
||||
|
display:none |
||||
|
} |
||||
|
|
||||
|
.on,.off { |
||||
|
position:absolute; |
||||
|
text-align:center; |
||||
|
@include text-shadow(1px 1px 4px #4a4a4a); |
||||
|
width:100%; |
||||
|
} |
||||
|
|
||||
|
.on { |
||||
|
color:#444; |
||||
|
top:10px; |
||||
|
@include transition(all 0.1s); |
||||
|
font-family:sans-serif |
||||
|
} |
||||
|
|
||||
|
.off { |
||||
|
bottom:5px; |
||||
|
@include transition(all 0.1s); |
||||
|
@include transform(scaleY(0.85)); |
||||
|
} |
||||
|
|
||||
|
.but { |
||||
|
cursor: pointer; |
||||
|
background-color:#d8d8d8; |
||||
|
border-radius: 400px 400px 400px 400px / 400px 400px 300px 300px; |
||||
|
border-bottom-width:0px; |
||||
|
@include box-shadow(inset 8px 6px 5px -7px #a2a2a2, |
||||
|
inset -8px 6px 5px -7px #a2a2a2, |
||||
|
inset 0 -3px 2px -2px rgba(200, 200, 200, 0.5), |
||||
|
0 3px 3px -2px #ffffff, |
||||
|
inset 0 -230px 60px -200px rgba(255, 255, 255, 0.2), |
||||
|
inset 0 220px 40px -200px rgba(0, 0, 0, 0.3)); |
||||
|
display:block; |
||||
|
font-size:48px; |
||||
|
height:178px; |
||||
|
position:relative; |
||||
|
@include transition(all 0.2s); |
||||
|
width:200px; |
||||
|
} |
||||
|
|
||||
|
.back { |
||||
|
cursor: pointer; |
||||
|
background-color: #888787; |
||||
|
background-image: -owg-linear-gradient(0deg, transparent 30%, transparent 70%), -owg-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, 0.2) 50%, rgba(150, 150, 150, 0) 70%); |
||||
|
background-image: -webkit-linear-gradient(0deg, transparent 30%, transparent 70%), -webkit-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, 0.2) 50%, rgba(150, 150, 150, 0) 70%); |
||||
|
background-image: -moz-linear-gradient(0deg, transparent 30%, transparent 70%), -moz-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, 0.2) 50%, rgba(150, 150, 150, 0) 70%); |
||||
|
background-image: -o-linear-gradient(0deg, transparent 30%, transparent 70%), -o-linear-gradient(90deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, 0.2) 50%, rgba(150, 150, 150, 0) 70%); |
||||
|
background-image: linear-gradient(-90deg, transparent 30%, transparent 70%), linear-gradient(0deg, rgba(150, 150, 150, 0) 30%, rgba(150, 150, 150, 0.2) 50%, rgba(150, 150, 150, 0) 70%); |
||||
|
border-radius:105px; |
||||
|
@include box-shadow(30px 30px 30px -20px rgba(58, 58, 58, 0.3), |
||||
|
-30px 30px 30px -20px rgba(58, 58, 58, 0.3), |
||||
|
0 30px 30px 0px rgba(16, 16, 16, 0.3), |
||||
|
inset 0 -1px 0 0 #484848); |
||||
|
@include box-sizing(border-box); |
||||
|
height:210px; |
||||
|
padding:4px 4px; |
||||
|
@include transition(all 0.2s); |
||||
|
width:210px; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
input:checked + .back .on,input:checked + .back .off{ |
||||
|
@include text-shadow(1px 1px 4px #4a4a4a); |
||||
|
} |
||||
|
input:checked + .back .on{ |
||||
|
color:#4c4c4c; |
||||
|
top:10px; |
||||
|
@include transform(scaleY(0.85)); |
||||
|
} |
||||
|
input:checked + .back .off{ |
||||
|
color:#444; |
||||
|
bottom:5px; |
||||
|
@include transform(scaleY(1)); |
||||
|
} |
||||
|
input:checked + .back .but{ |
||||
|
background:#dcdcdc; |
||||
|
background-image: -owg-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent); |
||||
|
background-image: -webkit-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent); |
||||
|
background-image: -moz-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent); |
||||
|
background-image: -o-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent); |
||||
|
background-image: radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent); |
||||
|
border-radius: 400px 400px 400px 400px / 300px 300px 400px 400px; |
||||
|
@include box-shadow(inset 8px -4px 5px -7px #a9a9a9, |
||||
|
inset -8px -4px 5px -7px #808080, |
||||
|
0 -3px 8px -4px rgba(50, 50, 50, 0.4), |
||||
|
inset 0 3px 4px -2px #9c9c9c, |
||||
|
inset 0 280px 40px -200px rgba(0, 0, 0, 0.2), |
||||
|
inset 0 -200px 40px -200px rgba(180, 180, 180, 0.2)); |
||||
|
margin-top:20px; |
||||
|
} |
||||
|
input:checked + .back{ |
||||
|
|
||||
|
background-image: -owg-linear-gradient(90deg, #868686 30%, transparent 70%), -owg-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, 0.74) 50%, rgba(105, 105, 105, 0) 100%); |
||||
|
background-image: -webkit-linear-gradient(90deg, #868686 30%, transparent 70%), -webkit-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, 0.74) 50%, rgba(105, 105, 105, 0) 100%); |
||||
|
background-image: -moz-linear-gradient(90deg, #868686 30%, transparent 70%), -moz-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, 0.74) 50%, rgba(105, 105, 105, 0) 100%); |
||||
|
background-image: -o-linear-gradient(90deg, #868686 30%, transparent 70%), -o-linear-gradient(180deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, 0.74) 50%, rgba(105, 105, 105, 0) 100%); |
||||
|
background-image: linear-gradient(0deg, #868686 30%, transparent 70%), linear-gradient(90deg, rgba(115, 115, 115, 0) 0%, rgba(255, 255, 255, 0.74) 50%, rgba(105, 105, 105, 0) 100%); |
||||
|
|
||||
|
@include box-shadow(30px 30px 30px -20px rgba(49, 49, 49, 0.1), |
||||
|
-30px 30px 30px -20px rgba(111, 111, 111, 0.1), |
||||
|
0 30px 30px 0px rgba(0, 0, 0, 0.2), |
||||
|
inset 0 1px 2px 0 rgba(167, 167, 167, 0.6)); |
||||
|
padding:2px 4px; |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,38 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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-round-switch" layout="column" ng-style="{'pointerEvents': vm.ctx.isEdit ? 'none' : 'all'}"> |
||||
|
<div flex="20" class="title-container" layout="row" layout-align="center center" ng-show="vm.showTitle"> |
||||
|
<span class="switch-title">{{vm.title}}</span> |
||||
|
</div> |
||||
|
<div flex="{{vm.showTitle ? 80 : 100}}" ng-style="{paddingTop: vm.showTitle ? '5px': '10px'}" id="switch-container" layout="column" layout-align="center center"> |
||||
|
<div class="switch"> |
||||
|
<input type="checkbox" id="{{vm.checkboxId}}" name="onoff" /> |
||||
|
<div class="back"> |
||||
|
<label class="but" for="{{vm.checkboxId}}"> |
||||
|
<span class="on">I</span> |
||||
|
<span class="off">0</span> |
||||
|
</label> |
||||
|
</div> |
||||
|
</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="switch-error">{{ vm.error }}</span> |
||||
|
</div> |
||||
|
<div id="text-measure"></div> |
||||
|
</div> |
||||
Loading…
Reference in new issue