shiny-knob.directive.js 5.62 KB
/*
 * 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;
        });
    }

}