Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery UI Sliders - Select overlapping sliders based on dragging direction

I have this simple jQuery UI Slider setup with a range and a two default values that overlap. The entire thing (with a few bells and whistles) can be found in this jsfiddle: http://jsfiddle.net/yijiang/XeyGS/

$('#slider').slider({
    min: 1,
    max: 11,
    range: true,
    values: [4, 4]
});

The problem with this is that when you attempt the drag the single visible handle to the right, it fails, because jQuery UI always places the minimum handle on top. This is obviously bad, for a number of reasons.

Is there a way to allow jQuery UI to choose which handle to drag depending on which direction the user starts dragging?

like image 567
Yi Jiang Avatar asked Nov 21 '10 18:11

Yi Jiang


1 Answers

Ah, I like it to eat through 11k libs, don't you too? :)

Note: The following is for jQuery UI 1.8.5

Anyways, here's a pretty clean solution:

// add some stuff to the slider instance
this._handleIndex = null;
this._handleStartValue = -1; 

// remember the starting values in _mouseCapture
this._handleStartValue = this.values( this._handleIndex ); 
this._mouseDownOffset = this._normValueFromMouse( { x: event.pageX, y: event.pageY } );


// modify _mouseDrag
oldValue = this.values( this._handleIndex ),
curValue;

curValue = this.values(this._handleIndex);
if ( curValue === oldValue && this._handleStartValue !== -1 ) {
    if ( normValue - this._mouseDownOffset > 0
         && ( curValue === this.values( ( this._handleIndex + 1 ) % 2 ) )
         && oldValue === this._handleStartValue) {

        this._handleIndex = (this._handleIndex + 1) % 2;
    }

} else {
    this._handleStartValue = - 1
}

// reset everything in _mouseStop
this._handleIndex = null;
this._handleStartValue = -1; 

And that's all there is to it, oh how it works, of course:

  1. Save the starting mouse offset as well as the value of the initially select handle
  2. When dragging compare the old value to the current value of the active handle and also check whether the start position is valid
  3. In case there's no difference we check whether there would be a difference if the active handle could be dragged further
  4. If that's the case we check whether both handles have the same value, that means they're on top of each other
  5. Now we check if the the currently selected handle hasn't been dragged yet
  6. And finally if all that is true, we switch the handles
  7. In case the user now changes the value we invalidate our start position so that there's no more switching between the handles

And for your pleasure here's a diff:

9960c9960,9962
< 
---
>       
>       this._handleIndex = null;
>       this._handleStartValue = -1; 
10215a10218,10219
>         this._handleStartValue = this.values( this._handleIndex ); 
>       this._mouseDownOffset = this._normValueFromMouse( { x: event.pageX, y: event.pageY } );
10243c10247,10249
<           normValue = this._normValueFromMouse( position );
---
>           normValue = this._normValueFromMouse( position ),
>           oldValue = this.values( this._handleIndex ),
>           curValue;
10246c10252,10263
< 
---
>       curValue = this.values(this._handleIndex);
>       if ( curValue === oldValue && this._handleStartValue !== -1 ) {
>           if ( normValue - this._mouseDownOffset > 0
>                && ( curValue === this.values( ( this._handleIndex + 1 ) % 2 ) )
>                && oldValue === this._handleStartValue) {
>             
>               this._handleIndex = (this._handleIndex + 1) % 2;
>           }
>         
>       } else {
>           this._handleStartValue = - 1
>       }
10257a10275,10276
>       this._handleStartValue = -1; 
>       this._handleIndex = null;

Save it to ui.diff then do patch -i ui.diff jquery-ui.js.

like image 77
Ivo Wetzel Avatar answered Nov 15 '22 14:11

Ivo Wetzel