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