Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 1436e7ff61e63ad88a71baec90adc5ced42b29d8 0 parents
@martinaglv authored
BIN  knobKnob/knob.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
52 knobKnob/knobKnob.css
@@ -0,0 +1,52 @@
+/*----------------------------
+ knobKnob Styles
+-----------------------------*/
+
+
+.knob{
+ width:83px;
+ height:83px;
+ position:relative;
+}
+
+.knob .top{
+ position:absolute;
+ top:0;
+ left:0;
+ width:83px;
+ height:83px;
+ background:url('knob.png') no-repeat;
+ z-index:10;
+ cursor:default !important;
+}
+
+.knob .base{
+ width:83px;
+ height:83px;
+ border-radius:50%;
+ box-shadow:0 5px 0 #4a5056,5px 5px 5px #000;
+ position:absolute;
+ top:0;
+ left:0;
+ z-index:1;
+}
+
+.knob .top:after{
+ content:'';
+ width:10px;
+ height:10px;
+ background-color:#666;
+ position:absolute;
+ top:50%;
+ left:10px;
+ margin-top:-5px;
+ border-radius: 50%;
+ cursor:default !important;
+ box-shadow: 0 0 1px #5a5a5a inset;
+}
+
+.knob [draggable] {
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ user-select: none;
+}
118 knobKnob/knobKnob.jquery.js
@@ -0,0 +1,118 @@
+/**
+ * @name jQuery KnobKnob plugin
+ * @author Martin Angelov
+ * @version 1.0
+ * @url http://tutorialzine.com/2011/11/pretty-switches-css3-jquery/
+ * @license MIT License
+ */
+
+(function($){
+
+ $.fn.knobKnob = function(props){
+
+ var options = $.extend({
+ snap: 0,
+ value: 0,
+ turn: function(){}
+ }, props || {});
+
+ var tpl = '<div class="knob">\
+ <div class="top"></div>\
+ <div class="base"></div>\
+ </div>';
+
+ return this.each(function(){
+
+ var el = $(this);
+ el.append(tpl);
+
+ var knob = $('.knob',el)
@alexmic
alexmic added a note

There's a comma missing here. It caused me endless amount of pain. Without the comma, everything after knob is declared global and things break when you use many knobs.

@martinaglv Owner

So sorry for that oversight! Fixing it at the moment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ knobTop = knob.find('.top'),
+ startDeg = -1,
+ currentDeg = 0,
+ rotation = 0,
+ lastDeg = 0,
+ doc = $(document);
+
+ if(options.value > 0 && options.value <= 359){
+ rotation = currentDeg = options.value;
+ knobTop.css('transform','rotate('+(currentDeg)+'deg)');
+ options.turn(currentDeg/359);
+ }
+
+ knob.on('mousedown', function(e){
+
+ e.preventDefault();
+
+ var offset = knob.offset();
+ var center = {
+ y : offset.top + knob.height()/2,
+ x: offset.left + knob.width()/2
+ };
+
+ var a, b, deg, tmp,
+ rad2deg = 180/Math.PI;
+
+ knob.on('mousemove.rem',function(e){
+
+ a = center.y - e.pageY;
+ b = center.x - e.pageX;
+ deg = Math.atan2(a,b)*rad2deg;
+
+ // we have to make sure that negative
+ // angles are turned into positive:
+ if(deg<0){
+ deg = 360 + deg;
+ }
+
+ // Save the starting position of the drag
+ if(startDeg == -1){
+ startDeg = deg;
+ }
+
+ // Calculating the current rotation
+ tmp = Math.floor((deg-startDeg) + rotation);
+
+ // Making sure the current rotation
+ // stays between 0 and 359
+ if(tmp < 0){
+ tmp = 360 + tmp;
+ }
+ else if(tmp > 359){
+ tmp = tmp % 360;
+ }
+
+ // Snapping in the off position:
+ if(options.snap && tmp < options.snap){
+ tmp = 0;
+ }
+
+ // This would suggest we are at an end position;
+ // we need to block further rotation.
+ if(Math.abs(tmp - lastDeg) > 180){
+ return false;
+ }
+
+ currentDeg = tmp;
+ lastDeg = tmp;
+
+ knobTop.css('transform','rotate('+(currentDeg)+'deg)');
+ options.turn(currentDeg/359);
+ });
+
+ doc.on('mouseup.rem',function(){
+ knob.off('.rem');
+ doc.off('.rem');
+
+ // Saving the current rotation
+ rotation = currentDeg;
+
+ // Marking the starting degree as invalid
+ startDeg = -1;
+ });
+
+ });
+ });
+ };
+
+})(jQuery);
532 knobKnob/transform.js
@@ -0,0 +1,532 @@
+/*
+ * transform: A jQuery cssHooks adding cross-browser 2d transform capabilities to $.fn.css() and $.fn.animate()
+ *
+ * limitations:
+ * - requires jQuery 1.4.3+
+ * - Should you use the *translate* property, then your elements need to be absolutely positionned in a relatively positionned wrapper **or it will fail in IE678**.
+ * - transformOrigin is not accessible
+ *
+ * latest version and complete README available on Github:
+ * https://github.com/louisremi/jquery.transform.js
+ *
+ * Copyright 2011 @louis_remi
+ * Licensed under the MIT license.
+ *
+ * This saved you an hour of work?
+ * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON
+ *
+ */
+(function( $ ) {
+
+/*
+ * Feature tests and global variables
+ */
+var div = document.createElement('div'),
+ divStyle = div.style,
+ propertyName = 'transform',
+ suffix = 'Transform',
+ testProperties = [
+ 'O' + suffix,
+ 'ms' + suffix,
+ 'Webkit' + suffix,
+ 'Moz' + suffix,
+ // prefix-less property
+ propertyName
+ ],
+ i = testProperties.length,
+ supportProperty,
+ supportMatrixFilter,
+ propertyHook,
+ propertyGet,
+ rMatrix = /Matrix([^)]*)/;
+
+// test different vendor prefixes of this property
+while ( i-- ) {
+ if ( testProperties[i] in divStyle ) {
+ $.support[propertyName] = supportProperty = testProperties[i];
+ continue;
+ }
+}
+// IE678 alternative
+if ( !supportProperty ) {
+ $.support.matrixFilter = supportMatrixFilter = divStyle.filter === '';
+}
+// prevent IE memory leak
+div = divStyle = null;
+
+// px isn't the default unit of this property
+$.cssNumber[propertyName] = true;
+
+/*
+ * fn.css() hooks
+ */
+if ( supportProperty && supportProperty != propertyName ) {
+ // Modern browsers can use jQuery.cssProps as a basic hook
+ $.cssProps[propertyName] = supportProperty;
+
+ // Firefox needs a complete hook because it stuffs matrix with 'px'
+ if ( supportProperty == 'Moz' + suffix ) {
+ propertyHook = {
+ get: function( elem, computed ) {
+ return (computed ?
+ // remove 'px' from the computed matrix
+ $.css( elem, supportProperty ).split('px').join(''):
+ elem.style[supportProperty]
+ )
+ },
+ set: function( elem, value ) {
+ // remove 'px' from matrices
+ elem.style[supportProperty] = /matrix[^)p]*\)/.test(value) ?
+ value.replace(/matrix((?:[^,]*,){4})([^,]*),([^)]*)/, 'matrix$1$2px,$3px'):
+ value;
+ }
+ }
+ /* Fix two jQuery bugs still present in 1.5.1
+ * - rupper is incompatible with IE9, see http://jqbug.com/8346
+ * - jQuery.css is not really jQuery.cssProps aware, see http://jqbug.com/8402
+ */
+ } else if ( /^1\.[0-5](?:\.|$)/.test($.fn.jquery) ) {
+ propertyHook = {
+ get: function( elem, computed ) {
+ return (computed ?
+ $.css( elem, supportProperty.replace(/^ms/, 'Ms') ):
+ elem.style[supportProperty]
+ )
+ }
+ }
+ }
+ /* TODO: leverage hardware acceleration of 3d transform in Webkit only
+ else if ( supportProperty == 'Webkit' + suffix && support3dTransform ) {
+ propertyHook = {
+ set: function( elem, value ) {
+ elem.style[supportProperty] =
+ value.replace();
+ }
+ }
+ }*/
+
+} else if ( supportMatrixFilter ) {
+ propertyHook = {
+ get: function( elem, computed ) {
+ var elemStyle = ( computed && elem.currentStyle ? elem.currentStyle : elem.style ),
+ matrix;
+
+ if ( elemStyle && rMatrix.test( elemStyle.filter ) ) {
+ matrix = RegExp.$1.split(',');
+ matrix = [
+ matrix[0].split('=')[1],
+ matrix[2].split('=')[1],
+ matrix[1].split('=')[1],
+ matrix[3].split('=')[1]
+ ];
+ } else {
+ matrix = [1,0,0,1];
+ }
+ matrix[4] = elemStyle ? elemStyle.left : 0;
+ matrix[5] = elemStyle ? elemStyle.top : 0;
+ return "matrix(" + matrix + ")";
+ },
+ set: function( elem, value, animate ) {
+ var elemStyle = elem.style,
+ currentStyle,
+ Matrix,
+ filter;
+
+ if ( !animate ) {
+ elemStyle.zoom = 1;
+ }
+
+ value = matrix(value);
+
+ // rotate, scale and skew
+ if ( !animate || animate.M ) {
+ Matrix = [
+ "Matrix("+
+ "M11="+value[0],
+ "M12="+value[2],
+ "M21="+value[1],
+ "M22="+value[3],
+ "SizingMethod='auto expand'"
+ ].join();
+ filter = ( currentStyle = elem.currentStyle ) && currentStyle.filter || elemStyle.filter || "";
+
+ elemStyle.filter = rMatrix.test(filter) ?
+ filter.replace(rMatrix, Matrix) :
+ filter + " progid:DXImageTransform.Microsoft." + Matrix + ")";
+
+ // center the transform origin, from pbakaus's Transformie http://github.com/pbakaus/transformie
+ if ( (centerOrigin = $.transform.centerOrigin) ) {
+ elemStyle[centerOrigin == 'margin' ? 'marginLeft' : 'left'] = -(elem.offsetWidth/2) + (elem.clientWidth/2) + 'px';
+ elemStyle[centerOrigin == 'margin' ? 'marginTop' : 'top'] = -(elem.offsetHeight/2) + (elem.clientHeight/2) + 'px';
+ }
+ }
+
+ // translate
+ if ( !animate || animate.T ) {
+ // We assume that the elements are absolute positionned inside a relative positionned wrapper
+ elemStyle.left = value[4] + 'px';
+ elemStyle.top = value[5] + 'px';
+ }
+ }
+ }
+}
+// populate jQuery.cssHooks with the appropriate hook if necessary
+if ( propertyHook ) {
+ $.cssHooks[propertyName] = propertyHook;
+}
+// we need a unique setter for the animation logic
+propertyGet = propertyHook && propertyHook.get || $.css;
+
+/*
+ * fn.animate() hooks
+ */
+$.fx.step.transform = function( fx ) {
+ var elem = fx.elem,
+ start = fx.start,
+ end = fx.end,
+ split,
+ pos = fx.pos,
+ transform,
+ translate,
+ rotate,
+ scale,
+ skew,
+ T = false,
+ M = false,
+ prop;
+ translate = rotate = scale = skew = '';
+
+ // fx.end and fx.start need to be converted to their translate/rotate/scale/skew components
+ // so that we can interpolate them
+ if ( !start || typeof start === "string" ) {
+ // the following block can be commented out with jQuery 1.5.1+, see #7912
+ if (!start) {
+ start = propertyGet( elem, supportProperty );
+ }
+
+ // force layout only once per animation
+ if ( supportMatrixFilter ) {
+ elem.style.zoom = 1;
+ }
+
+ // if the start computed matrix is in end, we are doing a relative animation
+ split = end.split(start);
+ if ( split.length == 2 ) {
+ // remove the start computed matrix to make animations more accurate
+ end = split.join('');
+ fx.origin = start;
+ start = 'none';
+ }
+
+ // start is either 'none' or a matrix(...) that has to be parsed
+ fx.start = start = start == 'none'?
+ {
+ translate: [0,0],
+ rotate: 0,
+ scale: [1,1],
+ skew: [0,0]
+ }:
+ unmatrix( toArray(start) );
+
+ // fx.end has to be parsed and decomposed
+ fx.end = end = ~end.indexOf('matrix')?
+ // bullet-proof parser
+ unmatrix(matrix(end)):
+ // faster and more precise parser
+ components(end);
+
+ // get rid of properties that do not change
+ for ( prop in start) {
+ if ( prop == 'rotate' ?
+ start[prop] == end[prop]:
+ start[prop][0] == end[prop][0] && start[prop][1] == end[prop][1]
+ ) {
+ delete start[prop];
+ }
+ }
+ }
+
+ /*
+ * We want a fast interpolation algorithm.
+ * This implies avoiding function calls and sacrifying DRY principle:
+ * - avoid $.each(function(){})
+ * - round values using bitewise hacks, see http://jsperf.com/math-round-vs-hack/3
+ */
+ if ( start.translate ) {
+ // round translate to the closest pixel
+ translate = ' translate('+
+ ((start.translate[0] + (end.translate[0] - start.translate[0]) * pos + .5) | 0) +'px,'+
+ ((start.translate[1] + (end.translate[1] - start.translate[1]) * pos + .5) | 0) +'px'+
+ ')';
+ T = true;
+ }
+ if ( start.rotate != undefined ) {
+ rotate = ' rotate('+ (start.rotate + (end.rotate - start.rotate) * pos) +'rad)';
+ M = true;
+ }
+ if ( start.scale ) {
+ scale = ' scale('+
+ (start.scale[0] + (end.scale[0] - start.scale[0]) * pos) +','+
+ (start.scale[1] + (end.scale[1] - start.scale[1]) * pos) +
+ ')';
+ M = true;
+ }
+ if ( start.skew ) {
+ skew = ' skew('+
+ (start.skew[0] + (end.skew[0] - start.skew[0]) * pos) +'rad,'+
+ (start.skew[1] + (end.skew[1] - start.skew[1]) * pos) +'rad'+
+ ')';
+ M = true;
+ }
+
+ // In case of relative animation, restore the origin computed matrix here.
+ transform = fx.origin ?
+ fx.origin + translate + skew + scale + rotate:
+ translate + rotate + scale + skew;
+
+ propertyHook && propertyHook.set ?
+ propertyHook.set( elem, transform, {M: M, T: T} ):
+ elem.style[supportProperty] = transform;
+};
+
+/*
+ * Utility functions
+ */
+
+// turns a transform string into its 'matrix(A,B,C,D,X,Y)' form (as an array, though)
+function matrix( transform ) {
+ transform = transform.split(')');
+ var
+ trim = $.trim
+ // last element of the array is an empty string, get rid of it
+ , i = transform.length -1
+ , split, prop, val
+ , A = 1
+ , B = 0
+ , C = 0
+ , D = 1
+ , A_, B_, C_, D_
+ , tmp1, tmp2
+ , X = 0
+ , Y = 0
+ ;
+ // Loop through the transform properties, parse and multiply them
+ while (i--) {
+ split = transform[i].split('(');
+ prop = trim(split[0]);
+ val = split[1];
+ A_ = B_ = C_ = D_ = 0;
+
+ switch (prop) {
+ case 'translateX':
+ X += parseInt(val, 10);
+ continue;
+
+ case 'translateY':
+ Y += parseInt(val, 10);
+ continue;
+
+ case 'translate':
+ val = val.split(',');
+ X += parseInt(val[0], 10);
+ Y += parseInt(val[1] || 0, 10);
+ continue;
+
+ case 'rotate':
+ val = toRadian(val);
+ A_ = Math.cos(val);
+ B_ = Math.sin(val);
+ C_ = -Math.sin(val);
+ D_ = Math.cos(val);
+ break;
+
+ case 'scaleX':
+ A_ = val;
+ D_ = 1;
+ break;
+
+ case 'scaleY':
+ A_ = 1;
+ D_ = val;
+ break;
+
+ case 'scale':
+ val = val.split(',');
+ A_ = val[0];
+ D_ = val.length>1 ? val[1] : val[0];
+ break;
+
+ case 'skewX':
+ A_ = D_ = 1;
+ C_ = Math.tan(toRadian(val));
+ break;
+
+ case 'skewY':
+ A_ = D_ = 1;
+ B_ = Math.tan(toRadian(val));
+ break;
+
+ case 'skew':
+ A_ = D_ = 1;
+ val = val.split(',');
+ C_ = Math.tan(toRadian(val[0]));
+ B_ = Math.tan(toRadian(val[1] || 0));
+ break;
+
+ case 'matrix':
+ val = val.split(',');
+ A_ = +val[0];
+ B_ = +val[1];
+ C_ = +val[2];
+ D_ = +val[3];
+ X += parseInt(val[4], 10);
+ Y += parseInt(val[5], 10);
+ }
+ // Matrix product
+ tmp1 = A * A_ + B * C_;
+ B = A * B_ + B * D_;
+ tmp2 = C * A_ + D * C_;
+ D = C * B_ + D * D_;
+ A = tmp1;
+ C = tmp2;
+ }
+ return [A,B,C,D,X,Y];
+}
+
+// turns a matrix into its rotate, scale and skew components
+// algorithm from http://hg.mozilla.org/mozilla-central/file/7cb3e9795d04/layout/style/nsStyleAnimation.cpp
+function unmatrix(matrix) {
+ var
+ scaleX
+ , scaleY
+ , skew
+ , A = matrix[0]
+ , B = matrix[1]
+ , C = matrix[2]
+ , D = matrix[3]
+ ;
+
+ // Make sure matrix is not singular
+ if ( A * D - B * C ) {
+ // step (3)
+ scaleX = Math.sqrt( A * A + B * B );
+ A /= scaleX;
+ B /= scaleX;
+ // step (4)
+ skew = A * C + B * D;
+ C -= A * skew;
+ D -= B * skew;
+ // step (5)
+ scaleY = Math.sqrt( C * C + D * D );
+ C /= scaleY;
+ D /= scaleY;
+ skew /= scaleY;
+ // step (6)
+ if ( A * D < B * C ) {
+ //scaleY = -scaleY;
+ //skew = -skew;
+ A = -A;
+ B = -B;
+ skew = -skew;
+ scaleX = -scaleX;
+ }
+
+ // matrix is singular and cannot be interpolated
+ } else {
+ rotate = scaleX = scaleY = skew = 0;
+ }
+
+ return {
+ translate: [+matrix[4], +matrix[5]],
+ rotate: Math.atan2(B, A),
+ scale: [scaleX, scaleY],
+ skew: [skew, 0]
+ }
+}
+
+// parse tranform components of a transform string not containing 'matrix(...)'
+function components( transform ) {
+ // split the != transforms
+ transform = transform.split(')');
+
+ var translate = [0,0],
+ rotate = 0,
+ scale = [1,1],
+ skew = [0,0],
+ i = transform.length -1,
+ trim = $.trim,
+ split, name, value;
+
+ // add components
+ while ( i-- ) {
+ split = transform[i].split('(');
+ name = trim(split[0]);
+ value = split[1];
+
+ if (name == 'translateX') {
+ translate[0] += parseInt(value, 10);
+
+ } else if (name == 'translateY') {
+ translate[1] += parseInt(value, 10);
+
+ } else if (name == 'translate') {
+ value = value.split(',');
+ translate[0] += parseInt(value[0], 10);
+ translate[1] += parseInt(value[1] || 0, 10);
+
+ } else if (name == 'rotate') {
+ rotate += toRadian(value);
+
+ } else if (name == 'scaleX') {
+ scale[0] *= value;
+
+ } else if (name == 'scaleY') {
+ scale[1] *= value;
+
+ } else if (name == 'scale') {
+ value = value.split(',');
+ scale[0] *= value[0];
+ scale[1] *= (value.length>1? value[1] : value[0]);
+
+ } else if (name == 'skewX') {
+ skew[0] += toRadian(value);
+
+ } else if (name == 'skewY') {
+ skew[1] += toRadian(value);
+
+ } else if (name == 'skew') {
+ value = value.split(',');
+ skew[0] += toRadian(value[0]);
+ skew[1] += toRadian(value[1] || '0');
+ }
+ }
+
+ return {
+ translate: translate,
+ rotate: rotate,
+ scale: scale,
+ skew: skew
+ };
+}
+
+// converts an angle string in any unit to a radian Float
+function toRadian(value) {
+ return ~value.indexOf('deg') ?
+ parseInt(value,10) * (Math.PI * 2 / 360):
+ ~value.indexOf('grad') ?
+ parseInt(value,10) * (Math.PI/200):
+ parseFloat(value);
+}
+
+// Converts 'matrix(A,B,C,D,X,Y)' to [A,B,C,D,X,Y]
+function toArray(matrix) {
+ // Fremove the unit of X and Y for Firefox
+ matrix = /\(([^,]*),([^,]*),([^,]*),([^,]*),([^,p]*)(?:px)?,([^)p]*)(?:px)?/.exec(matrix);
+ return [matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]];
+}
+
+$.transform = {
+ centerOrigin: 'margin'
+};
+
+})( jQuery );
17 readme.md
@@ -0,0 +1,17 @@
+KnobKnob - a jQuery plugin for creating shiny knob controls
+===========================================================
+
+Usage:
+
+```js
+$('#elem').knobKnob({
+ snap : 10, // Snap to zero if less than this deg.
+ value: 154, // Default rotation
+ turn : function(ratio){
+ // Do what you want here. Ratio moves from 0 to 1
+ // relative to the knob rotation. 0 - off, 1 - max
+ }
+ });
+```
+
+Head on to [Tutorialzine](http://tutorialzine.com/2011/11/pretty-switches-css3-jquery/) for a live demo.
Please sign in to comment.
Something went wrong with that request. Please try again.