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.

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Rudiger
  • 231
  • 1
  • 2
  • 4
  • @Dave Jarvis I'm working on my own custom one right now. Gotta run but if you want to take a look: http://jsfiddle.net/EXpse/45/ Lemme know if it needs to be a framework or if something custom like that will do. – Thomas Shields May 23 '11 at 01:31
  • @Thomas - Looks like it needs some work. To fit his needs I recommend modifying the existing jQuery UI slider to meet his requirement. – Justin Ethier May 23 '11 at 01:46
  • 1
    i created an extension for this. see my answer. – Gergely Fehérvári May 23 '11 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. – Thomas Shields May 23 '11 at 14:02

6 Answers6

48

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]        
});
});
Gergely Fehérvári
  • 7,811
  • 6
  • 47
  • 74
  • 6
    +1 for the nice work! We ought to see about issuing a pull request for this on https://github.com/jquery/jquery-ui - maybe they would add it to a future release (?) – Justin Ethier May 23 '11 at 14:16
  • No problem, I hope their team will be receptive :) – Justin Ethier May 24 '11 at 21:45
  • 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. – mg1075 Dec 20 '12 at 17:40
  • 2
    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. – ericsoco Oct 22 '13 at 17:29
  • Is this code available for newer version(1.10.3) of jquery.ui.slider.js? Can these changes be pulled into git? – John Smith Nov 21 '13 at 10:49
  • Works perfectly (thank you!) except in Opera - grabs the nearest handle and resizes instead.. ? – T4NK3R Aug 18 '14 at 15:05
  • I use this implementation, it works fine with mouse. How could I trigger the slide effect to go right or left with right and left keys respectively? – partizanos Nov 02 '15 at 13:41
  • @ericsoco Can you explain the second bit a bit please. I can't call any getter or setter on `$('#slider').dragslider()` but have no problem with`$('#slider').slider()` caling ` $( "#slider" ).on( "slidechange", function( event, ui ) {console.log("changed");} );` Thanks in advance – Douglas Sep 05 '19 at 22:29
  • To answer my question for anyone stuck, events like `.on("change", function(){});` will now be `.on("dragslider change", function(){});`. The name of the custom plugin is concatanated to the name of the event. – Douglas Sep 06 '19 at 01:46
5

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.

Lg102
  • 4,733
  • 3
  • 38
  • 61
4

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

ghusse
  • 3,200
  • 2
  • 22
  • 30
3

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

Justin Ethier
  • 131,333
  • 52
  • 229
  • 284
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.

Thomas Shields
  • 8,874
  • 5
  • 42
  • 77
  • What are the other ways? The jQuery UI Slider doesn't support dragging the range across the slider, as far as I can tell. – Rudiger May 10 '11 at 19:30
  • It has a range, yes, but no way to drag the range itself. You must drag the end-points of the range. – Dave Jarvis May 22 '11 at 23:40
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')

Johan Olsson
  • 608
  • 3
  • 10
  • 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. – J E Carter II Sep 25 '13 at 13:38