3

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.

Ramtin Gh
  • 1,035
  • 2
  • 11
  • 31
  • @Shaddow That's exactly what I'm doing, But I need it to be Draggable at the same time, so you can drag it even between the values, Slider bound to select only jumps from one value to another. – Ramtin Gh Jun 21 '13 at 22:39
  • sony... much clearest soulution draggable slider without animation ofc, look, may be help you... http://www.pureexample.com/jquery-ui/draggable-options-opacity.html – daremachine Jun 21 '13 at 22:56
  • @daremachine Slider + Draggable is what Im looking for – Ramtin Gh Jun 23 '13 at 07:24

1 Answers1

0

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());
    });

});
rusln
  • 1,284
  • 8
  • 10
  • 2# rusln good idea and pretty solution 2# sony ... KISS .. read jqUi API =) – daremachine Jun 21 '13 at 23:11
  • Thanks, the problem with sony's example (in my opinion) is that the actual problem is not clear because of all the implementation details. Hey, i've missed your edit, can't find how to accept it now :/. Your solution is obviously better ! – rusln Jun 21 '13 at 23:43
  • @rusln Thanks, but the fiddle you provided does exactly what jquery ui (slider bound to select) does, what I need is merging it with draggable function, I think the question is clear enough. – Ramtin Gh Jun 23 '13 at 07:22
  • @rusln np look at my edit ... 2@sony ... this is help not finish solution .. if you need any change this code is better for maintainance. But if we help you pls vote this thread as correct ;) thx – daremachine Jun 23 '13 at 10:12
  • @daremachine your edit been rejected(not by me). Sony i think to do what you want to do you'll have to look at widget factory. I will be experimenting with your problem today. Will let you know once i have something decent. – rusln Jun 23 '13 at 11:02
  • @daremachine Thanks for the help, But I think there must be a solution, actually I did it before with 2 options(fixed) by using conditional statements , (so if the slider position is less than 50% go to option 1 , and if more than 50% go to option 2), here I'm looking for a solution to do it with any number of option, so there is no need to fake it with more steps, and it really doesn't give the desired result. – Ramtin Gh Jun 23 '13 at 15:30
  • Sony i've updated my second example with code+fiddle. It now has a draggable handle living inside a custom slider widget, the math to calculate the position of the handle is off, but i'll leave that up to you. – rusln Jun 23 '13 at 16:20
  • @daremachine This was the reason: 'This edit changes too much in the original post; the original meaning or intent of the post would be lost.' – rusln Jun 23 '13 at 16:34
  • @daremachine, thanks man. I was looking for an excuse to try out widget factory :). Glad you liked it. I've fixed the "math problem". So an updated version is in my post. – rusln Jun 24 '13 at 10:30