23
<---------[]=====================================[]-------->

0         10                                     90       100

I need an input range slider with two handles to select a range, and the ability to drag the range (the equals signs in the above diagram). So, in the above example, start=10 and end=90, and it is dragged left by shifting the entire line between the two handles:

<[]=====================================[]------------------>

0                                       80                 100

Now Start is 0 and End is 80, accomplished without dragging the handles.

What library offers this functionality?

Thank you.

4
  • @Dave Jarvis I'm working on my own custom one right now. Gotta run but if you want to take a look: jsfiddle.net/EXpse/45 Lemme know if it needs to be a framework or if something custom like that will do. Commented May 23, 2011 at 1:31
  • @Thomas - Looks like it needs some work. To fit his needs I recommend modifying the existing jQuery UI slider to meet his requirement. Commented May 23, 2011 at 1:46
  • 1
    i created an extension for this. see my answer. Commented May 23, 2011 at 10:42
  • @Justin Ethier, @Dave Jarvis yeah, i hadn't worked on it much. I was just showing it's possible without TOO much trouble to roll your own. Commented May 23, 2011 at 14:02

6 Answers 6

48
+150

Overview

jQuery UI Slider widget extension for a rangeDrag feature. This feature allows the user to drag the entire range at once, rather than having to drag the handles to move the range.

Code

https://gist.github.com/3758297

(function( $, undefined ) {

$.widget("ui.dragslider", $.ui.slider, {

    options: $.extend({},$.ui.slider.prototype.options,{rangeDrag:false}),

    _create: function() {
      $.ui.slider.prototype._create.apply(this,arguments);
      this._rangeCapture = false;
    },

    _mouseCapture: function( event ) { 
      var o = this.options;

      if ( o.disabled ) return false;

      if(event.target == this.range.get(0) && o.rangeDrag == true && o.range == true) {
        this._rangeCapture = true;
        this._rangeStart = null;
      }
      else {
        this._rangeCapture = false;
      }

      $.ui.slider.prototype._mouseCapture.apply(this,arguments);

      if(this._rangeCapture == true) {  
          this.handles.removeClass("ui-state-active").blur();   
      }

      return true;
    },

    _mouseStop: function( event ) {
      this._rangeStart = null;
      return $.ui.slider.prototype._mouseStop.apply(this,arguments);
    },

    _slide: function( event, index, newVal ) {
      if(!this._rangeCapture) { 
        return $.ui.slider.prototype._slide.apply(this,arguments);
      }

      if(this._rangeStart == null) {
        this._rangeStart = newVal;
      }

      var oldValLeft = this.options.values[0],
          oldValRight = this.options.values[1],
          slideDist = newVal - this._rangeStart,
          newValueLeft = oldValLeft + slideDist,
          newValueRight = oldValRight + slideDist,
          allowed;

      if ( this.options.values && this.options.values.length ) {
        if(newValueRight > this._valueMax() && slideDist > 0) {
          slideDist -= (newValueRight-this._valueMax());
          newValueLeft = oldValLeft + slideDist;
          newValueRight = oldValRight + slideDist;
        }

        if(newValueLeft < this._valueMin()) {
          slideDist += (this._valueMin()-newValueLeft);
          newValueLeft = oldValLeft + slideDist;
          newValueRight = oldValRight + slideDist;
        }

        if ( slideDist != 0 ) {
          newValues = this.values();
          newValues[ 0 ] = newValueLeft;
          newValues[ 1 ] = newValueRight;

          // A slide can be canceled by returning false from the slide callback
          allowed = this._trigger( "slide", event, {
            handle: this.handles[ index ],
            value: slideDist,
            values: newValues
          } );

          if ( allowed !== false ) {
            this.values( 0, newValueLeft, true );
            this.values( 1, newValueRight, true );
          }
          this._rangeStart = newVal;
        }
      }



    },


    /*
    //only for testing purpose
    value: function(input) {
        console.log("this is working!");
        $.ui.slider.prototype.value.apply(this,arguments);
    }
    */
});

})(jQuery);

Example

http://jsfiddle.net/omnosis/Swd9S/

Usage

HTML

<script type="text/javascript" src="js/jquery-1.5.1.min.js"></script>
<script type="text/javascript" src="js/jquery-ui-1.8.13.custom.min.js"></script>
<script type="text/javascript" src="js/jquery.ui.slider.custom.js"></script>
...
<div id="slider"></div>

JavaScript

$(function(){
// Slider
$('#slider').dragslider({
    animate: true,   // Works with animation.
    range: true,     // Must have a range to drag.
    rangeDrag: true, // Enable range dragging.
    values: [30, 70]        
});
});
Sign up to request clarification or add additional context in comments.

9 Comments

+1 for the nice work! We ought to see about issuing a pull request for this on github.com/jquery/jquery-ui - maybe they would add it to a future release (?)
No problem, I hope their team will be receptive :)
Good stuff! One little note of caution, though: for the code "as is", the last closing curly brace } prior to the end comments has a comma after it, which will generate a javascript error, depending on the browser you are using.
this is awesome, thank you. two bits for other users: for those using with require.js, you can save this extension as its own file and shim similar to jquery-ui: 'jquery-ui-dragslider': { deps: ['jquery-ui'], exports: "$" } and, be sure you call methods within your dragslider as $('#slider').dragslider(), not slider(), or you'll get a jquery-ui error about the component not being initialized.
Is this code available for newer version(1.10.3) of jquery.ui.slider.js? Can these changes be pulled into git?
|
6

noUiSlider offers this feature. You can use it by setting the behaviouroption. It allows for both fixed and user-changeable ranges. There are no dependencies on jQueryUI, and if you prefer Zepto over jQuery: that works too.

enter image description here

Disclosure: I am the plugin author.

Comments

4

You can also try jQRangeSlider, take a look at the demo.

Comments

3

I recommend you have a look a the jQuery UI Slider.

4 Comments

Sorry, I forgot to mention: I need to be able to drag the range across the slider.
The drag functionality is not part of the jQuery UI Slider.
@Dave - I know, I answered his question before he added that requirement.
But that said, it is probably possible to modify the slider to support dragging the range. And the jQuery UI developers have discussed adding this feature.
1

You might try checking out the jQuery UI Slider

The link above demonstrates the "range" selector feature, which is what you're looking for, but there are lots of other ways to use it as well.

2 Comments

What are the other ways? The jQuery UI Slider doesn't support dragging the range across the slider, as far as I can tell.
It has a range, yes, but no way to drag the range itself. You must drag the end-points of the range.
1

You can try adding the drag + drop triggers to the $('.ui-slider-range') element
OR
add you own event to the $('.ui-slider-range') element that just trigger the events on the $('.ui-slider-handle')

1 Comment

This is the approach I'm using as it's a bit cleaner, but you do have to provide some management of the handles when the slider is dragged. Setting the ui.values[0] and [1] are the most direct way but your implementation will determine how you determine these values. I've used a pageX and slider.left comparison in combination with a set tick-width to determine how many ticks to move the values when dragging. YMMV.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.