Path: blob/master/web-gui/buildyourownbotnet/assets/js/jquery.knob.js
1292 views
/*!jQuery Knob*/1/**2* Downward compatible, touchable dial3*4* Version: 1.2.115* Requires: jQuery v1.7+6*7* Copyright (c) 2012 Anthony Terrien8* Under MIT License (http://www.opensource.org/licenses/mit-license.php)9*10* Thanks to vor, eskimoblood, spiffistan, FabrizioC11*/12(function (factory) {13if (typeof exports === 'object') {14// CommonJS15module.exports = factory(require('jquery'));16} else if (typeof define === 'function' && define.amd) {17// AMD. Register as an anonymous module.18define(['jquery'], factory);19} else {20// Browser globals21factory(jQuery);22}23}(function ($) {2425/**26* Kontrol library27*/28"use strict";2930/**31* Definition of globals and core32*/33var k = {}, // kontrol34max = Math.max,35min = Math.min;3637k.c = {};38k.c.d = $(document);39k.c.t = function (e) {40return e.originalEvent.touches.length - 1;41};4243/**44* Kontrol Object45*46* Definition of an abstract UI control47*48* Each concrete component must call this one.49* <code>50* k.o.call(this);51* </code>52*/53k.o = function () {54var s = this;5556this.o = null; // array of options57this.$ = null; // jQuery wrapped element58this.i = null; // mixed HTMLInputElement or array of HTMLInputElement59this.g = null; // deprecated 2D graphics context for 'pre-rendering'60this.v = null; // value ; mixed array or integer61this.cv = null; // change value ; not commited value62this.x = 0; // canvas x position63this.y = 0; // canvas y position64this.w = 0; // canvas width65this.h = 0; // canvas height66this.$c = null; // jQuery canvas element67this.c = null; // rendered canvas context68this.t = 0; // touches index69this.isInit = false;70this.fgColor = null; // main color71this.pColor = null; // previous color72this.dH = null; // draw hook73this.cH = null; // change hook74this.eH = null; // cancel hook75this.rH = null; // release hook76this.scale = 1; // scale factor77this.relative = false;78this.relativeWidth = false;79this.relativeHeight = false;80this.$div = null; // component div8182this.run = function () {83var cf = function (e, conf) {84var k;85for (k in conf) {86s.o[k] = conf[k];87}88s._carve().init();89s._configure()90._draw();91};9293if (this.$.data('kontroled')) return;94this.$.data('kontroled', true);9596this.extend();97this.o = $.extend({98// Config99min: this.$.data('min') !== undefined ? this.$.data('min') : 0,100max: this.$.data('max') !== undefined ? this.$.data('max') : 100,101stopper: true,102readOnly: this.$.data('readonly') || (this.$.attr('readonly') === 'readonly'),103104// UI105cursor: this.$.data('cursor') === true && 30106|| this.$.data('cursor') || 0,107thickness: this.$.data('thickness')108&& Math.max(Math.min(this.$.data('thickness'), 1), 0.01)109|| 0.35,110lineCap: this.$.data('linecap') || 'butt',111width: this.$.data('width') || 200,112height: this.$.data('height') || 200,113displayInput: this.$.data('displayinput') == null || this.$.data('displayinput'),114displayPrevious: this.$.data('displayprevious'),115fgColor: this.$.data('fgcolor') || '#87CEEB',116inputColor: this.$.data('inputcolor'),117font: this.$.data('font') || 'Arial',118fontWeight: this.$.data('font-weight') || 'bold',119inline: false,120step: this.$.data('step') || 1,121rotation: this.$.data('rotation'),122123// Hooks124draw: null, // function () {}125change: null, // function (value) {}126cancel: null, // function () {}127release: null, // function (value) {}128129// Output formatting, allows to add unit: %, ms ...130format: function(v) {131return v;132},133parse: function (v) {134return parseFloat(v);135}136}, this.o137);138139// finalize options140this.o.flip = this.o.rotation === 'anticlockwise' || this.o.rotation === 'acw';141if (!this.o.inputColor) {142this.o.inputColor = this.o.fgColor;143}144145// routing value146if (this.$.is('fieldset')) {147148// fieldset = array of integer149this.v = {};150this.i = this.$.find('input');151this.i.each(function(k) {152var $this = $(this);153s.i[k] = $this;154s.v[k] = s.o.parse($this.val());155156$this.bind(157'change blur',158function () {159var val = {};160val[k] = $this.val();161s.val(s._validate(val));162}163);164});165this.$.find('legend').remove();166} else {167168// input = integer169this.i = this.$;170this.v = this.o.parse(this.$.val());171this.v === '' && (this.v = this.o.min);172this.$.bind(173'change blur',174function () {175s.val(s._validate(s.o.parse(s.$.val())));176}177);178179}180181!this.o.displayInput && this.$.hide();182183// adds needed DOM elements (canvas, div)184this.$c = $(document.createElement('canvas')).attr({185width: this.o.width,186height: this.o.height187});188189// wraps all elements in a div190// add to DOM before Canvas init is triggered191this.$div = $('<div style="'192+ (this.o.inline ? 'display:inline;' : '')193+ 'width:' + this.o.width + 'px;height:' + this.o.height + 'px;'194+ '"></div>');195196this.$.wrap(this.$div).before(this.$c);197this.$div = this.$.parent();198199if (typeof G_vmlCanvasManager !== 'undefined') {200G_vmlCanvasManager.initElement(this.$c[0]);201}202203this.c = this.$c[0].getContext ? this.$c[0].getContext('2d') : null;204205if (!this.c) {206throw {207name: "CanvasNotSupportedException",208message: "Canvas not supported. Please use excanvas on IE8.0.",209toString: function(){return this.name + ": " + this.message}210}211}212213// hdpi support214this.scale = (window.devicePixelRatio || 1) / (215this.c.webkitBackingStorePixelRatio ||216this.c.mozBackingStorePixelRatio ||217this.c.msBackingStorePixelRatio ||218this.c.oBackingStorePixelRatio ||219this.c.backingStorePixelRatio || 1220);221222// detects relative width / height223this.relativeWidth = this.o.width % 1 !== 0224&& this.o.width.indexOf('%');225this.relativeHeight = this.o.height % 1 !== 0226&& this.o.height.indexOf('%');227this.relative = this.relativeWidth || this.relativeHeight;228229// computes size and carves the component230this._carve();231232// prepares props for transaction233if (this.v instanceof Object) {234this.cv = {};235this.copy(this.v, this.cv);236} else {237this.cv = this.v;238}239240// binds configure event241this.$242.bind("configure", cf)243.parent()244.bind("configure", cf);245246// finalize init247this._listen()248._configure()249._xy()250.init();251252this.isInit = true;253254this.$.val(this.o.format(this.v));255this._draw();256257return this;258};259260this._carve = function() {261if (this.relative) {262var w = this.relativeWidth ?263this.$div.parent().width() *264parseInt(this.o.width) / 100265: this.$div.parent().width(),266h = this.relativeHeight ?267this.$div.parent().height() *268parseInt(this.o.height) / 100269: this.$div.parent().height();270271// apply relative272this.w = this.h = Math.min(w, h);273} else {274this.w = this.o.width;275this.h = this.o.height;276}277278// finalize div279this.$div.css({280'width': this.w + 'px',281'height': this.h + 'px'282});283284// finalize canvas with computed width285this.$c.attr({286width: this.w,287height: this.h288});289290// scaling291if (this.scale !== 1) {292this.$c[0].width = this.$c[0].width * this.scale;293this.$c[0].height = this.$c[0].height * this.scale;294this.$c.width(this.w);295this.$c.height(this.h);296}297298return this;299};300301this._draw = function () {302303// canvas pre-rendering304var d = true;305306s.g = s.c;307308s.clear();309310s.dH && (d = s.dH());311312d !== false && s.draw();313};314315this._touch = function (e) {316var touchMove = function (e) {317var v = s.xy2val(318e.originalEvent.touches[s.t].pageX,319e.originalEvent.touches[s.t].pageY320);321322if (v == s.cv) return;323324if (s.cH && s.cH(v) === false) return;325326s.change(s._validate(v));327s._draw();328};329330// get touches index331this.t = k.c.t(e);332333// First touch334touchMove(e);335336// Touch events listeners337k.c.d338.bind("touchmove.k", touchMove)339.bind(340"touchend.k",341function () {342k.c.d.unbind('touchmove.k touchend.k');343s.val(s.cv);344}345);346347return this;348};349350this._mouse = function (e) {351var mouseMove = function (e) {352var v = s.xy2val(e.pageX, e.pageY);353354if (v == s.cv) return;355356if (s.cH && (s.cH(v) === false)) return;357358s.change(s._validate(v));359s._draw();360};361362// First click363mouseMove(e);364365// Mouse events listeners366k.c.d367.bind("mousemove.k", mouseMove)368.bind(369// Escape key cancel current change370"keyup.k",371function (e) {372if (e.keyCode === 27) {373k.c.d.unbind("mouseup.k mousemove.k keyup.k");374375if (s.eH && s.eH() === false)376return;377378s.cancel();379}380}381)382.bind(383"mouseup.k",384function (e) {385k.c.d.unbind('mousemove.k mouseup.k keyup.k');386s.val(s.cv);387}388);389390return this;391};392393this._xy = function () {394var o = this.$c.offset();395this.x = o.left;396this.y = o.top;397398return this;399};400401this._listen = function () {402if (!this.o.readOnly) {403this.$c404.bind(405"mousedown",406function (e) {407e.preventDefault();408s._xy()._mouse(e);409}410)411.bind(412"touchstart",413function (e) {414e.preventDefault();415s._xy()._touch(e);416}417);418419this.listen();420} else {421this.$.attr('readonly', 'readonly');422}423424if (this.relative) {425$(window).resize(function() {426s._carve().init();427s._draw();428});429}430431return this;432};433434this._configure = function () {435436// Hooks437if (this.o.draw) this.dH = this.o.draw;438if (this.o.change) this.cH = this.o.change;439if (this.o.cancel) this.eH = this.o.cancel;440if (this.o.release) this.rH = this.o.release;441442if (this.o.displayPrevious) {443this.pColor = this.h2rgba(this.o.fgColor, "0.4");444this.fgColor = this.h2rgba(this.o.fgColor, "0.6");445} else {446this.fgColor = this.o.fgColor;447}448449return this;450};451452this._clear = function () {453this.$c[0].width = this.$c[0].width;454};455456this._validate = function (v) {457var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step;458return Math.round(val * 100) / 100;459};460461// Abstract methods462this.listen = function () {}; // on start, one time463this.extend = function () {}; // each time configure triggered464this.init = function () {}; // each time configure triggered465this.change = function (v) {}; // on change466this.val = function (v) {}; // on release467this.xy2val = function (x, y) {}; //468this.draw = function () {}; // on change / on release469this.clear = function () { this._clear(); };470471// Utils472this.h2rgba = function (h, a) {473var rgb;474h = h.substring(1,7);475rgb = [476parseInt(h.substring(0,2), 16),477parseInt(h.substring(2,4), 16),478parseInt(h.substring(4,6), 16)479];480481return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";482};483484this.copy = function (f, t) {485for (var i in f) {486t[i] = f[i];487}488};489};490491492/**493* k.Dial494*/495k.Dial = function () {496k.o.call(this);497498this.startAngle = null;499this.xy = null;500this.radius = null;501this.lineWidth = null;502this.cursorExt = null;503this.w2 = null;504this.PI2 = 2*Math.PI;505506this.extend = function () {507this.o = $.extend({508bgColor: this.$.data('bgcolor') || '#EEEEEE',509angleOffset: this.$.data('angleoffset') || 0,510angleArc: this.$.data('anglearc') || 360,511inline: true512}, this.o);513};514515this.val = function (v, triggerRelease) {516if (null != v) {517518// reverse format519v = this.o.parse(v);520521if (triggerRelease !== false522&& v != this.v523&& this.rH524&& this.rH(v) === false) { return; }525526this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;527this.v = this.cv;528this.$.val(this.o.format(this.v));529this._draw();530} else {531return this.v;532}533};534535this.xy2val = function (x, y) {536var a, ret;537538a = Math.atan2(539x - (this.x + this.w2),540- (y - this.y - this.w2)541) - this.angleOffset;542543if (this.o.flip) {544a = this.angleArc - a - this.PI2;545}546547if (this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {548549// if isset angleArc option, set to min if .5 under min550a = 0;551} else if (a < 0) {552a += this.PI2;553}554555ret = (a * (this.o.max - this.o.min) / this.angleArc) + this.o.min;556557this.o.stopper && (ret = max(min(ret, this.o.max), this.o.min));558559return ret;560};561562this.listen = function () {563564// bind MouseWheel565var s = this, mwTimerStop,566mwTimerRelease,567mw = function (e) {568e.preventDefault();569570var ori = e.originalEvent,571deltaX = ori.detail || ori.wheelDeltaX,572deltaY = ori.detail || ori.wheelDeltaY,573v = s._validate(s.o.parse(s.$.val()))574+ (575deltaX > 0 || deltaY > 0576? s.o.step577: deltaX < 0 || deltaY < 0 ? -s.o.step : 0578);579580v = max(min(v, s.o.max), s.o.min);581582s.val(v, false);583584if (s.rH) {585// Handle mousewheel stop586clearTimeout(mwTimerStop);587mwTimerStop = setTimeout(function () {588s.rH(v);589mwTimerStop = null;590}, 100);591592// Handle mousewheel releases593if (!mwTimerRelease) {594mwTimerRelease = setTimeout(function () {595if (mwTimerStop)596s.rH(v);597mwTimerRelease = null;598}, 200);599}600}601},602kval,603to,604m = 1,605kv = {60637: -s.o.step,60738: s.o.step,60839: s.o.step,60940: -s.o.step610};611612this.$613.bind(614"keydown",615function (e) {616var kc = e.keyCode;617618// numpad support619if (kc >= 96 && kc <= 105) {620kc = e.keyCode = kc - 48;621}622623kval = parseInt(String.fromCharCode(kc));624625if (isNaN(kval)) {626(kc !== 13) // enter627&& kc !== 8 // bs628&& kc !== 9 // tab629&& kc !== 189 // -630&& (kc !== 190631|| s.$.val().match(/\./)) // . allowed once632&& e.preventDefault();633634// arrows635if ($.inArray(kc,[37,38,39,40]) > -1) {636e.preventDefault();637638var v = s.o.parse(s.$.val()) + kv[kc] * m;639s.o.stopper && (v = max(min(v, s.o.max), s.o.min));640641s.change(s._validate(v));642s._draw();643644// long time keydown speed-up645to = window.setTimeout(function () {646m *= 2;647}, 30);648}649}650}651)652.bind(653"keyup",654function (e) {655if (isNaN(kval)) {656if (to) {657window.clearTimeout(to);658to = null;659m = 1;660s.val(s.$.val());661}662} else {663// kval postcond664(s.$.val() > s.o.max && s.$.val(s.o.max))665|| (s.$.val() < s.o.min && s.$.val(s.o.min));666}667}668);669670this.$c.bind("mousewheel DOMMouseScroll", mw);671this.$.bind("mousewheel DOMMouseScroll", mw);672};673674this.init = function () {675if (this.v < this.o.min676|| this.v > this.o.max) { this.v = this.o.min; }677678this.$.val(this.v);679this.w2 = this.w / 2;680this.cursorExt = this.o.cursor / 100;681this.xy = this.w2 * this.scale;682this.lineWidth = this.xy * this.o.thickness;683this.lineCap = this.o.lineCap;684this.radius = this.xy - this.lineWidth / 2;685686this.o.angleOffset687&& (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);688689this.o.angleArc690&& (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);691692// deg to rad693this.angleOffset = this.o.angleOffset * Math.PI / 180;694this.angleArc = this.o.angleArc * Math.PI / 180;695696// compute start and end angles697this.startAngle = 1.5 * Math.PI + this.angleOffset;698this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;699700var s = max(701String(Math.abs(this.o.max)).length,702String(Math.abs(this.o.min)).length,7032704) + 2;705706this.o.displayInput707&& this.i.css({708'width' : ((this.w / 2 + 4) >> 0) + 'px',709'height' : ((this.w / 3) >> 0) + 'px',710'position' : 'absolute',711'vertical-align' : 'middle',712'margin-top' : ((this.w / 3) >> 0) + 'px',713'margin-left' : '-' + ((this.w * 3 / 4 + 2) >> 0) + 'px',714'border' : 0,715'background' : 'none',716'font' : this.o.fontWeight + ' ' + ((this.w / s) >> 0) + 'px ' + this.o.font,717'text-align' : 'center',718'color' : this.o.inputColor || this.o.fgColor,719'padding' : '0px',720'-webkit-appearance': 'none'721}) || this.i.css({722'width': '0px',723'visibility': 'hidden'724});725};726727this.change = function (v) {728this.cv = v;729this.$.val(this.o.format(v));730};731732this.angle = function (v) {733return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);734};735736this.arc = function (v) {737var sa, ea;738v = this.angle(v);739if (this.o.flip) {740sa = this.endAngle + 0.00001;741ea = sa - v - 0.00001;742} else {743sa = this.startAngle - 0.00001;744ea = sa + v + 0.00001;745}746this.o.cursor747&& (sa = ea - this.cursorExt)748&& (ea = ea + this.cursorExt);749750return {751s: sa,752e: ea,753d: this.o.flip && !this.o.cursor754};755};756757this.draw = function () {758var c = this.g, // context759a = this.arc(this.cv), // Arc760pa, // Previous arc761r = 1;762763c.lineWidth = this.lineWidth;764c.lineCap = this.lineCap;765766if (this.o.bgColor !== "none") {767c.beginPath();768c.strokeStyle = this.o.bgColor;769c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);770c.stroke();771}772773if (this.o.displayPrevious) {774pa = this.arc(this.v);775c.beginPath();776c.strokeStyle = this.pColor;777c.arc(this.xy, this.xy, this.radius, pa.s, pa.e, pa.d);778c.stroke();779r = this.cv == this.v;780}781782c.beginPath();783c.strokeStyle = r ? this.o.fgColor : this.fgColor ;784c.arc(this.xy, this.xy, this.radius, a.s, a.e, a.d);785c.stroke();786};787788this.cancel = function () {789this.val(this.v);790};791};792793$.fn.dial = $.fn.knob = function (o) {794return this.each(795function () {796var d = new k.Dial();797d.o = o;798d.$ = $(this);799d.run();800}801).parent();802};803804}));805806