jQuery UI Slider Draggable

2019-07-07 01:03发布

问题:

I'm trying to make my slider draggable , So for example if I have 3 options:

o---|---o---||---o

I want the slider handle to snap to closest possible option, so for example you release the mouse key between | & || in above example, it should automatically go to the middle "o". So, not to mention if it is released at any place before | , it goes to first"o" and to the last "o" if released after ||. I wrote a code and I added jQuery UI Draggable to the slider, But I have difficulty finding a solution for it to snap to the closest option.

Please note that Options are dynamic so it can be any number:

o---|---o

o---|---o---||---o---|||---o---||||---o

This is what I wrote to do the same thing for two options only:

///slider Stuff
     $(function() {
    var select = $( "#select" );
    var $max = $('#select').find('option').length;
    if ($max > 1){
    var slider = $( "<div id='slider'></div>" ).insertAfter( select ).slider({
      min: 1,
      max: $max,
      step:1,
      animate: 'true',
      range: "min",
      value: select[ 0 ].selectedIndex + 1,
       slide: function(event, ui) {
            $('#select').trigger('change'); ///trigger change event for the dropdown menu.
            select[ 0 ].selectedIndex = ui.value - 1;
          }
    });


//Draggable Stuff
    $("#slider .ui-slider-handle").draggable({
                          animate: true,
                          step: 1,
                          axis: "x",
                          containment: "parent",
                                 });

    ////Making the draggable function work if mouse is released outside of the handle by adding mouseup event to body

    $("#slider .ui-slider-handle").mousedown(function(){
     $('body').one('mouseup', function() {
    var sliderleft = $('#wwslider .ui-slider-handle').css('left').replace(/[^-\d\.]/g, '');
    ///here I tried to get the percentage of slider's position
    $sliderwidth = $("#slider").css('width').replace(/[^-\d\.]/g, '');;
    $sliderleft = $("#slider .ui-slider-handle").css('left').replace(/[^-\d\.]/g, '');;
    $max = $('#select').find('option').length;
    $selectvalue =  $('#select').val();
    $slidervalue = $("#slider").slider('value');
    $sliderpercent = ($sliderleft/$sliderwidth)*100;
    console.log($sliderpercent);

///Okay, here is what I did for two options, If it is released at some percent lower than a certain amount, set value to 1, else set it to two, But now I want to be able to do it automatically with any number of options.    
    if($sliderpercent <= 33.3) {
    $("#slider").slider('value',1);
    $('#select').trigger('change');
    }
    else {
    $("#slider").slider('value',2);
    $('#select').trigger('change');
    }
                                           });
                                                  });
    //Draggable
    $( "#select" ).change(function() {
      slider.slider( "value", this.selectedIndex + 1 );
      var $currentscs = $('#select').find(":selected").text();
     $('#holder li').fadeOut('fast');
     $('#holder li[data-scs-id*='+$currentscs+']').fadeIn('fast');
    });
    }
  });

For Better Understanding, Here is The Fiddle

As you can see in the fiddle, If you select an option from dropdown list, everything is perfect, Respective li is shown and slider moves to it's correct position, What I want is to Make it work with slider too, if you move the slider ,I want the nearest value to release point of slider to be selected in dropdown. Hope it is clear enough. Any help on this would be highly appreciated.

Update:

For more clarification, Please have a look at this default functionality of jQuery UI slider bound to "<Select>". I think What I want is already there, I just need some help figuring out how to use it: As you can see, when you click somewhere near option 2 it goes to option 2 and selects it in dropdown, if you click anywhere in the slider , it goes to nearest option, I want this exact same thing to happen with dragging, so when you drag the slider, the moment you release it, the slider should go to nearest option to the releasing point.

回答1:

If i understand you correct, what you try to accomplish in the first place is a two-way communication between the slider and the select element?

A possible solution using widget factory to extend the slider and turn the handle into a draggable: fiddle

$.widget("ui.dragSlider", $.ui.slider, {
    _create: function () {
        this._super('_create');
        var drWidth = this.element.context.clientWidth;
        var drMax = this.options.max - this.options.min;
        var drStep = drWidth / drMax;
        var perc = drStep / drWidth;
        // turn handle into draggable widget
        this._handleDraggable(this.handle, drWidth, drMax);
        // add a basic ruler to the slider 
        this._addVisuals(drMax, drStep);
    },
    // setup handle as a draggable object
    // wire up draggable event handlers with slider event handlers
    _handleDraggable: function ($handle, drWidth, drMax) {
        var that = this;
        $handle.draggable({
            animate: true,
            axis: "x",
            containment: "parent",
            drag: function (event, ui) {
                // trigger slide event on drag
                that._trigger("slide", event, ui);
            },
            stop: function (event, ui) {
                // calculate percentage of handle's position relative to
                // the slider width
                var posPer = Math.round(ui.position.left / drWidth * 100);
                // calculate value for the slider based on handles position
                var sliderPos = (posPer / 100 * drMax) + that.options.min;
                // set new value(will trigger change event)
                that._setOption("value", sliderPos);
                // trigger slider's stop event
                that._trigger("stop", "slidestop", ui);
            }
        });

    },
    // add a "basic ruler"
    _addVisuals: function (drMax, drStep) {
        for (var i = 0; i <= drMax; i++) {
            if (i == 0) {
                $("#value").append("<span>|</span>");
            } else {
                $("#value").append("<span style='padding-left:" + (drStep - 3) + "px'>|" + "</span>");
            }
        }

    },
});
// implementation of custom slider 
$(document).ready(function () {
    $("#dragSlider").dragSlider({
        min: 1,
        max: 5,
        animate: true,
        slide: function (event, ui) {
            $("#location").html(ui.position.left);
        },
        change: function (event, ui) {
            $("#select").val(ui.value);
        },
    });
    $("#select").change(function (e) {
        $("#dragSlider").dragSlider("value", $(this).val());
    });

});