Curved, Rounded, or Circular Sliders in Javascript with jQuery UI

Canvas and SVG in HTML5 will be great... but what can we actually roll out today? Flash? We'd rather not. Check out this curvy slider implemented with jQuery UI.

First, the fun part:

 

User picked:

What's going on here? Well the slider handle (anchor) is no longer the width of the slider handle image (as in stock jQuery UI sliders). The anchor actually goes across the full width of the "slider container". Drag from somewhere to the left of the green circle... we're still sliding.

So this is actually pretty simple. We're just customizing jQuery UI's slide function to position the handle/anchor's background image where we want, using the background-position css property and a percentage value. Sometimes the circle image is on the far left of the anchor, sometimes the far right, but most of the time somewhere in between based on a simple calculation.

We're using our old friend from high school, the circle equation, (x - h)2 + (y - k)2 = r2. It just so happens that we're going to choose the x or horizontal position (of the background image) based on the y or vertical position of the handle (mouse position while dragging). This example is of course using a vertical slider. We could reverse this if we wanted a horizontal slider, where the circle image moved up and down.

The slide function:

  1. 'slide': function(e, ui){
  2. var percentLeft;
  3. var submitValue;
  4. var Y = ui.value - 100; //Find center of Circle (We're using a max value and height of 200)
  5. var R = 100; //Circle's radius
  6. var skip = false;
  7.  
  8. $(this).children('.ui-slider-handle').attr('href',' UI.val = ' + ui.value);
  9.  
  10. //Show default/disabled/out of bounds state
  11. if ( ui.value > 0 && ui.value < 201 ) { //if in the valid slide rang
  12. $(this).children('.ui-slider-handle').addClass('is-active');
  13. }
  14. else {
  15. $(this).children('.ui-slider-handle').removeClass('is-active');
  16. }
  17.  
  18. //Calculate slider's path on circle, put it there, by setting background-position
  19. if ( ui.value >= 0 && ui.value <= 200 ) { //if in valid range, these are one inside the min and max
  20. var X = Math.sqrt((R*R) - (Y*Y)); //X^2 + Y^2 = R^2. Find X.
  21. if ( X == 'NaN' ) {
  22. percentLeft = 0;
  23. }
  24. else {
  25. percentLeft = X;
  26. }
  27. }
  28. else if ( ui.value == -1 || ui.value == 201 ) {
  29. percentLeft = 0;
  30. skip = true;
  31. }
  32. else {
  33. percentLeft = 0;
  34. }
  35.  
  36. //Move handle
  37. if ( percentLeft > 100 ) { percentLeft = 100; }
  38. $(this).children('.ui-slider-handle').css('background-position',percentLeft +'% 100%'); //set new css sprite, active state
  39.  
  40. //Figure out and set input value
  41. if ( skip == true ) {
  42. submitValue = 'fail';
  43. $(this).children('.ui-slider-handle').css('background-position',percentLeft +'% 0%'); //reset css sprite
  44. }
  45. else {
  46. submitValue = Math.round(ui.value / 2); //Clamp input value to range 0 - 100
  47. }
  48. $('#display-only input').val(submitValue); //display selected value, demo only
  49. $('#slider-display').text(submitValue); //display selected value, demo only
  50. $(this).prev('.slider-input').val(ui.value); //Set actual input field val. jQuery UI hid it for us, but it will be submitted.
  51. }

So the meat is on lines 19-34. Set the background position based on the circle equation.

The Good:

  • A default state lets users see they haven't picked anything yet... +1 for usability

The Bad:

  • We should really be using the standard anchor mouse cursor, but we would see it when not on top of the handle... which would be weird. In other words, the draggable area is not accurate.
  • The circle could follow its path a little more closely (this is a proof of concept)
  • Javascript could be much more efficient and lightweight (this is a proof of concept)

Extending this example:

You can use this as a starting point to accomplish whatever you're going for- a slider that follows a sine wave, a fully circular slider, etc.

Alternate approaches:

  1. Have the slider change the background position for a CSS sprite type image. This leads to the possibility of things like gauges or needles which start at the center of the circle and rotate based on dragging.
  2. Plain javascript... use the mouse position to absolutely position something inside of a container, as in this example, which forces the position to follow a circular path.

We know this is rough and could be improved. We welcome your suggestions, improvements, critiques, and extensions.

Comments

That's pretty sweet!

That's pretty sweet!

How can I use this for iphone

How can I use this for iphone

You'll have to be a little

You'll have to be a little more specific... in an iPhone App?

This is great but I can't

This is great but I can't figure out how to make the slider complete a full 360. Any help would be much appreciated.

Since this is based on a

Since this is based on a jQuery UI Slider, which goes left-right or top-bottom, this approach probably isn't the best for you. The user gets to an awkward position where there is no more area left to scroll over.

You could try doing revolutions around a circle based on ui.value though. For example, 0-50 would be a complete revolution, and 51-100 would be as well. As the user moused over the complete vertical (or horizontal) distance, the UI would show 2 revolutions, while the stock widget would just be doing a full slide.

Instead, you may want to simply start over with a coordinate based system with the x-y axis. Reading the x,y position of the mouse in this square would force the visible drag element to position itself on a circular path.

Post your results!

if max value chosen... I

if max value chosen... I worked it out!

Thank you!

I was searching all over to find code that would explain to me how to set different rules if for example the max value is chosen, thank you so much for this! :D

Have a GREAT summer!

the Full Source & Standalone

the Full Source & Standalone Demo link is broken.
URL:
URL

I'm not able to get the compatible source code.
any alternative link allows me to download it??

The link is fixed... sorry

The link is fixed... sorry about that.