Skip to content
Browse files

Revision 1.1.2

- removed padding around the wheel in default skin
- 'configure' event
- added 'displayPrevious' option
- change color cgColor / 'displayPrevious' must be true
- escape keycode supported while changing = restore the current value
- tab keycode supported
- added 'stopper'
- bugfix init when 'value' attribute is not defined
- JSLint qa
- infinite mode demo
  • Loading branch information...
1 parent 0a3dd8d commit dc9df18e9c8bf34105c76c50013385a8adb37394 @aterrien committed May 22, 2012
Showing with 469 additions and 18 deletions.
  1. +47 −18 index.html
  2. +422 −0 js/jquery.knob-1.1.2.js
View
65 index.html
@@ -3,7 +3,7 @@
<head>
<title>jQuery Knob demo</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
- <script src="js/jquery.knob-1.1.1.js"></script>
+ <script src="js/jquery.knob-1.1.2.js"></script>
<script>
$(function() {
$(".knob").knob();
@@ -16,7 +16,10 @@
,decr = function() { i--; $idir.show().html("-").fadeOut(); $ival.html(i); };
$("input.infinite").knob(
{
- 'change':function(v){
+ 'min':0
+ ,'max':20
+ ,'stopper':false
+ ,'change':function(v){
if(val>v){
if(up){
decr();
@@ -34,6 +37,27 @@
}
);
+
+ // Automatic mode
+ /*var autoVal = 0
+ ,timer = setInterval(function() {
+ $(".knob").each(
+ function(){
+ $(this)
+ .val(Math.round(Math.sin(autoVal)*100))
+ .trigger('change');
+ }
+ );
+ autoVal++;
+ }, 100);*/
+
+ // Configure
+ /*$(".knob").val(25).trigger(
+ "configure",
+ {"min":10, "max":40, "fgColor":"#FF0000", "skin":"tron", "cursor":true}
+ );*/
+
+ // Change example
/*$(".knob").knob(
{
'change':function(e){
@@ -46,30 +70,32 @@
});
</script>
<style>
- h2{color:#87CEEB;font-family:Georgia;}
+ h2{color:#87CEEB;font-family:'Georgia';}
</style>
</head>
<body>
- <div style="float:left;width:100%;font-family:Georgia;font-size:70px;font-weight:bold;color:#87CEEB;letter-spacing:-5px">
+ <div style="float:left;width:100%;font-family:'Georgia';font-size:70px;font-weight:bold;color:#87CEEB;letter-spacing:-5px">
Knob demo <a href="http://flattr.com/thing/674900/jQuery-Knob" target="_blank">
-<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>
+ <img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a>
</div>
<div style="float:left;width:300px;height:300px;background-color:#222;color:#FFF;padding:20px">
<pre>
data-width="75"
data-fgColor="#fff"
data-skin="tron"
+data-displayPrevious=true
</pre>
- <input class="knob" data-width="75" data-fgColor="#ffec03" data-skin="tron" data-cursor=true value="75">
+ <input class="knob" data-width="75" data-displayPrevious=true data-fgColor="#ffec03" data-skin="tron" data-cursor=true value="75">
</div>
<div style="float:left;width:300px;height:300px;background-color:#222;color:#FFF;padding:20px">
<pre>
data-width="150"
data-fgColor="#fff"
data-skin="tron"
data-thickness=".2"
+data-displayPrevious=true
</pre>
- <input class="knob" data-width="150" data-fgColor="#ffec03" data-skin="tron" data-thickness=".2" value="75">
+ <input class="knob" data-width="150" data-displayPrevious=true data-fgColor="#ffec03" data-skin="tron" data-thickness=".2" value="75">
</div>
<div style="float:left;width:300px;height:300px;background-color:#222;color:#FFF;padding:20px">
<pre>
@@ -80,26 +106,29 @@
</pre>
<input class="knob" data-width="150" data-fgColor="#C0ffff" data-skin="tron" data-thickness=".1" value="35">
</div>
- <div style="float:left;width:250px;height:350px;padding:20px">
+ <div style="clear:both"></div>
+ <div style="float:left;width:300px;height:300px;padding:20px">
<pre>
data-width="100"
data-displayInput=false
</pre>
<input class="knob" data-width="100" data-displayInput=false value="35">
</div>
- <div style="float:left;width:350px;height:350px;padding:20px">
+ <div style="float:left;width:300px;height:300px;padding:20px">
<pre>
-data-width="300"
+data-width="200"
data-cursor=true
</pre>
- <input class="knob" data-width="300" data-cursor=true value="29">
+ <input class="knob" data-width="200" data-cursor=true value="29">
</div>
- <div style="float:left;width:300px;height:350px;padding:20px">
+ <div style="float:left;width:300px;height:300px;padding:20px">
<pre>
-data-width="250"
+data-width="200"
data-min="-100"
+data-cgColor="#A9EFFD"
+data-displayPrevious=true
</pre>
- <input class="knob"data-width="250" data-min="-100" value="44">
+ <input class="knob"data-width="200" data-min="-100" data-displayPrevious=true value="44">
</div>
<div style="clear:both"></div>
<div style="float:left;width:300px;height:320px;padding:20px">
@@ -137,17 +166,17 @@
<div style="clear:both"></div>
<div style="float:left;height:440px;width:420px;padding:20px">
<h2>Infinite / iPod click wheel</h2>
- <div style="float:left;width:200px;height:350px;padding:20px;background-color:#EEEEEE;">
+ <div style="float:left;width:200px;height:300px;padding:20px;background-color:#EEEEEE;text-align:center;">
<pre>
-data-width="200"
+data-width="150"
data-cursor=true
-data-thickness=".4"
+data-thickness=".5"
data-fgColor="#AAAAAA"
data-bgColor="#FFFFFF"
data-displayInput="false"
+ some code
</pre>
- <input class="infinite" data-width="200" data-thickness=".4" data-fgColor="#AAAAAA" data-bgColor="#FFFFFF" data-displayInput="false" data-cursor=true>
+ <input class="infinite" data-width="150" data-thickness=".5" data-fgColor="#AAAAAA" data-bgColor="#FFFFFF" data-displayInput="false" data-cursor=true>
</div>
<div style="float:left;margin-top:200px;">
<div class="ival" style="width:100px;text-align:center;font-size:50px;color:#AAA">0</div>
View
422 js/jquery.knob-1.1.2.js
@@ -0,0 +1,422 @@
+/**
+ * Knob - jQuery Plugin
+ * Downward compatible, touchable dial
+ *
+ * Version: 1.1.2 (10/05/2012)
+ * Requires: jQuery v1.7+
+ *
+ * Copyright (c) 2011 Anthony Terrien
+ * Under MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Thanks to vor, eskimoblood, spiffistan
+ */
+$(function () {
+
+ // Dial logic
+ var Dial = function (c, opt) {
+
+ var v = null
+ ,ctx = c[0].getContext("2d")
+ ,PI2 = 2*Math.PI
+ ,mx ,my ,x ,y
+ ,self = this;
+
+ this.onChange = function () {};
+ this.onCancel = function () {};
+ this.onRelease = function () {};
+
+ this.val = function (nv) {
+ if (null != nv) {
+ opt.stopper && (nv = Math.max(Math.min(nv, opt.max), opt.min));
+ v = nv;
+ this.onChange(nv);
+ this.draw(nv);
+ } else {
+ var b, a;
+ b = a = Math.atan2(mx - x, -(my - y - opt.width / 2));
+ (a < 0) && (b = a + PI2);
+ nv = Math.round(b * (opt.max - opt.min) / PI2) + opt.min;
+ return (nv > opt.max) ? opt.max : nv;
+ }
+ };
+
+ this.change = function (nv) {
+ opt.stopper && (nv = Math.max(Math.min(nv, opt.max), opt.min));
+ this.onChange(nv);
+ this.draw(nv);
+ };
+
+ this.angle = function (nv) {
+ return (nv - opt.min) * PI2 / (opt.max - opt.min);
+ };
+
+ this.draw = function (nv) {
+
+ var a = this.angle(nv)
+ ,sa = 1.5 * Math.PI // Start angle
+ ,sat = sa
+ ,ea = sa + this.angle(v) // End angle
+ ,eat = sat + a
+ ,r = opt.width / 2 // Radius
+ ,lw = r * opt.thickness // Line width
+ ,cgcolor = Dial.getCgColor(opt.cgColor)
+ ,tick
+ ;
+
+ ctx.clearRect(0, 0, opt.width, opt.width);
+ ctx.lineWidth = lw;
+
+ // Hook draw
+ //{"startAngle":sa,"endAngle":ea,"radius":r,"lineWidth":lw}
+ if (opt.draw(a, v, opt, ctx)) { return; }
+
+ for (tick = 0; tick < opt.ticks; tick++) {
+
+ ctx.beginPath();
+
+ if (a > (((2 * Math.PI) / opt.ticks) * tick) && opt.tickColorizeValues) {
+ ctx.strokeStyle = opt.fgColor;
+ } else {
+ ctx.strokeStyle = opt.tickColor;
+ }
+
+ var tick_sa = (((2 * Math.PI) / opt.ticks) * tick) - (0.5 * Math.PI);
+ ctx.arc( r, r, r-lw-opt.tickLength, tick_sa, tick_sa+opt.tickWidth , false);
+ ctx.stroke();
+ }
+
+ opt.cursor
+ && (sa = ea - 0.3)
+ && (ea = ea + 0.3)
+ && (sat = eat - 0.3)
+ && (eat = eat + 0.3);
+
+ switch (opt.skin) {
+
+ case 'default' :
+
+ ctx.beginPath();
+ ctx.strokeStyle = opt.bgColor;
+ ctx.arc(r, r, r - lw / 2, 0, PI2, true);
+ ctx.stroke();
+
+ if (opt.displayPrevious) {
+ ctx.beginPath();
+ ctx.strokeStyle = (v == nv) ? opt.fgColor : cgcolor;
+ ctx.arc(r, r, r - lw / 2, sa, ea, false);
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.strokeStyle = opt.fgColor;
+ ctx.arc(r, r, r - lw / 2, sat, eat, false);
+ ctx.stroke();
+
+ break;
+
+ case 'tron' :
+
+ if (opt.displayPrevious) {
+ ctx.beginPath();
+ ctx.strokeStyle = (v == nv) ? opt.fgColor : cgcolor;
+ ctx.arc( r, r, r - lw, sa, ea, false);
+ ctx.stroke();
+ }
+
+ ctx.beginPath();
+ ctx.strokeStyle = opt.fgColor;
+ ctx.arc( r, r, r - lw, sat, eat, false);
+ ctx.stroke();
+
+ ctx.lineWidth = 2;
+ ctx.beginPath();
+ ctx.strokeStyle = opt.fgColor;
+ ctx.arc( r, r, r - lw + 1 + lw * 2 / 3, 0, 2 * Math.PI, false);
+ ctx.stroke();
+
+ break;
+ }
+ };
+
+ this.capture = function (e) {
+ switch (e.type) {
+ case 'mousemove' :
+ case 'mousedown' :
+ mx = e.pageX;
+ my = e.pageY;
+ break;
+ case 'touchmove' :
+ case 'touchstart' :
+ mx = e.originalEvent.touches[0].pageX;
+ my = e.originalEvent.touches[0].pageY;
+ break;
+ }
+ this.change( this.val() );
+ };
+
+ this.cancel = function () {
+ self.val(v);
+ self.onCancel();
+ };
+
+ this.startDrag = function (e) {
+
+ var p = c.position()
+ ,$doc = $(document);
+
+ x = p.left + (opt.width / 2);
+ y = p.top;
+
+ this.capture(e);
+
+ // Listen mouse and touch events
+ $doc.bind(
+ "mousemove.dial touchmove.dial"
+ ,function (e) {
+ self.capture(e);
+ }
+ )
+ .bind(
+ // Escape
+ "keyup.dial"
+ ,function (e) {
+ if(e.keyCode === 27) {
+ $doc.unbind("mouseup.dial mousemove.dial keyup.dial");
+ self.cancel();
+ }
+ }
+ )
+ .bind(
+ "mouseup.dial touchend.dial"
+ ,function (e) {
+ $doc.unbind('mousemove.dial touchmove.dial mouseup.dial touchend.dial keyup.dial');
+ self.val(self.val());
+ self.onRelease(v);
+ }
+ );
+ };
+ };
+
+ // Dial static func
+ Dial.getCgColor = function (h) {
+ h = h.substring(1,7);
+ var rgb = [parseInt(h.substring(0,2),16)
+ ,parseInt(h.substring(2,4),16)
+ ,parseInt(h.substring(4,6),16)];
+ return "rgba("+rgb[0]+","+rgb[1]+","+rgb[2]+",.5)";
+ };
+
+ // jQuery plugin
+ $.fn.knob = $.fn.dial = function (gopt) {
+
+ return this.each(
+
+ function () {
+
+ var $this = $(this), opt;
+
+ if ($this.data('dialed')) { return $this; }
+ $this.data('dialed', true);
+
+ opt = $.extend(
+ {
+ // Config
+ 'min' : $this.data('min') || 0
+ ,'max' : $this.data('max') || 100
+ ,'stopper' : true
+ ,'readOnly' : $this.data('readonly')
+
+ // UI
+ ,'cursor' : $this.data('cursor')
+ ,'thickness' : $this.data('thickness') || 0.35
+ ,'width' : $this.data('width') || 200
+ ,'displayInput' : $this.data('displayinput') == null || $this.data('displayinput')
+ ,'displayPrevious' : $this.data('displayprevious')
+ ,'fgColor' : $this.data('fgcolor') || '#87CEEB'
+ ,'cgColor' : $this.data('cgcolor') || $this.data('fgcolor') || '#87CEEB'
+ ,'bgColor' : $this.data('bgcolor') || '#EEEEEE'
+ ,'tickColor' : $this.data('tickColor') || $this.data('fgcolor') || '#DDDDDD'
+ ,'ticks' : $this.data('ticks') || 0
+ ,'tickLength' : $this.data('tickLength') || 0
+ ,'tickWidth' : $this.data('tickWidth') || 0.02
+ ,'tickColorizeValues' : $this.data('tickColorizeValues') || true
+ ,'skin' : $this.data('skin') || 'default'
+
+ // Hooks
+ ,'draw' :
+ /**
+ * @param int a angle
+ * @param int v current value
+ * @param array opt plugin options
+ * @param context ctx Canvas context 2d
+ * @return bool true:bypass default draw methode
+ */
+ function (a, v, opt, ctx) {}
+ ,'change' :
+ /**
+ * @param int v Current value
+ */
+ function (v) {}
+ ,'release' :
+ /**
+ * @param int v Current value
+ * @param jQuery ipt Input
+ */
+ function (v, ipt) {}
+ }
+ ,gopt
+ );
+
+ var c = $('<canvas width="' + opt.width + '" height="' + opt.width + '"></canvas>')
+ ,wd = $('<div style=width:' + opt.width + 'px;display:inline;"></div>')
+ ,k
+ ,vl = $this.val()
+ ,initStyle = function () {
+ opt.displayInput
+ && $this.css({
+ 'width' : opt.width / 2 + 'px'
+ ,'position' : 'absolute'
+ ,'margin-top' : (opt.width * 5 / 14) + 'px'
+ ,'margin-left' : '-' + (opt.width * 3 / 4) + 'px'
+ ,'font-size' : (opt.width / 4) + 'px'
+ ,'border' : 'none'
+ ,'background' : 'none'
+ ,'font-family' : 'Arial'
+ ,'font-weight' : 'bold'
+ ,'text-align' : 'center'
+ ,'color' : opt.fgColor
+ ,'padding' : '0px'
+ ,'-webkit-appearance': 'none'
+ })
+ || $this.css({
+ 'width' : '0px'
+ ,'visibility' : 'hidden'
+ });
+ };
+
+ // Canvas insert
+ $this.wrap(wd).before(c);
+
+ initStyle();
+
+ // Invoke dial logic
+ k = new Dial(c, opt);
+ vl || (vl = opt.min);
+ $this.val(vl);
+ k.val(vl);
+
+ k.onRelease = function (v) {
+ opt.release(v, $this);
+ };
+ k.onChange = function (v) {
+ $this.val(v);
+ opt.change(v);
+ };
+
+ // bind change on input
+ $this.bind(
+ 'change'
+ ,function (e) {
+ k.val($this.val());
+ }
+ );
+
+ if (!opt.readOnly) {
+
+ // canvas
+ c.bind(
+ "mousedown touchstart"
+ ,function (e) {
+ e.preventDefault();
+ k.startDrag(e);
+ }
+ )
+ .bind(
+ "mousewheel DOMMouseScroll"
+ ,mw = function (e) {
+ e.preventDefault();
+ var ori = e.originalEvent
+ ,deltaX = ori.detail || ori.wheelDeltaX
+ ,deltaY = ori.detail || ori.wheelDeltaY
+ ,val = parseInt($this.val()) + (deltaX>0 || deltaY>0 ? 1 : deltaX<0 || deltaY<0 ? -1 : 0);
+ k.val(val);
+ }
+ );
+
+ // input
+ var kval, val, to, m = 1, kv = {37:-1, 38:1, 39:1, 40:-1};
+ $this
+ .bind(
+ "configure"
+ ,function (e, aconf) {
+ var kconf;
+ for (kconf in aconf) { opt[kconf] = aconf[kconf]; }
+ initStyle();
+ k.val($this.val());
+ }
+ )
+ .bind(
+ "keydown"
+ ,function (e) {
+ var kc = e.keyCode;
+ kval = parseInt(String.fromCharCode(kc));
+
+ if (isNaN(kval)) {
+
+ (kc !== 13) // enter
+ && (kc !== 8) // bs
+ && (kc !== 9) // tab
+ && (kc !== 189) // -
+ && e.preventDefault();
+
+ // arrows
+ if ($.inArray(kc,[37,38,39,40]) > -1) {
+ k.change(parseInt($this.val()) + kv[kc] * m);
+
+ // long time keydown speed-up
+ to = window.setTimeout(
+ function () { m < 20 && m++; }
+ ,50
+ );
+
+ e.preventDefault();
+ }
+ }
+ }
+ )
+ .bind(
+ "keyup"
+ ,function(e) {
+ if (isNaN(kval)) {
+ if (to) {
+ window.clearTimeout(to);
+ to = null;
+ m = 1;
+ k.val($this.val());
+ k.onRelease($this.val(), $this);
+ } else {
+ // enter
+ (e.keyCode === 13)
+ && k.onRelease($this.val(), $this);
+ }
+ } else {
+ // kval postcond
+ ($this.val() > opt.max && $this.val(opt.max))
+ || ($this.val() < opt.min && $this.val(opt.min));
+ }
+
+ }
+ )
+ .bind(
+ "mousewheel DOMMouseScroll"
+ ,mw
+ );
+ } else {
+ $this.attr('readonly', 'readonly');
+ }
+ }
+ ).parent();
+ };
+});

0 comments on commit dc9df18

Please sign in to comment.
Something went wrong with that request. Please try again.