0

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?

JaskeyLam
  • 15,405
  • 21
  • 114
  • 149

1 Answers1

0

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 ~~).

Community
  • 1
  • 1
jeremysawesome
  • 7,033
  • 5
  • 33
  • 37
  • I tried and found another bug, when I click on the knob and click outside, which will trigger "release" and then format, in this format hook method, 709 becomes 71.....and the values changes. – JaskeyLam Jun 18 '15 at 02:32
  • Yeah - that's a bit frustrating. Ideally a `format` method shouldn't have any impact on what the actual value is - just how it is formatted. Still thinking about this... – jeremysawesome Jun 18 '15 at 04:09
  • @Jaskey - I've updated this method with an edit to address the bug. I believe it works as expected now. – jeremysawesome Jun 18 '15 at 04:33
  • Yeah, I figure out we should hook `parse` method before I read you updated answer. But there still be a problem: when the value is '-', and the release triggered, the value will be updated to "0.0%" . I debug this, the "parse" hook is called twice, the first time, value is "-", the second time it becomes "0", and then when calls format, the value is "0", so formating to "0.0%". Any idea to deal with this? – JaskeyLam Jun 18 '15 at 06:17
  • Maybe add an additional condition to check for that in the if statement? I've done so in the parse method above. – jeremysawesome Jun 19 '15 at 00:42
  • `if(value === '-') return value;` does not solve the problem, do you solve it? Would you please provide a fiddler? – JaskeyLam Jun 19 '15 at 04:26