diff --git a/index.html b/index.html index ac450e0..5aeddca 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ jQuery Knob demo - + -
+
Knob demo -Flattr this + Flattr this
 data-width="75"
 data-fgColor="#fff"
 data-skin="tron"
+data-displayPrevious=true
             
- +
@@ -68,8 +93,9 @@
 data-fgColor="#fff"
 data-skin="tron"
 data-thickness=".2"
+data-displayPrevious=true
             
- +
@@ -80,26 +106,29 @@
             
-
+
+
 data-width="100"
 data-displayInput=false
             
-
+
-data-width="300"
+data-width="200"
 data-cursor=true
             
- +
-
+
-data-width="250"
+data-width="200"
 data-min="-100"
+data-cgColor="#A9EFFD"
+data-displayPrevious=true
             
- +
@@ -137,17 +166,17 @@

Knobify!

Infinite / iPod click wheel

-
+
-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
                 
- +
0
diff --git a/js/jquery.knob-1.1.2.js b/js/jquery.knob-1.1.2.js new file mode 100644 index 0000000..2654507 --- /dev/null +++ b/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 = $('') + ,wd = $('
') + ,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(); + }; +}); \ No newline at end of file