Commit d1f9f25f2998073d95c3cf745ad3fe89430daf59

Authored by Volodymyr Babak
2 parents 49feb913 d77dd0f8

Merge remote-tracking branch 'upstream/master'

... ... @@ -68,6 +68,38 @@
68 68 "dataKeySettingsSchema": "{}\n",
69 69 "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Switch control\"},\"title\":\"Switch Control\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
70 70 }
  71 + },
  72 + {
  73 + "alias": "round_switch",
  74 + "name": "Round switch",
  75 + "descriptor": {
  76 + "type": "rpc",
  77 + "sizeX": 2.5,
  78 + "sizeY": 2,
  79 + "resources": [],
  80 + "templateHtml": "<tb-round-switch ctx='ctx'></tb-round-switch>",
  81 + "templateCss": "",
  82 + "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",
  83 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"Switch title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"setValueMethod\": {\n \"title\": \"Set value method\",\n \"type\": \"string\",\n \"default\": \"setValue\"\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"getValueMethod\", \"setValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n \"getValueMethod\",\n \"setValueMethod\",\n \"requestTimeout\"\n ]\n}",
  84 + "dataKeySettingsSchema": "{}\n",
  85 + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":false,\"getValueMethod\":\"getValue\",\"setValueMethod\":\"setValue\",\"showOnOffLabels\":true,\"title\":\"Round switch\"},\"title\":\"Round switch\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
  86 + }
  87 + },
  88 + {
  89 + "alias": "led_indicator",
  90 + "name": "Led indicator",
  91 + "descriptor": {
  92 + "type": "rpc",
  93 + "sizeX": 2.5,
  94 + "sizeY": 2.5,
  95 + "resources": [],
  96 + "templateHtml": "<tb-led-indicator ctx='ctx'></tb-led-indicator>",
  97 + "templateCss": "",
  98 + "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",
  99 + "settingsSchema": "{\n \"schema\": {\n \"type\": \"object\",\n \"title\": \"Settings\",\n \"properties\": {\n \"initialValue\": {\n \"title\": \"Initial value\",\n \"type\": \"boolean\",\n \"default\": false\n },\n \"title\": {\n \"title\": \"LED title\",\n \"type\": \"string\",\n \"default\": \"\"\n },\n \"ledColor\": {\n \"title\": \"LED Color\",\n \"type\": \"string\",\n \"default\": \"green\"\n },\n \"getValueMethod\": {\n \"title\": \"Get value method\",\n \"type\": \"string\",\n \"default\": \"getValue\"\n },\n \"valuePollingInterval\": {\n \"title\": \"Value polling interval (ms)\",\n \"type\": \"number\",\n \"default\": 500\n },\n \"requestTimeout\": {\n \"title\": \"RPC request timeout (ms)\",\n \"type\": \"number\",\n \"default\": 500\n }\n },\n \"required\": [\"getValueMethod\", \"requestTimeout\"]\n },\n \"form\": [\n \"initialValue\",\n \"title\",\n {\n \"key\": \"ledColor\",\n \"type\": \"color\"\n },\n \"getValueMethod\",\n \"valuePollingInterval\",\n \"requestTimeout\"\n ]\n}",
  100 + "dataKeySettingsSchema": "{}\n",
  101 + "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"requestTimeout\":500,\"initialValue\":true,\"getValueMethod\":\"getValue\",\"title\":\"Led indicator\",\"ledColor\":\"#4caf50\",\"valuePollingInterval\":500},\"title\":\"Led indicator\",\"dropShadow\":true,\"enableFullscreen\":false,\"widgetStyle\":{},\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"useDashboardTimewindow\":true,\"showLegend\":false,\"actions\":{},\"decimals\":2}"
  102 + }
71 103 }
72 104 ]
73 105 }
\ No newline at end of file
... ...
... ... @@ -16,8 +16,12 @@
16 16
17 17 import tbKnob from './knob.directive';
18 18 import tbSwitch from './switch.directive';
  19 +import tbRoundSwitch from './round-switch.directive';
  20 +import tbLedIndicator from './led-indicator.directive';
19 21
20 22 export default angular.module('thingsboard.widgets.rpc', [
21 23 tbKnob,
22   - tbSwitch
  24 + tbSwitch,
  25 + tbRoundSwitch,
  26 + tbLedIndicator
23 27 ]).name;
... ...
  1 +/*
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +import './led-indicator.scss';
  18 +
  19 +import tinycolor from 'tinycolor2';
  20 +
  21 +/* eslint-disable import/no-unresolved, import/default */
  22 +
  23 +import ledIndicatorTemplate from './led-indicator.tpl.html';
  24 +
  25 +/* eslint-enable import/no-unresolved, import/default */
  26 +
  27 +export default angular.module('thingsboard.widgets.rpc.ledIndicator', [])
  28 + .directive('tbLedIndicator', LedIndicator)
  29 + .name;
  30 +
  31 +/*@ngInject*/
  32 +function LedIndicator() {
  33 + return {
  34 + restrict: "E",
  35 + scope: true,
  36 + bindToController: {
  37 + ctx: '='
  38 + },
  39 + controller: LedIndicatorController,
  40 + controllerAs: 'vm',
  41 + templateUrl: ledIndicatorTemplate
  42 + };
  43 +}
  44 +
  45 +/*@ngInject*/
  46 +function LedIndicatorController($element, $scope, $timeout) {
  47 + let vm = this;
  48 +
  49 + vm.showTitle = false;
  50 + vm.value = false;
  51 + vm.error = '';
  52 +
  53 + var led = angular.element('.led', $element),
  54 + ledContainer = angular.element('#led-container', $element),
  55 + textMeasure = angular.element('#text-measure', $element),
  56 + ledTitleContainer = angular.element('.title-container', $element),
  57 + ledTitle = angular.element('.led-title', $element),
  58 + ledErrorContainer = angular.element('.error-container', $element),
  59 + ledError = angular.element('.led-error', $element);
  60 +
  61 + $scope.$watch('vm.ctx', () => {
  62 + if (vm.ctx) {
  63 + init();
  64 + }
  65 + });
  66 +
  67 + $scope.$on('$destroy', () => {
  68 + vm.destroyed = true;
  69 + if (vm.requestValueTimeoutHandle) {
  70 + $timeout.cancel(vm.requestValueTimeoutHandle);
  71 + }
  72 + });
  73 +
  74 + resize();
  75 +
  76 + function init() {
  77 +
  78 + vm.title = angular.isDefined(vm.ctx.settings.title) ? vm.ctx.settings.title : '';
  79 + vm.showTitle = vm.title && vm.title.length ? true : false;
  80 +
  81 + var origColor = angular.isDefined(vm.ctx.settings.ledColor) ? vm.ctx.settings.ledColor : 'green';
  82 +
  83 + vm.ledColor = tinycolor(origColor).brighten(30).toHexString();
  84 + vm.ledMiddleColor = tinycolor(origColor).toHexString();
  85 + vm.disabledColor = tinycolor(origColor).darken(40).toHexString();
  86 + vm.disabledMiddleColor = tinycolor(origColor).darken(60).toHexString();
  87 +
  88 + vm.ctx.resize = resize;
  89 + $scope.$applyAsync(() => {
  90 + resize();
  91 + });
  92 + var initialValue = angular.isDefined(vm.ctx.settings.initialValue) ? vm.ctx.settings.initialValue : false;
  93 + setValue(initialValue, true);
  94 +
  95 + var subscription = vm.ctx.defaultSubscription;
  96 + var rpcEnabled = subscription.rpcEnabled;
  97 +
  98 + vm.isSimulated = $scope.widgetEditMode;
  99 +
  100 + vm.requestTimeout = 500;
  101 + if (vm.ctx.settings.requestTimeout) {
  102 + vm.requestTimeout = vm.ctx.settings.requestTimeout;
  103 + }
  104 + vm.valuePollingInterval = 500;
  105 + if (vm.ctx.settings.valuePollingInterval) {
  106 + vm.valuePollingInterval = vm.ctx.settings.valuePollingInterval;
  107 + }
  108 + vm.getValueMethod = 'getValue';
  109 + if (vm.ctx.settings.getValueMethod && vm.ctx.settings.getValueMethod.length) {
  110 + vm.getValueMethod = vm.ctx.settings.getValueMethod;
  111 + }
  112 + if (!rpcEnabled) {
  113 + onError('Target device is not set!');
  114 + } else {
  115 + if (!vm.isSimulated) {
  116 + rpcRequestValue();
  117 + }
  118 + }
  119 + }
  120 +
  121 + function resize() {
  122 + var width = ledContainer.width();
  123 + var height = ledContainer.height();
  124 + var size = Math.min(width, height);
  125 +
  126 + led.css({width: size, height: size});
  127 +
  128 + if (vm.showTitle) {
  129 + setFontSize(ledTitle, vm.title, ledTitleContainer.height() * 2 / 3, ledTitleContainer.width());
  130 + }
  131 + setFontSize(ledError, vm.error, ledErrorContainer.height(), ledErrorContainer.width());
  132 + }
  133 +
  134 + function setValue(value, forceUpdate) {
  135 + if (vm.value != value || forceUpdate) {
  136 + vm.value = value;
  137 + updateColor();
  138 + }
  139 + }
  140 +
  141 + function updateColor() {
  142 + var color = vm.value ? vm.ledColor : vm.disabledColor;
  143 + var middleColor = vm.value ? vm.ledMiddleColor : vm.disabledMiddleColor;
  144 + var boxShadow = `#000 0 -1px 6px 1px, inset ${middleColor} 0 -1px 8px, ${color} 0 3px 11px`;
  145 + led.css({'backgroundColor': color});
  146 + led.css({'boxShadow': boxShadow});
  147 + if (vm.value) {
  148 + led.removeClass( 'disabled' );
  149 + } else {
  150 + led.addClass( 'disabled' );
  151 + }
  152 + }
  153 +
  154 + function onError(error) {
  155 + $scope.$applyAsync(() => {
  156 + vm.error = error;
  157 + setFontSize(ledError, vm.error, ledErrorContainer.height(), ledErrorContainer.width());
  158 + });
  159 + }
  160 +
  161 + function setFontSize(element, text, fontSize, maxWidth) {
  162 + var textWidth = measureTextWidth(text, fontSize);
  163 + while (textWidth > maxWidth) {
  164 + fontSize--;
  165 + textWidth = measureTextWidth(text, fontSize);
  166 + }
  167 + element.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'});
  168 + }
  169 +
  170 + function measureTextWidth(text, fontSize) {
  171 + textMeasure.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'});
  172 + textMeasure.text(text);
  173 + return textMeasure.width();
  174 + }
  175 +
  176 + function rpcRequestValue() {
  177 + if (vm.destroyed) {
  178 + return;
  179 + }
  180 + vm.error = '';
  181 + vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then(
  182 + (responseBody) => {
  183 + var newValue = responseBody ? true : false;
  184 + setValue(newValue);
  185 + if (vm.requestValueTimeoutHandle) {
  186 + $timeout.cancel(vm.requestValueTimeoutHandle);
  187 + }
  188 + vm.requestValueTimeoutHandle = $timeout(rpcRequestValue, vm.valuePollingInterval);
  189 + },
  190 + () => {
  191 + var errorText = vm.ctx.defaultSubscription.rpcErrorText;
  192 + onError(errorText);
  193 + if (vm.requestValueTimeoutHandle) {
  194 + $timeout.cancel(vm.requestValueTimeoutHandle);
  195 + }
  196 + vm.requestValueTimeoutHandle = $timeout(rpcRequestValue, vm.valuePollingInterval);
  197 + }
  198 + );
  199 + }
  200 +
  201 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +@import "~compass-sass-mixins/lib/compass";
  18 +
  19 +$error-height: 14px;
  20 +
  21 +$background-color: #e6e7e8;
  22 +
  23 +.tb-led-indicator {
  24 + width:100%;
  25 + height:100%;
  26 + background: $background-color;
  27 +
  28 + .title-container {
  29 + .led-title {
  30 + color: #757575;
  31 + font-weight: 500;
  32 + white-space: nowrap;
  33 + }
  34 + }
  35 +
  36 + .error-container {
  37 + position:absolute;
  38 + top: 1%;
  39 + left: 0;
  40 + right: 0;
  41 + z-index:4;
  42 + height: $error-height;
  43 + .led-error {
  44 + color: #ff3315;
  45 + white-space: nowrap;
  46 + }
  47 + }
  48 + #text-measure {
  49 + position: absolute;
  50 + visibility: hidden;
  51 + height: auto;
  52 + width: auto;
  53 + white-space: nowrap;
  54 + }
  55 +
  56 + #led-container {
  57 + padding: 10px;
  58 + .led {
  59 + cursor: pointer;
  60 + position: relative;
  61 + border-radius: 50%;
  62 + background-image: -owg-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25));
  63 + background-image: -webkit-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25));
  64 + background-image: -moz-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25));
  65 + background-image: -o-radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25));
  66 + background-image: radial-gradient(50% 50%, circle closest-corner, transparent, rgba(0, 0, 0, 0.25));
  67 + transition: background-color 0.5s, box-shadow 0.5s;
  68 + &.disabled {
  69 + background-image: -owg-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1));
  70 + background-image: -webkit-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1));
  71 + background-image: -moz-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1));
  72 + background-image: -o-radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1));
  73 + background-image: radial-gradient(50% 50%, circle closest-corner, rgba(255, 255, 255, 0.5), rgba(0, 0, 0, 0.1));
  74 + }
  75 + }
  76 + }
  77 +}
  78 +
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2017 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div class="tb-led-indicator" layout="column">
  19 + <div flex="20" class="title-container" layout="row" layout-align="center center" ng-show="vm.showTitle">
  20 + <span class="led-title">{{vm.title}}</span>
  21 + </div>
  22 + <div flex="{{vm.showTitle ? 80 : 100}}"
  23 + ng-style="{paddingTop: vm.showTitle ? '5px': '10px'}" id="led-container" layout="column" layout-align="center center">
  24 + <div class="led">
  25 + </div>
  26 + </div>
  27 + <div class="error-container" ng-style="{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}"
  28 + layout="row" layout-align="center center">
  29 + <span class="led-error">{{ vm.error }}</span>
  30 + </div>
  31 + <div id="text-measure"></div>
  32 +</div>
... ...
  1 +/*
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +import './round-switch.scss';
  18 +
  19 +/* eslint-disable import/no-unresolved, import/default */
  20 +
  21 +import roundSwitchTemplate from './round-switch.tpl.html';
  22 +
  23 +/* eslint-enable import/no-unresolved, import/default */
  24 +
  25 +export default angular.module('thingsboard.widgets.rpc.roundSwitch', [])
  26 + .directive('tbRoundSwitch', RoundSwitch)
  27 + .name;
  28 +
  29 +/*@ngInject*/
  30 +function RoundSwitch() {
  31 + return {
  32 + restrict: "E",
  33 + scope: true,
  34 + bindToController: {
  35 + ctx: '='
  36 + },
  37 + controller: RoundSwitchController,
  38 + controllerAs: 'vm',
  39 + templateUrl: roundSwitchTemplate
  40 + };
  41 +}
  42 +
  43 +/*@ngInject*/
  44 +function RoundSwitchController($element, $scope, utils) {
  45 + let vm = this;
  46 +
  47 + vm.showTitle = false;
  48 + vm.value = false;
  49 + vm.error = '';
  50 +
  51 + vm.checkboxId = 'onoff-' + utils.guid();
  52 +
  53 + var switchElement = angular.element('.switch', $element),
  54 + switchContainer = angular.element('#switch-container', $element),
  55 + onoff = angular.element('input', $element),
  56 + textMeasure = angular.element('#text-measure', $element),
  57 + switchTitleContainer = angular.element('.title-container', $element),
  58 + switchTitle = angular.element('.switch-title', $element),
  59 + switchErrorContainer = angular.element('.error-container', $element),
  60 + switchError = angular.element('.switch-error', $element);
  61 +
  62 + onoff.bind('change', () => {
  63 + vm.value = onoff.prop('checked') === false;
  64 + onValue();
  65 + });
  66 +
  67 + $scope.$watch('vm.ctx', () => {
  68 + if (vm.ctx) {
  69 + init();
  70 + }
  71 + });
  72 +
  73 + resize();
  74 +
  75 + function init() {
  76 +
  77 + vm.title = angular.isDefined(vm.ctx.settings.title) ? vm.ctx.settings.title : '';
  78 + vm.showTitle = vm.title && vm.title.length ? true : false;
  79 + vm.ctx.resize = resize;
  80 + $scope.$applyAsync(() => {
  81 + resize();
  82 + });
  83 + var initialValue = angular.isDefined(vm.ctx.settings.initialValue) ? vm.ctx.settings.initialValue : false;
  84 + setValue(initialValue);
  85 +
  86 + var subscription = vm.ctx.defaultSubscription;
  87 + var rpcEnabled = subscription.rpcEnabled;
  88 +
  89 + vm.isSimulated = $scope.widgetEditMode;
  90 +
  91 + vm.requestTimeout = 500;
  92 + if (vm.ctx.settings.requestTimeout) {
  93 + vm.requestTimeout = vm.ctx.settings.requestTimeout;
  94 + }
  95 + vm.getValueMethod = 'getValue';
  96 + if (vm.ctx.settings.getValueMethod && vm.ctx.settings.getValueMethod.length) {
  97 + vm.getValueMethod = vm.ctx.settings.getValueMethod;
  98 + }
  99 + vm.setValueMethod = 'setValue';
  100 + if (vm.ctx.settings.setValueMethod && vm.ctx.settings.setValueMethod.length) {
  101 + vm.setValueMethod = vm.ctx.settings.setValueMethod;
  102 + }
  103 + if (!rpcEnabled) {
  104 + onError('Target device is not set!');
  105 + } else {
  106 + if (!vm.isSimulated) {
  107 + rpcRequestValue();
  108 + }
  109 + }
  110 + }
  111 +
  112 + function resize() {
  113 + var width = switchContainer.width();
  114 + var height = switchContainer.height();
  115 + var size = Math.min(width, height);
  116 + var scale = size/260;
  117 + switchElement.css({
  118 + '-webkit-transform': `scale(${scale})`,
  119 + '-moz-transform': `scale(${scale})`,
  120 + '-ms-transform': `scale(${scale})`,
  121 + '-o-transform': `scale(${scale})`,
  122 + transform: `scale(${scale})`
  123 + });
  124 + if (vm.showTitle) {
  125 + setFontSize(switchTitle, vm.title, switchTitleContainer.height() * 2 / 3, switchTitleContainer.width());
  126 + }
  127 + setFontSize(switchError, vm.error, switchErrorContainer.height(), switchErrorContainer.width());
  128 + }
  129 +
  130 + function setValue(value) {
  131 + vm.value = value ? true : false;
  132 + onoff.prop('checked', !vm.value);
  133 + }
  134 +
  135 + function onValue() {
  136 + rpcUpdateValue(vm.value);
  137 + }
  138 +
  139 + function onError(error) {
  140 + $scope.$applyAsync(() => {
  141 + vm.error = error;
  142 + setFontSize(switchError, vm.error, switchErrorContainer.height(), switchErrorContainer.width());
  143 + });
  144 + }
  145 +
  146 + function setFontSize(element, text, fontSize, maxWidth) {
  147 + var textWidth = measureTextWidth(text, fontSize);
  148 + while (textWidth > maxWidth) {
  149 + fontSize--;
  150 + textWidth = measureTextWidth(text, fontSize);
  151 + }
  152 + element.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'});
  153 + }
  154 +
  155 + function measureTextWidth(text, fontSize) {
  156 + textMeasure.css({'fontSize': fontSize+'px', 'lineHeight': fontSize+'px'});
  157 + textMeasure.text(text);
  158 + return textMeasure.width();
  159 + }
  160 +
  161 + function rpcRequestValue() {
  162 + vm.error = '';
  163 + vm.ctx.controlApi.sendTwoWayCommand(vm.getValueMethod, null, vm.requestTimeout).then(
  164 + (responseBody) => {
  165 + setValue(responseBody);
  166 + },
  167 + () => {
  168 + var errorText = vm.ctx.defaultSubscription.rpcErrorText;
  169 + onError(errorText);
  170 + }
  171 + );
  172 + }
  173 +
  174 + function rpcUpdateValue(value) {
  175 + if (vm.executingUpdateValue) {
  176 + vm.scheduledValue = value;
  177 + return;
  178 + } else {
  179 + vm.scheduledValue = null;
  180 + vm.rpcValue = value;
  181 + vm.executingUpdateValue = true;
  182 + }
  183 + vm.error = '';
  184 + vm.ctx.controlApi.sendOneWayCommand(vm.setValueMethod, value, vm.requestTimeout).then(
  185 + () => {
  186 + vm.executingUpdateValue = false;
  187 + if (vm.scheduledValue != null && vm.scheduledValue != vm.rpcValue) {
  188 + rpcUpdateValue(vm.scheduledValue);
  189 + }
  190 + },
  191 + () => {
  192 + vm.executingUpdateValue = false;
  193 + var errorText = vm.ctx.defaultSubscription.rpcErrorText;
  194 + onError(errorText);
  195 + }
  196 + );
  197 + }
  198 +}
... ...
  1 +/**
  2 + * Copyright © 2016-2017 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +
  17 +@import "~compass-sass-mixins/lib/compass";
  18 +
  19 +$error-height: 14px;
  20 +
  21 +$background-color: #e6e7e8;
  22 +
  23 +.tb-round-switch {
  24 + width:100%;
  25 + height:100%;
  26 + background: $background-color;
  27 +
  28 + .title-container {
  29 + .switch-title {
  30 + color: #757575;
  31 + font-weight: 500;
  32 + white-space: nowrap;
  33 + }
  34 + }
  35 +
  36 + .error-container {
  37 + position:absolute;
  38 + top: 1%;
  39 + left: 0;
  40 + right: 0;
  41 + z-index:4;
  42 + height: $error-height;
  43 + .switch-error {
  44 + color: #ff3315;
  45 + white-space: nowrap;
  46 + }
  47 + }
  48 + #text-measure {
  49 + position: absolute;
  50 + visibility: hidden;
  51 + height: auto;
  52 + width: auto;
  53 + white-space: nowrap;
  54 + }
  55 +
  56 + #switch-container {
  57 + padding: 10px;
  58 + .switch {
  59 + cursor: pointer;
  60 + position: relative;
  61 + background:#ddd;
  62 + background: -owg-linear-gradient(270deg, #bbb, #ddd);
  63 + background: -webkit-linear-gradient(270deg, #bbb, #ddd);
  64 + background: -moz-linear-gradient(270deg, #bbb, #ddd);
  65 + background: -o-linear-gradient(270deg, #bbb, #ddd);
  66 + -pie-background: -pie-linear-gradient(270deg, #bbb, #ddd);
  67 + background: linear-gradient(180deg, #bbb, #ddd);
  68 + border-radius:130px;
  69 + @include box-sizing(border-box);
  70 + @include box-shadow(
  71 + 0px 0px 0px 8px rgba(0,0,0,.1)
  72 + ,0px 0px 3px 1px rgba(0,0,0,.1)
  73 + ,inset 0 8px 3px -8px rgba(255,255,255,.4));
  74 + height: 260px;
  75 + min-height: 260px;
  76 + padding: 25px;
  77 + width: 260px;
  78 + min-width: 260px;
  79 +
  80 + color: #424242;
  81 + font-family:sans-serif;
  82 + font-size:48px;
  83 +
  84 + input {
  85 + display:none
  86 + }
  87 +
  88 + .on,.off {
  89 + position:absolute;
  90 + text-align:center;
  91 + @include text-shadow(1px 1px 4px #4a4a4a);
  92 + width:100%;
  93 + }
  94 +
  95 + .on {
  96 + color:#444;
  97 + top:10px;
  98 + @include transition(all 0.1s);
  99 + font-family:sans-serif
  100 + }
  101 +
  102 + .off {
  103 + bottom:5px;
  104 + @include transition(all 0.1s);
  105 + @include transform(scaleY(0.85));
  106 + }
  107 +
  108 + .but {
  109 + cursor: pointer;
  110 + background-color:#d8d8d8;
  111 + border-radius: 400px 400px 400px 400px / 400px 400px 300px 300px;
  112 + border-bottom-width:0px;
  113 + @include box-shadow(inset 8px 6px 5px -7px #a2a2a2,
  114 + inset -8px 6px 5px -7px #a2a2a2,
  115 + inset 0 -3px 2px -2px rgba(200, 200, 200, 0.5),
  116 + 0 3px 3px -2px #ffffff,
  117 + inset 0 -230px 60px -200px rgba(255, 255, 255, 0.2),
  118 + inset 0 220px 40px -200px rgba(0, 0, 0, 0.3));
  119 + display:block;
  120 + font-size:48px;
  121 + height:178px;
  122 + position:relative;
  123 + @include transition(all 0.2s);
  124 + width:200px;
  125 + }
  126 +
  127 + .back {
  128 + cursor: pointer;
  129 + background-color: #888787;
  130 + 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%);
  131 + 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%);
  132 + 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%);
  133 + 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%);
  134 + 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%);
  135 + border-radius:105px;
  136 + @include box-shadow(30px 30px 30px -20px rgba(58, 58, 58, 0.3),
  137 + -30px 30px 30px -20px rgba(58, 58, 58, 0.3),
  138 + 0 30px 30px 0px rgba(16, 16, 16, 0.3),
  139 + inset 0 -1px 0 0 #484848);
  140 + @include box-sizing(border-box);
  141 + height:210px;
  142 + padding:4px 4px;
  143 + @include transition(all 0.2s);
  144 + width:210px;
  145 + }
  146 +
  147 +
  148 + input:checked + .back .on,input:checked + .back .off{
  149 + @include text-shadow(1px 1px 4px #4a4a4a);
  150 + }
  151 + input:checked + .back .on{
  152 + color:#4c4c4c;
  153 + top:10px;
  154 + @include transform(scaleY(0.85));
  155 + }
  156 + input:checked + .back .off{
  157 + color:#444;
  158 + bottom:5px;
  159 + @include transform(scaleY(1));
  160 + }
  161 + input:checked + .back .but{
  162 + background:#dcdcdc;
  163 + background-image: -owg-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent);
  164 + background-image: -webkit-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent);
  165 + background-image: -moz-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent);
  166 + background-image: -o-radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent);
  167 + background-image: radial-gradient(50% 15%, circle closest-corner, rgba(0, 0, 0, 0.3), transparent);
  168 + border-radius: 400px 400px 400px 400px / 300px 300px 400px 400px;
  169 + @include box-shadow(inset 8px -4px 5px -7px #a9a9a9,
  170 + inset -8px -4px 5px -7px #808080,
  171 + 0 -3px 8px -4px rgba(50, 50, 50, 0.4),
  172 + inset 0 3px 4px -2px #9c9c9c,
  173 + inset 0 280px 40px -200px rgba(0, 0, 0, 0.2),
  174 + inset 0 -200px 40px -200px rgba(180, 180, 180, 0.2));
  175 + margin-top:20px;
  176 + }
  177 + input:checked + .back{
  178 +
  179 + 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%);
  180 + 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%);
  181 + 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%);
  182 + 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%);
  183 + 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%);
  184 +
  185 + @include box-shadow(30px 30px 30px -20px rgba(49, 49, 49, 0.1),
  186 + -30px 30px 30px -20px rgba(111, 111, 111, 0.1),
  187 + 0 30px 30px 0px rgba(0, 0, 0, 0.2),
  188 + inset 0 1px 2px 0 rgba(167, 167, 167, 0.6));
  189 + padding:2px 4px;
  190 + }
  191 +
  192 + }
  193 + }
  194 +}
  195 +
... ...
  1 +<!--
  2 +
  3 + Copyright © 2016-2017 The Thingsboard Authors
  4 +
  5 + Licensed under the Apache License, Version 2.0 (the "License");
  6 + you may not use this file except in compliance with the License.
  7 + You may obtain a copy of the License at
  8 +
  9 + http://www.apache.org/licenses/LICENSE-2.0
  10 +
  11 + Unless required by applicable law or agreed to in writing, software
  12 + distributed under the License is distributed on an "AS IS" BASIS,
  13 + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14 + See the License for the specific language governing permissions and
  15 + limitations under the License.
  16 +
  17 +-->
  18 +<div class="tb-round-switch" layout="column" ng-style="{'pointerEvents': vm.ctx.isEdit ? 'none' : 'all'}">
  19 + <div flex="20" class="title-container" layout="row" layout-align="center center" ng-show="vm.showTitle">
  20 + <span class="switch-title">{{vm.title}}</span>
  21 + </div>
  22 + <div flex="{{vm.showTitle ? 80 : 100}}" ng-style="{paddingTop: vm.showTitle ? '5px': '10px'}" id="switch-container" layout="column" layout-align="center center">
  23 + <div class="switch">
  24 + <input type="checkbox" id="{{vm.checkboxId}}" name="onoff" />
  25 + <div class="back">
  26 + <label class="but" for="{{vm.checkboxId}}">
  27 + <span class="on">I</span>
  28 + <span class="off">0</span>
  29 + </label>
  30 + </div>
  31 + </div>
  32 + </div>
  33 + <div class="error-container" ng-style="{'background': vm.error.length ? 'rgba(255,255,255,0.25)' : 'none'}"
  34 + layout="row" layout-align="center center">
  35 + <span class="switch-error">{{ vm.error }}</span>
  36 + </div>
  37 + <div id="text-measure"></div>
  38 +</div>
... ...