Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery knob angular gradient

Is there any way to add angular gradient to jQuery knob plugin, so that it starts from one color and along the arc, changes into another?

like image 628
Adee Avatar asked Feb 06 '13 14:02

Adee


2 Answers

I digged the internet for a solution but no one ever tried this or posted a solution. Finally I am posting a Q&A. If anyone has a better solution, please share with us.

During the initialization, I have overridden the draw method and checked for the attribute shaded="true". If it's there, then a gradient is formed, starting from white and moving towards fgColor. To chose starting color other than white, set the attribute shadeColor="#(color hex code)".

<input class="knob" value="95" autocomplete="off" data-readOnly=true data-fgColor="#FF0000" data-bgColor="transparent" shaded="1" shadeColor="#00FF00"/>
<script>
    $(function(){
        $('.knob').knob({
            draw : function () {
                var a = this.angle(this.cv)  // Angle
                , sa = this.startAngle          // Previous start angle
                , sat = this.startAngle         // Start angle
                , ea                            // Previous end angle
                , eat = sat + a                 // End angle
                , r = 1;

                this.g.lineWidth = this.lineWidth;

                if(this.$.attr('shaded')){
                    var color1 = r ? this.o.fgColor : this.fgColor;
                    var color2 = this.$.attr('shadeColor') ? this.$.attr('shadeColor') : '#ffffff';
                    var grad = getGradient(color2, color1);

                    var saDeg = parseInt((sa * 180 / Math.PI) % 360);
                    var eatDeg = parseInt((eat * 180 / Math.PI) % 360);

                    for(var angle = saDeg;(angle % 360) != eatDeg;angle++){
                        sat = angle * (Math.PI / 180);
                        eat = (angle + 2) * (Math.PI / 180);

                        if(grad.color2[0] != grad.color1[0] && (angle + 1) % grad.steps[0] == 0){
                            grad.color1[0] += grad.adder[0];
                        }
                        if(grad.color2[1] != grad.color1[1] && (angle + 1) % grad.steps[1] == 0){
                            grad.color1[1] += grad.adder[1];
                        }
                        if(grad.color2[2] != grad.color1[2] && (angle + 1) % grad.steps[2] == 0){
                            grad.color1[2] += grad.adder[2];
                        }

                        color = '#' + toHex(grad.color1[0]) + toHex(grad.color1[1]) + toHex(grad.color1[2]);

                        this.g.beginPath();
                        this.g.strokeStyle = color;
                        this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
                        this.g.stroke();
                    }
                } else {
                    this.g.beginPath();
                    this.g.strokeStyle = r ? this.o.fgColor : this.fgColor ;
                    this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
                    this.g.stroke();
                }

                return false;
            }
        });
    });

    function getGradient(color1, color2){
        var ret = new Object();

        ret.color1 = new Array();
        ret.color2 = new Array();
        ret.steps = new Array();
        ret.adder = new Array();

        color1 = color1.replace('#','');
        ret.color1[0] = parseInt(color1.slice(0,2), 16),
        ret.color1[1] = parseInt(color1.slice(2,4), 16),
        ret.color1[2] = parseInt(color1.slice(4,6), 16);

        color2 = color2.replace('#','');
        ret.color2[0] = parseInt(color2.slice(0,2), 16),
        ret.color2[1] = parseInt(color2.slice(2,4), 16),
        ret.color2[2] = parseInt(color2.slice(4,6), 16);

        ret.steps[0] = (ret.color1[0] == ret.color2[0])? 0 : parseInt(360 / Math.abs(ret.color1[0] - ret.color2[0])),
        ret.steps[1] = (ret.color1[1] == ret.color2[1])? 0 : parseInt(360 / Math.abs(ret.color1[1] - ret.color2[1])),
        ret.steps[2] = (ret.color1[2] == ret.color2[2])? 0 : parseInt(360 / Math.abs(ret.color1[2] - ret.color2[2])),

        ret.adder[0] = (ret.color1[0] > ret.color2[0])? -1 : 1;
        ret.adder[1] = (ret.color1[1] > ret.color2[1])? -1 : 1;
        ret.adder[2] = (ret.color1[2] > ret.color2[2])? -1 : 1;

        return ret;
    }

    function toHex(number){
        number = number.toString(16);
        if(number.length < 2){
            number = '0' + number;
        }
        return number;
    }
</script>

It draws a separate arc for each degree (with arc angle of 2 degrees instead of one for the sake of smoothness). The colors of arcs go through a transition from fgColor to shadeColor.

The color mixing effect is like paint mixing rather than light mixing, so if you start from green and go towards red, you won't get the yellow shade in the center. It would look cool with light mixing effect but don't know how to do that exactly. Also it is not a well optimized code, it's just a solution. Huge room for improvement..

like image 114
Adee Avatar answered Sep 27 '22 23:09

Adee


Great, exactly what I needed! I added the "cursor" option as well, because that was the only thing that was not working yet.

var drawGradient = function () {

    var a = this.angle(this.cv)  // Angle
        , sa = this.startAngle          // Previous start angle
        , sat = this.startAngle         // Start angle
        , eat = sat + a                 // End angle
        , r = 1;

    this.g.lineCap = this.lineCap;
    this.g.lineWidth = this.lineWidth;

    if (this.o.bgColor !== "none") {
        this.g.beginPath();
        this.g.strokeStyle = this.o.bgColor;
        this.g.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
        this.g.stroke();
    }

    if (this.$.attr('shaded')) {
        var color1 = r ? this.o.fgColor : this.fgColor;
        var color2 = this.$.attr('shadeColor') ? this.$.attr('shadeColor') : '#ffffff';
        var grad = getGradient(color2, color1);

        var saDeg = parseInt((sa * 180 / Math.PI) % 360);
        var eatDeg = parseInt((eat * 180 / Math.PI));

        var normalizedAngle = 0
        var normalizedEatAngle = eatDeg - saDeg;

        if(this.o.cursor == true) {
            var size = 40;
        } else if(this.o.cursor != false) {
            var size = this.o.cursor;
            this.o.cursor = true;
        }

        if(this.o.cursor) {
            if(normalizedEatAngle <= size) {
                normalizedEatAngle = size;
            }
        }
        for (var angle = saDeg; normalizedAngle < normalizedEatAngle; angle++, normalizedAngle++) {

            sat = angle * (Math.PI / 180);
            eat = (angle + 2) * (Math.PI / 180);

            if (grad.color2[0] != grad.color1[0] && (angle + 1) % grad.steps[0] == 0) {
                grad.color1[0] += grad.adder[0];
            }
            if (grad.color2[1] != grad.color1[1] && (angle + 1) % grad.steps[1] == 0) {
                grad.color1[1] += grad.adder[1];
            }
            if (grad.color2[2] != grad.color1[2] && (angle + 1) % grad.steps[2] == 0) {
                grad.color1[2] += grad.adder[2];
            }


            if(!this.o.cursor || (normalizedAngle + size) > normalizedEatAngle) {
                color = '#' + toHex(grad.color1[0]) + toHex(grad.color1[1]) + toHex(grad.color1[2]);
                this.g.beginPath();
                this.g.strokeStyle = color;
                this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
                this.g.stroke();
            }
        }
    } else {
        this.g.beginPath();
        this.g.strokeStyle = r ? this.o.fgColor : this.fgColor;
        this.g.arc(this.xy, this.xy, this.radius, sat, eat, false);
        this.g.stroke();
    }

    return false;
};
like image 25
elbowz Avatar answered Sep 28 '22 01:09

elbowz