Search code examples
javascriptjqueryjquery-knob

wrong value passed to format hook function after set value , jQuery Knob


I am using jQuery knob, and I have below code:

var knobOption={//ref: https://github.com/aterrien/jQuery-Knob
    'min':0,
    'max':1,
    'width':100,
    'height':100,
    'thickness':0.1,
    'readOnly':true,//READ ONLY
    'fgColor': '#31bbff',
    //'bgColor':'#626262',
    'inputColor':'#868686',
    'change': function (v) {
        console.log("knob change:",v);
    },
    'format':function(value){//format to percentage
        console.log('fomarting knob ',value);
        if(isNaN(value)) return "-";
        else return (value*100).toFixed(1)+"%";//percentage
    },

    'draw' : function(){
        console.log("drawing",$(this).find('.knob'));
        $(this.i).css("font-size","19px");
    }
}

var $retention = this.$overviewHandler.find('#retention_wrapper');
$retention.find('#1_day .knob').knob(knobOption);
$retention.find('#3_day .knob').knob(knobOption);
$retention.find('#7_day .knob').knob(knobOption);

After this, I will call below at Ajax callback:

        $retention.find('#1_day .knob').val(oneDayRet).trigger('change');
        $retention.find('#3_day .knob').val(threeDayRet).trigger('change');
        $retention.find('#7_day .knob').val(sevenDayRet).trigger('change');

But after this, I found the value in format hook is 1, even though I pass a value of 0.704. So the knob display 100% where is not what I want.

What's my problem?


Solution

  • I've looked at this some more. I think you can achieve what you want by passing in values between 1 and 1000 and then formatting.

    You would pass in a value between 1 and 1000. Instead of .704 pass in 704. You're formatting line would then become: return (value*.1).toFixed(1)+"%";

    Your new knobOptions would look like the following. The max value is 1000 and the formatting method has been changed.

    var knobOption={//ref: https://github.com/aterrien/jQuery-Knob
        'min':0,
        'max':1000,
        'width':100,
        'height':100,
        'thickness':0.1,
        'readOnly':true,//READ ONLY
        'fgColor': '#31bbff',
        //'bgColor':'#626262',
        'inputColor':'#868686',
        'change': function (v) {
            console.log("knob change:",v);
        },
        'format':function(value){//format to percentage
            console.log('fomarting knob ',value);
            if(isNaN(value)) return "-";
            else return (value*.1).toFixed(1)+"%";//percentage
        },
    
        'draw' : function(){
            console.log("drawing",$(this).find('.knob'));
            $(this.i).css("font-size","19px");
        }
    }
    

    Edit

    Because we are messing with the output of the value in our format method, we also need to reverse that formatting in a .parse method.

    So add the following .parse method in your jQuery knob options and things should start working as expected. Essentially what we want to do is check if our formatting is applied. To do this we check if the value ends in a %. If it does then we assume our formatting is applied and divide the value by .1 (because we multiplied by .1 in the format method).

    // ... codez
     'format': function(value) {
         if (isNaN(value)) return "-";
         return (value * .1).toFixed(1) + "%"; //percentage
     },
     'parse': function(value) {
         if (typeof(value) !== 'string') return value; // if we don't have a string, then don't bother parsing
         if(value === '-') return value;
         var suffix = '%';
         // see https://stackoverflow.com/a/2548133/296889
         if (value.indexOf(suffix, value.length - suffix.length) === -1) return parseFloat(value);
         return parseFloat(value) / .1; // there is special formatting, parse and convert
     },
    // ... more codez
    

    The reason for the original issue, as far as I can tell, is due to the libraries usage of ~~ to round values. The ~~ appears to truncate any values after a decimal point.

    The library is doing the following: var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step; So let's run through it really quick with .704.

    (v < 0) ? -0.5 : 0.5 .704 is less than 0. We end up with 0.5.

    0.5 + (v/this.o.step) - this.o.step is 1. .704 divided by 1 + 0.5 is 1.204.

    ~~1.204 - this yields 1.

    (1) * this.o.step - this.o.step is 1. 1 times 1 is still 1. The result of the entire process yields 1.

    That is why you get a 1 when you enter in a .704. Therefore, as mentioned above, the solution would be to give input that does not have decimal values (so that they do not get stripped out by the ~~).