Blame | Last modification | View Log | RSS feed
/*!jQuery Knob*//*** Downward compatible, touchable dial** Version: 1.2.0 (15/07/2012)* Requires: jQuery v1.7+** Copyright (c) 2012 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, FabrizioC*/(function($) {/*** Kontrol library*/"use strict";/*** Definition of globals and core*/var k = {}, // kontrolmax = Math.max,min = Math.min;k.c = {};k.c.d = $(document);k.c.t = function (e) {return e.originalEvent.touches.length - 1;};/*** Kontrol Object** Definition of an abstract UI control** Each concrete component must call this one.* <code>* k.o.call(this);* </code>*/k.o = function () {var s = this;this.o = null; // array of optionsthis.$ = null; // jQuery wrapped elementthis.i = null; // mixed HTMLInputElement or array of HTMLInputElementthis.g = null; // 2D graphics context for 'pre-rendering'this.v = null; // value ; mixed array or integerthis.cv = null; // change value ; not commited valuethis.x = 0; // canvas x positionthis.y = 0; // canvas y positionthis.$c = null; // jQuery canvas elementthis.c = null; // rendered canvas contextthis.t = 0; // touches indexthis.isInit = false;this.fgColor = null; // main colorthis.pColor = null; // previous colorthis.dH = null; // draw hookthis.cH = null; // change hookthis.eH = null; // cancel hookthis.rH = null; // release hookthis.run = function () {var cf = function (e, conf) {var k;for (k in conf) {s.o[k] = conf[k];}s.init();s._configure()._draw();};if(this.$.data('kontroled')) return;this.$.data('kontroled', true);this.extend();this.o = $.extend({// Configmin : this.$.data('min') || 0,max : this.$.data('max') || 100,stopper : true,readOnly : this.$.data('readonly'),// UIcursor : (this.$.data('cursor') === true && 30)|| this.$.data('cursor')|| 0,thickness : this.$.data('thickness') || 0.35,width : this.$.data('width') || 200,height : this.$.data('height') || 200,displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'),displayPrevious : this.$.data('displayprevious'),fgColor : this.$.data('fgcolor') || '#87CEEB',inline : false,// Hooksdraw : null, // function () {}change : null, // function (value) {}cancel : null, // function () {}release : null // function (value) {}}, this.o);// routing valueif(this.$.is('fieldset')) {// fieldset = array of integerthis.v = {};this.i = this.$.find('input')this.i.each(function(k) {var $this = $(this);s.i[k] = $this;s.v[k] = $this.val();$this.bind('change', function () {var val = {};val[k] = $this.val();s.val(val);});});this.$.find('legend').remove();} else {// input = integerthis.i = this.$;this.v = this.$.val();(this.v == '') && (this.v = this.o.min);this.$.bind('change', function () {s.val(s.$.val());});}(!this.o.displayInput) && this.$.hide();this.$c = $('<canvas width="' +this.o.width + 'px" height="' +this.o.height + 'px"></canvas>');this.c = this.$c[0].getContext("2d");this.$.wrap($('<div style="' + (this.o.inline ? 'display:inline;' : '') +'width:' + this.o.width + 'px;height:' +this.o.height + 'px;"></div>')).before(this.$c);if (this.v instanceof Object) {this.cv = {};this.copy(this.v, this.cv);} else {this.cv = this.v;}this.$.bind("configure", cf).parent().bind("configure", cf);this._listen()._configure()._xy().init();this.isInit = true;this._draw();return this;};this._draw = function () {// canvas pre-renderingvar d = true,c = document.createElement('canvas');c.width = s.o.width;c.height = s.o.height;s.g = c.getContext('2d');s.clear();s.dH&& (d = s.dH());(d !== false) && s.draw();s.c.drawImage(c, 0, 0);c = null;};this._touch = function (e) {var touchMove = function (e) {var v = s.xy2val(e.originalEvent.touches[s.t].pageX,e.originalEvent.touches[s.t].pageY);if (v == s.cv) return;if (s.cH&& (s.cH(v) === false)) return;s.change(v);s._draw();};// get touches indexthis.t = k.c.t(e);// First touchtouchMove(e);// Touch events listenersk.c.d.bind("touchmove.k", touchMove).bind("touchend.k", function () {k.c.d.unbind('touchmove.k touchend.k');if (s.rH&& (s.rH(s.cv) === false)) return;s.val(s.cv);});return this;};this._mouse = function (e) {var mouseMove = function (e) {var v = s.xy2val(e.pageX, e.pageY);if (v == s.cv) return;if (s.cH&& (s.cH(v) === false)) return;s.change(v);s._draw();};// First clickmouseMove(e);// Mouse events listenersk.c.d.bind("mousemove.k", mouseMove).bind(// Escape key cancel current change"keyup.k", function (e) {if (e.keyCode === 27) {k.c.d.unbind("mouseup.k mousemove.k keyup.k");if (s.eH&& (s.eH() === false)) return;s.cancel();}}).bind("mouseup.k", function (e) {k.c.d.unbind('mousemove.k mouseup.k keyup.k');if (s.rH&& (s.rH(s.cv) === false)) return;s.val(s.cv);});return this;};this._xy = function () {var o = this.$c.offset();this.x = o.left;this.y = o.top;return this;};this._listen = function () {if (!this.o.readOnly) {this.$c.bind("mousedown", function (e) {e.preventDefault();s._xy()._mouse(e);}).bind("touchstart", function (e) {e.preventDefault();s._xy()._touch(e);});this.listen();} else {this.$.attr('readonly', 'readonly');}return this;};this._configure = function () {// Hooksif (this.o.draw) this.dH = this.o.draw;if (this.o.change) this.cH = this.o.change;if (this.o.cancel) this.eH = this.o.cancel;if (this.o.release) this.rH = this.o.release;if (this.o.displayPrevious) {this.pColor = this.h2rgba(this.o.fgColor, "0.4");this.fgColor = this.h2rgba(this.o.fgColor, "0.6");} else {this.fgColor = this.o.fgColor;}return this;};this._clear = function () {this.$c[0].width = this.$c[0].width;};// Abstract methodsthis.listen = function () {}; // on start, one timethis.extend = function () {}; // each time configure triggeredthis.init = function () {}; // each time configure triggeredthis.change = function (v) {}; // on changethis.val = function (v) {}; // on releasethis.xy2val = function (x, y) {}; //this.draw = function () {}; // on change / on releasethis.clear = function () { this._clear(); };// Utilsthis.h2rgba = function (h, a) {var rgb;h = h.substring(1,7)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] + "," + a + ")";};this.copy = function (f, t) {for (var i in f) { t[i] = f[i]; }};};/*** k.Dial*/k.Dial = function () {k.o.call(this);this.startAngle = null;this.xy = null;this.radius = null;this.lineWidth = null;this.cursorExt = null;this.w2 = null;this.PI2 = 2*Math.PI;this.extend = function () {this.o = $.extend({bgColor : this.$.data('bgcolor') || '#EEEEEE',angleOffset : this.$.data('angleoffset') || 0,angleArc : this.$.data('anglearc') || 360,inline : true}, this.o);};this.val = function (v) {if (null != v) {this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;this.v = this.cv;this.$.val(this.v);this._draw();} else {return this.v;}};this.xy2val = function (x, y) {var a, ret;a = Math.atan2(x - (this.x + this.w2), - (y - this.y - this.w2)) - this.angleOffset;if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {// if isset angleArc option, set to min if .5 under mina = 0;} else if (a < 0) {a += this.PI2;}ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc))+ this.o.min;this.o.stopper&& (ret = max(min(ret, this.o.max), this.o.min));return ret;};this.listen = function () {// bind MouseWheelvar s = this,mw = function (e) {e.preventDefault();var ori = e.originalEvent,deltaX = ori.detail || ori.wheelDeltaX,deltaY = ori.detail || ori.wheelDeltaY,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? 1 : deltaX<0 || deltaY<0 ? -1 : 0);if (s.cH&& (s.cH(v) === false)) return;s.val(v);}, kval, to, m = 1, kv = {37:-1, 38:1, 39:1, 40:-1};this.$.bind("keydown",function (e) {var kc = e.keyCode;// numpad supportif(kc >= 96 && kc <= 105) {kc = e.keyCode = kc - 48;}kval = parseInt(String.fromCharCode(kc));if (isNaN(kval)) {(kc !== 13) // enter&& (kc !== 8) // bs&& (kc !== 9) // tab&& (kc !== 189) // -&& e.preventDefault();// arrowsif ($.inArray(kc,[37,38,39,40]) > -1) {e.preventDefault();var v = parseInt(s.$.val()) + kv[kc] * m;s.o.stopper&& (v = max(min(v, s.o.max), s.o.min));s.change(v);s._draw();// long time keydown speed-upto = window.setTimeout(function () { m*=2; },30);}}}).bind("keyup",function (e) {if (isNaN(kval)) {if (to) {window.clearTimeout(to);to = null;m = 1;s.val(s.$.val());}} else {// kval postcond(s.$.val() > s.o.max && s.$.val(s.o.max))|| (s.$.val() < s.o.min && s.$.val(s.o.min));}});this.$c.bind("mousewheel DOMMouseScroll", mw);this.$.bind("mousewheel DOMMouseScroll", mw)};this.init = function () {if (this.v < this.o.min|| this.v > this.o.max) this.v = this.o.min;this.$.val(this.v);this.w2 = this.o.width / 2;this.cursorExt = this.o.cursor / 100;this.xy = this.w2;this.lineWidth = this.xy * this.o.thickness;this.radius = this.xy - this.lineWidth / 2;this.o.angleOffset&& (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);this.o.angleArc&& (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);// deg to radthis.angleOffset = this.o.angleOffset * Math.PI / 180;this.angleArc = this.o.angleArc * Math.PI / 180;// compute start and end anglesthis.startAngle = 1.5 * Math.PI + this.angleOffset;this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;var s = max(String(Math.abs(this.o.max)).length, String(Math.abs(this.o.min)).length, 2) + 2;this.o.displayInput&& this.i.css({'width' : ((this.o.width / 2 + 4) >> 0) + 'px','height' : ((this.o.width / 3) >> 0) + 'px','position' : 'absolute','vertical-align' : 'middle','margin-top' : ((this.o.width / 3) >> 0) + 'px','margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px','border' : 0,'background' : 'none','font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial','text-align' : 'center','color' : this.o.fgColor,'padding' : '0px','-webkit-appearance': 'none'})|| this.i.css({'width' : '0px','visibility' : 'hidden'});};this.change = function (v) {this.cv = v;this.$.val(v);};this.angle = function (v) {return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);};this.draw = function () {var c = this.g, // contexta = this.angle(this.cv) // Angle, sat = this.startAngle // Start angle, eat = sat + a // End angle, sa, ea // Previous angles, r = 1;c.lineWidth = this.lineWidth;this.o.cursor&& (sat = eat - this.cursorExt)&& (eat = eat + this.cursorExt);c.beginPath();c.strokeStyle = this.o.bgColor;c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true);c.stroke();if (this.o.displayPrevious) {ea = this.startAngle + this.angle(this.v);sa = this.startAngle;this.o.cursor&& (sa = ea - this.cursorExt)&& (ea = ea + this.cursorExt);c.beginPath();c.strokeStyle = this.pColor;c.arc(this.xy, this.xy, this.radius, sa, ea, false);c.stroke();r = (this.cv == this.v);}c.beginPath();c.strokeStyle = r ? this.o.fgColor : this.fgColor ;c.arc(this.xy, this.xy, this.radius, sat, eat, false);c.stroke();};this.cancel = function () {this.val(this.v);};};$.fn.dial = $.fn.knob = function (o) {return this.each(function () {var d = new k.Dial();d.o = o;d.$ = $(this);d.run();}).parent();};})(jQuery);