jquery.knob.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. /*!jQuery Knob*/
  2. /**
  3. * Downward compatible, touchable dial
  4. *
  5. * Version: 1.2.12
  6. * Requires: jQuery v1.7+
  7. *
  8. * Copyright (c) 2012 Anthony Terrien
  9. * Under MIT License (http://www.opensource.org/licenses/mit-license.php)
  10. *
  11. * Thanks to vor, eskimoblood, spiffistan, FabrizioC
  12. */
  13. (function (factory) {
  14. if (typeof exports === 'object') {
  15. // CommonJS
  16. module.exports = factory(require('jquery'));
  17. } else if (typeof define === 'function' && define.amd) {
  18. // AMD. Register as an anonymous module.
  19. define(['jquery'], factory);
  20. } else {
  21. // Browser globals
  22. factory(jQuery);
  23. }
  24. }(function ($) {
  25. /**
  26. * Kontrol library
  27. */
  28. "use strict";
  29. /**
  30. * Definition of globals and core
  31. */
  32. var k = {}, // kontrol
  33. max = Math.max,
  34. min = Math.min;
  35. k.c = {};
  36. k.c.d = $(document);
  37. k.c.t = function (e) {
  38. return e.originalEvent.touches.length - 1;
  39. };
  40. /**
  41. * Kontrol Object
  42. *
  43. * Definition of an abstract UI control
  44. *
  45. * Each concrete component must call this one.
  46. * <code>
  47. * k.o.call(this);
  48. * </code>
  49. */
  50. k.o = function () {
  51. var s = this;
  52. this.o = null; // array of options
  53. this.$ = null; // jQuery wrapped element
  54. this.i = null; // mixed HTMLInputElement or array of HTMLInputElement
  55. this.g = null; // deprecated 2D graphics context for 'pre-rendering'
  56. this.v = null; // value ; mixed array or integer
  57. this.cv = null; // change value ; not commited value
  58. this.x = 0; // canvas x position
  59. this.y = 0; // canvas y position
  60. this.w = 0; // canvas width
  61. this.h = 0; // canvas height
  62. this.$c = null; // jQuery canvas element
  63. this.c = null; // rendered canvas context
  64. this.t = 0; // touches index
  65. this.isInit = false;
  66. this.fgColor = null; // main color
  67. this.pColor = null; // previous color
  68. this.dH = null; // draw hook
  69. this.cH = null; // change hook
  70. this.eH = null; // cancel hook
  71. this.rH = null; // release hook
  72. this.scale = 1; // scale factor
  73. this.relative = false;
  74. this.relativeWidth = false;
  75. this.relativeHeight = false;
  76. this.$div = null; // component div
  77. this.run = function () {
  78. var cf = function (e, conf) {
  79. var k;
  80. for (k in conf) {
  81. s.o[k] = conf[k];
  82. }
  83. s._carve().init();
  84. s._configure()
  85. ._draw();
  86. };
  87. if (this.$.data('kontroled')) return;
  88. this.$.data('kontroled', true);
  89. this.extend();
  90. this.o = $.extend({
  91. // Config
  92. min: this.$.data('min') !== undefined ? this.$.data('min') : 0,
  93. max: this.$.data('max') !== undefined ? this.$.data('max') : 100,
  94. stopper: true,
  95. readOnly: this.$.data('readonly') || (this.$.attr('readonly') === 'readonly'),
  96. // UI
  97. cursor: this.$.data('cursor') === true && 30
  98. || this.$.data('cursor') || 0,
  99. thickness: this.$.data('thickness')
  100. && Math.max(Math.min(this.$.data('thickness'), 1), 0.01)
  101. || 0.35,
  102. lineCap: this.$.data('linecap') || 'butt',
  103. width: this.$.data('width') || 200,
  104. height: this.$.data('height') || 200,
  105. displayInput: this.$.data('displayinput') == null || this.$.data('displayinput'),
  106. displayPrevious: this.$.data('displayprevious'),
  107. fgColor: this.$.data('fgcolor') || '#87CEEB',
  108. inputColor: this.$.data('inputcolor'),
  109. font: this.$.data('font') || 'Arial',
  110. fontWeight: this.$.data('font-weight') || 'bold',
  111. inline: false,
  112. step: this.$.data('step') || 1,
  113. rotation: this.$.data('rotation'),
  114. // Hooks
  115. draw: null, // function () {}
  116. change: null, // function (value) {}
  117. cancel: null, // function () {}
  118. release: null, // function (value) {}
  119. // Output formatting, allows to add unit: %, ms ...
  120. format: function(v) {
  121. return v;
  122. },
  123. parse: function (v) {
  124. return parseFloat(v);
  125. }
  126. }, this.o
  127. );
  128. // finalize options
  129. this.o.flip = this.o.rotation === 'anticlockwise' || this.o.rotation === 'acw';
  130. if (!this.o.inputColor) {
  131. this.o.inputColor = this.o.fgColor;
  132. }
  133. // routing value
  134. if (this.$.is('fieldset')) {
  135. // fieldset = array of integer
  136. this.v = {};
  137. this.i = this.$.find('input');
  138. this.i.each(function(k) {
  139. var $this = $(this);
  140. s.i[k] = $this;
  141. s.v[k] = s.o.parse($this.val());
  142. $this.bind(
  143. 'change blur',
  144. function () {
  145. var val = {};
  146. val[k] = $this.val();
  147. s.val(s._validate(val));
  148. }
  149. );
  150. });
  151. this.$.find('legend').remove();
  152. } else {
  153. // input = integer
  154. this.i = this.$;
  155. this.v = this.o.parse(this.$.val());
  156. this.v === '' && (this.v = this.o.min);
  157. this.$.bind(
  158. 'change blur',
  159. function () {
  160. s.val(s._validate(s.o.parse(s.$.val())));
  161. }
  162. );
  163. }
  164. !this.o.displayInput && this.$.hide();
  165. // adds needed DOM elements (canvas, div)
  166. this.$c = $(document.createElement('canvas')).attr({
  167. width: this.o.width,
  168. height: this.o.height
  169. });
  170. // wraps all elements in a div
  171. // add to DOM before Canvas init is triggered
  172. this.$div = $('<div style="'
  173. + (this.o.inline ? 'display:inline;' : '')
  174. + 'width:' + this.o.width + 'px;height:' + this.o.height + 'px;'
  175. + '"></div>');
  176. this.$.wrap(this.$div).before(this.$c);
  177. this.$div = this.$.parent();
  178. if (typeof G_vmlCanvasManager !== 'undefined') {
  179. G_vmlCanvasManager.initElement(this.$c[0]);
  180. }
  181. this.c = this.$c[0].getContext ? this.$c[0].getContext('2d') : null;
  182. if (!this.c) {
  183. throw {
  184. name: "CanvasNotSupportedException",
  185. message: "Canvas not supported. Please use excanvas on IE8.0.",
  186. toString: function(){return this.name + ": " + this.message}
  187. }
  188. }
  189. // hdpi support
  190. this.scale = (window.devicePixelRatio || 1) / (
  191. this.c.webkitBackingStorePixelRatio ||
  192. this.c.mozBackingStorePixelRatio ||
  193. this.c.msBackingStorePixelRatio ||
  194. this.c.oBackingStorePixelRatio ||
  195. this.c.backingStorePixelRatio || 1
  196. );
  197. // detects relative width / height
  198. this.relativeWidth = this.o.width % 1 !== 0
  199. && this.o.width.indexOf('%');
  200. this.relativeHeight = this.o.height % 1 !== 0
  201. && this.o.height.indexOf('%');
  202. this.relative = this.relativeWidth || this.relativeHeight;
  203. // computes size and carves the component
  204. this._carve();
  205. // prepares props for transaction
  206. if (this.v instanceof Object) {
  207. this.cv = {};
  208. this.copy(this.v, this.cv);
  209. } else {
  210. this.cv = this.v;
  211. }
  212. // binds configure event
  213. this.$
  214. .bind("configure", cf)
  215. .parent()
  216. .bind("configure", cf);
  217. // finalize init
  218. this._listen()
  219. ._configure()
  220. ._xy()
  221. .init();
  222. this.isInit = true;
  223. this.$.val(this.o.format(this.v));
  224. this._draw();
  225. return this;
  226. };
  227. this._carve = function() {
  228. if (this.relative) {
  229. var w = this.relativeWidth ?
  230. this.$div.parent().width() *
  231. parseInt(this.o.width) / 100
  232. : this.$div.parent().width(),
  233. h = this.relativeHeight ?
  234. this.$div.parent().height() *
  235. parseInt(this.o.height) / 100
  236. : this.$div.parent().height();
  237. // apply relative
  238. this.w = this.h = Math.min(w, h);
  239. } else {
  240. this.w = this.o.width;
  241. this.h = this.o.height;
  242. }
  243. // finalize div
  244. this.$div.css({
  245. 'width': this.w + 'px',
  246. 'height': this.h + 'px'
  247. });
  248. // finalize canvas with computed width
  249. this.$c.attr({
  250. width: this.w,
  251. height: this.h
  252. });
  253. // scaling
  254. if (this.scale !== 1) {
  255. this.$c[0].width = this.$c[0].width * this.scale;
  256. this.$c[0].height = this.$c[0].height * this.scale;
  257. this.$c.width(this.w);
  258. this.$c.height(this.h);
  259. }
  260. return this;
  261. };
  262. this._draw = function () {
  263. // canvas pre-rendering
  264. var d = true;
  265. s.g = s.c;
  266. s.clear();
  267. s.dH && (d = s.dH());
  268. d !== false && s.draw();
  269. };
  270. this._touch = function (e) {
  271. var touchMove = function (e) {
  272. var v = s.xy2val(
  273. e.originalEvent.touches[s.t].pageX,
  274. e.originalEvent.touches[s.t].pageY
  275. );
  276. if (v == s.cv) return;
  277. if (s.cH && s.cH(v) === false) return;
  278. s.change(s._validate(v));
  279. s._draw();
  280. };
  281. // get touches index
  282. this.t = k.c.t(e);
  283. // First touch
  284. touchMove(e);
  285. // Touch events listeners
  286. k.c.d
  287. .bind("touchmove.k", touchMove)
  288. .bind(
  289. "touchend.k",
  290. function () {
  291. k.c.d.unbind('touchmove.k touchend.k');
  292. s.val(s.cv);
  293. }
  294. );
  295. return this;
  296. };
  297. this._mouse = function (e) {
  298. var mouseMove = function (e) {
  299. var v = s.xy2val(e.pageX, e.pageY);
  300. if (v == s.cv) return;
  301. if (s.cH && (s.cH(v) === false)) return;
  302. s.change(s._validate(v));
  303. s._draw();
  304. };
  305. // First click
  306. mouseMove(e);
  307. // Mouse events listeners
  308. k.c.d
  309. .bind("mousemove.k", mouseMove)
  310. .bind(
  311. // Escape key cancel current change
  312. "keyup.k",
  313. function (e) {
  314. if (e.keyCode === 27) {
  315. k.c.d.unbind("mouseup.k mousemove.k keyup.k");
  316. if (s.eH && s.eH() === false)
  317. return;
  318. s.cancel();
  319. }
  320. }
  321. )
  322. .bind(
  323. "mouseup.k",
  324. function (e) {
  325. k.c.d.unbind('mousemove.k mouseup.k keyup.k');
  326. s.val(s.cv);
  327. }
  328. );
  329. return this;
  330. };
  331. this._xy = function () {
  332. var o = this.$c.offset();
  333. this.x = o.left;
  334. this.y = o.top;
  335. return this;
  336. };
  337. this._listen = function () {
  338. if (!this.o.readOnly) {
  339. this.$c
  340. .bind(
  341. "mousedown",
  342. function (e) {
  343. e.preventDefault();
  344. s._xy()._mouse(e);
  345. }
  346. )
  347. .bind(
  348. "touchstart",
  349. function (e) {
  350. e.preventDefault();
  351. s._xy()._touch(e);
  352. }
  353. );
  354. this.listen();
  355. } else {
  356. this.$.attr('readonly', 'readonly');
  357. }
  358. if (this.relative) {
  359. $(window).resize(function() {
  360. s._carve().init();
  361. s._draw();
  362. });
  363. }
  364. return this;
  365. };
  366. this._configure = function () {
  367. // Hooks
  368. if (this.o.draw) this.dH = this.o.draw;
  369. if (this.o.change) this.cH = this.o.change;
  370. if (this.o.cancel) this.eH = this.o.cancel;
  371. if (this.o.release) this.rH = this.o.release;
  372. if (this.o.displayPrevious) {
  373. this.pColor = this.h2rgba(this.o.fgColor, "0.4");
  374. this.fgColor = this.h2rgba(this.o.fgColor, "0.6");
  375. } else {
  376. this.fgColor = this.o.fgColor;
  377. }
  378. return this;
  379. };
  380. this._clear = function () {
  381. this.$c[0].width = this.$c[0].width;
  382. };
  383. this._validate = function (v) {
  384. var val = (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step;
  385. return Math.round(val * 100) / 100;
  386. };
  387. // Abstract methods
  388. this.listen = function () {}; // on start, one time
  389. this.extend = function () {}; // each time configure triggered
  390. this.init = function () {}; // each time configure triggered
  391. this.change = function (v) {}; // on change
  392. this.val = function (v) {}; // on release
  393. this.xy2val = function (x, y) {}; //
  394. this.draw = function () {}; // on change / on release
  395. this.clear = function () { this._clear(); };
  396. // Utils
  397. this.h2rgba = function (h, a) {
  398. var rgb;
  399. h = h.substring(1,7);
  400. rgb = [
  401. parseInt(h.substring(0,2), 16),
  402. parseInt(h.substring(2,4), 16),
  403. parseInt(h.substring(4,6), 16)
  404. ];
  405. return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";
  406. };
  407. this.copy = function (f, t) {
  408. for (var i in f) {
  409. t[i] = f[i];
  410. }
  411. };
  412. };
  413. /**
  414. * k.Dial
  415. */
  416. k.Dial = function () {
  417. k.o.call(this);
  418. this.startAngle = null;
  419. this.xy = null;
  420. this.radius = null;
  421. this.lineWidth = null;
  422. this.cursorExt = null;
  423. this.w2 = null;
  424. this.PI2 = 2*Math.PI;
  425. this.extend = function () {
  426. this.o = $.extend({
  427. bgColor: this.$.data('bgcolor') || '#EEEEEE',
  428. angleOffset: this.$.data('angleoffset') || 0,
  429. angleArc: this.$.data('anglearc') || 360,
  430. inline: true
  431. }, this.o);
  432. };
  433. this.val = function (v, triggerRelease) {
  434. if (null != v) {
  435. // reverse format
  436. v = this.o.parse(v);
  437. if (triggerRelease !== false
  438. && v != this.v
  439. && this.rH
  440. && this.rH(v) === false) { return; }
  441. this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;
  442. this.v = this.cv;
  443. this.$.val(this.o.format(this.v));
  444. this._draw();
  445. } else {
  446. return this.v;
  447. }
  448. };
  449. this.xy2val = function (x, y) {
  450. var a, ret;
  451. a = Math.atan2(
  452. x - (this.x + this.w2),
  453. - (y - this.y - this.w2)
  454. ) - this.angleOffset;
  455. if (this.o.flip) {
  456. a = this.angleArc - a - this.PI2;
  457. }
  458. if (this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {
  459. // if isset angleArc option, set to min if .5 under min
  460. a = 0;
  461. } else if (a < 0) {
  462. a += this.PI2;
  463. }
  464. ret = (a * (this.o.max - this.o.min) / this.angleArc) + this.o.min;
  465. this.o.stopper && (ret = max(min(ret, this.o.max), this.o.min));
  466. return ret;
  467. };
  468. this.listen = function () {
  469. // bind MouseWheel
  470. var s = this, mwTimerStop,
  471. mwTimerRelease,
  472. mw = function (e) {
  473. e.preventDefault();
  474. var ori = e.originalEvent,
  475. deltaX = ori.detail || ori.wheelDeltaX,
  476. deltaY = ori.detail || ori.wheelDeltaY,
  477. v = s._validate(s.o.parse(s.$.val()))
  478. + (
  479. deltaX > 0 || deltaY > 0
  480. ? s.o.step
  481. : deltaX < 0 || deltaY < 0 ? -s.o.step : 0
  482. );
  483. v = max(min(v, s.o.max), s.o.min);
  484. s.val(v, false);
  485. if (s.rH) {
  486. // Handle mousewheel stop
  487. clearTimeout(mwTimerStop);
  488. mwTimerStop = setTimeout(function () {
  489. s.rH(v);
  490. mwTimerStop = null;
  491. }, 100);
  492. // Handle mousewheel releases
  493. if (!mwTimerRelease) {
  494. mwTimerRelease = setTimeout(function () {
  495. if (mwTimerStop)
  496. s.rH(v);
  497. mwTimerRelease = null;
  498. }, 200);
  499. }
  500. }
  501. },
  502. kval,
  503. to,
  504. m = 1,
  505. kv = {
  506. 37: -s.o.step,
  507. 38: s.o.step,
  508. 39: s.o.step,
  509. 40: -s.o.step
  510. };
  511. this.$
  512. .bind(
  513. "keydown",
  514. function (e) {
  515. var kc = e.keyCode;
  516. // numpad support
  517. if (kc >= 96 && kc <= 105) {
  518. kc = e.keyCode = kc - 48;
  519. }
  520. kval = parseInt(String.fromCharCode(kc));
  521. if (isNaN(kval)) {
  522. (kc !== 13) // enter
  523. && kc !== 8 // bs
  524. && kc !== 9 // tab
  525. && kc !== 189 // -
  526. && (kc !== 190
  527. || s.$.val().match(/\./)) // . allowed once
  528. && e.preventDefault();
  529. // arrows
  530. if ($.inArray(kc,[37,38,39,40]) > -1) {
  531. e.preventDefault();
  532. var v = s.o.parse(s.$.val()) + kv[kc] * m;
  533. s.o.stopper && (v = max(min(v, s.o.max), s.o.min));
  534. s.change(s._validate(v));
  535. s._draw();
  536. // long time keydown speed-up
  537. to = window.setTimeout(function () {
  538. m *= 2;
  539. }, 30);
  540. }
  541. }
  542. }
  543. )
  544. .bind(
  545. "keyup",
  546. function (e) {
  547. if (isNaN(kval)) {
  548. if (to) {
  549. window.clearTimeout(to);
  550. to = null;
  551. m = 1;
  552. s.val(s.$.val());
  553. }
  554. } else {
  555. // kval postcond
  556. (s.$.val() > s.o.max && s.$.val(s.o.max))
  557. || (s.$.val() < s.o.min && s.$.val(s.o.min));
  558. }
  559. }
  560. );
  561. this.$c.bind("mousewheel DOMMouseScroll", mw);
  562. this.$.bind("mousewheel DOMMouseScroll", mw);
  563. };
  564. this.init = function () {
  565. if (this.v < this.o.min
  566. || this.v > this.o.max) { this.v = this.o.min; }
  567. this.$.val(this.v);
  568. this.w2 = this.w / 2;
  569. this.cursorExt = this.o.cursor / 100;
  570. this.xy = this.w2 * this.scale;
  571. this.lineWidth = this.xy * this.o.thickness;
  572. this.lineCap = this.o.lineCap;
  573. this.radius = this.xy - this.lineWidth / 2;
  574. this.o.angleOffset
  575. && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);
  576. this.o.angleArc
  577. && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);
  578. // deg to rad
  579. this.angleOffset = this.o.angleOffset * Math.PI / 180;
  580. this.angleArc = this.o.angleArc * Math.PI / 180;
  581. // compute start and end angles
  582. this.startAngle = 1.5 * Math.PI + this.angleOffset;
  583. this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;
  584. var s = max(
  585. String(Math.abs(this.o.max)).length,
  586. String(Math.abs(this.o.min)).length,
  587. 2
  588. ) + 2;
  589. this.o.displayInput
  590. && this.i.css({
  591. 'width' : ((this.w / 2 + 4) >> 0) + 'px',
  592. 'height' : ((this.w / 3) >> 0) + 'px',
  593. 'position' : 'absolute',
  594. 'vertical-align' : 'middle',
  595. 'margin-top' : ((this.w / 3) >> 0) + 'px',
  596. 'margin-left' : '-' + ((this.w * 3 / 4 + 2) >> 0) + 'px',
  597. 'border' : 0,
  598. 'background' : 'none',
  599. 'font' : this.o.fontWeight + ' ' + ((this.w / s) >> 0) + 'px ' + this.o.font,
  600. 'text-align' : 'center',
  601. 'color' : this.o.inputColor || this.o.fgColor,
  602. 'padding' : '0px',
  603. '-webkit-appearance': 'none'
  604. }) || this.i.css({
  605. 'width': '0px',
  606. 'visibility': 'hidden'
  607. });
  608. };
  609. this.change = function (v) {
  610. this.cv = v;
  611. this.$.val(this.o.format(v));
  612. };
  613. this.angle = function (v) {
  614. return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);
  615. };
  616. this.arc = function (v) {
  617. var sa, ea;
  618. v = this.angle(v);
  619. if (this.o.flip) {
  620. sa = this.endAngle + 0.00001;
  621. ea = sa - v - 0.00001;
  622. } else {
  623. sa = this.startAngle - 0.00001;
  624. ea = sa + v + 0.00001;
  625. }
  626. this.o.cursor
  627. && (sa = ea - this.cursorExt)
  628. && (ea = ea + this.cursorExt);
  629. return {
  630. s: sa,
  631. e: ea,
  632. d: this.o.flip && !this.o.cursor
  633. };
  634. };
  635. this.draw = function () {
  636. var c = this.g, // context
  637. a = this.arc(this.cv), // Arc
  638. pa, // Previous arc
  639. r = 1;
  640. c.lineWidth = this.lineWidth;
  641. c.lineCap = this.lineCap;
  642. if (this.o.bgColor !== "none") {
  643. c.beginPath();
  644. c.strokeStyle = this.o.bgColor;
  645. c.arc(this.xy, this.xy, this.radius, this.endAngle - 0.00001, this.startAngle + 0.00001, true);
  646. c.stroke();
  647. }
  648. if (this.o.displayPrevious) {
  649. pa = this.arc(this.v);
  650. c.beginPath();
  651. c.strokeStyle = this.pColor;
  652. c.arc(this.xy, this.xy, this.radius, pa.s, pa.e, pa.d);
  653. c.stroke();
  654. r = this.cv == this.v;
  655. }
  656. c.beginPath();
  657. c.strokeStyle = r ? this.o.fgColor : this.fgColor ;
  658. c.arc(this.xy, this.xy, this.radius, a.s, a.e, a.d);
  659. c.stroke();
  660. };
  661. this.cancel = function () {
  662. this.val(this.v);
  663. };
  664. };
  665. $.fn.dial = $.fn.knob = function (o) {
  666. return this.each(
  667. function () {
  668. var d = new k.Dial();
  669. d.o = o;
  670. d.$ = $(this);
  671. d.run();
  672. }
  673. ).parent();
  674. };
  675. }));