Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add padding to jQuery UI Slider

Is there an easy way to add padding to the slider-bar of a jQuery UI Slider? I'ld like to be able to have the slider-handle not reach the ends of the bar. So if this is the regular left end:

no padding
\/
[]------------------

I would like it to have padding on the left (and right) end:

padding of 10px for instance
\/
--[]----------------

I tried this in the css file:

.ui-slider-horizontal { height: .8em; padding: 0 10px; }

But it seems jQuery UI Slider uses the the complete ( outerWidth() ) width to determine the sliding range of the handle, instead of the width without padding. I also tried hacking the code, replacing outerWidth() with width(), but it didn't do anything.

I explicitly don't want to resort to a hack of setting min and max values. The values should always keep working as expected.

Any suggestions?

Edit:

Following pkauko's comment; I am using the slider as an element that has three labels above it:

   not                      very
important    important    important
----[]-----------[]----------[]----

The above illustration indicates the positions where I want the handle to appear, centered underneath the labels. But the bar visually needs to stretch to the edges.

like image 800
Decent Dabbler Avatar asked Oct 01 '10 05:10

Decent Dabbler


2 Answers

Ok, I've often wanted that myself, but never had the motivation actually to sit down and so something about it. Since you asked now, I did sit down and hacked jQuery UI's slider to add the padding options as you requested.

Note: I've only added it for horizontal sliders with a single handle. The other cases aren't any more complicated. I just didn't have the motivation to do the typing and subsequent testing to cover cases that probably weren't needed right now.

Include this code after you've included the original Slider from jQuery UI. The extension overwrites a couple of methods and adds the options 'paddingMin' and 'paddingMax' to the Slider widget (values have to be numerical and will be interpreted as pixels; this too can be easily extended to take other units, obviously, but again would imply more typing/testing for currently unrequested cases).

Simple example usage:

$('#slider').slider({ paddingMin: 50, paddingMax: 100 });

Extension hack code (provided as is, don't sue me):

(
    function($, undefined)
    {
        $.ui.slider.prototype.options =
            $.extend(
                {},
                $.ui.slider.prototype.options,
                {
                    paddingMin: 0,
                    paddingMax: 0
                }
            );

        $.ui.slider.prototype._refreshValue =
            function() {
                var
                    oRange = this.options.range,
                    o = this.options,
                    self = this,
                    animate = ( !this._animateOff ) ? o.animate : false,
                    valPercent,
                    _set = {},
                    elementWidth,
                    elementHeight,
                    paddingMinPercent,
                    paddingMaxPercent,
                    paddedBarPercent,
                    lastValPercent,
                    value,
                    valueMin,
                    valueMax;

                if (self.orientation === "horizontal")
                {
                    elementWidth = this.element.outerWidth();
                    paddingMinPercent = o.paddingMin * 100 / elementWidth;
                    paddedBarPercent = ( elementWidth - ( o.paddingMin + o.paddingMax) ) * 100 / elementWidth;
                }
                else
                {
                    elementHeight = this.element.outerHeight();
                    paddingMinPercent = o.paddingMin * 100 / elementHeight;
                    paddedBarPercent = ( elementHeight - ( o.paddingMin + o.paddingMax) ) * 100 / elementHeight;
                }

                if ( this.options.values && this.options.values.length ) {
                    this.handles.each(function( i, j ) {
                        valPercent =
                            ( ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100 )
                            * paddedBarPercent / 100 + paddingMinPercent;
                        _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
                        $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
                        if ( self.options.range === true ) {
                            if ( self.orientation === "horizontal" ) {
                                if ( i === 0 ) {
                                    self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
                                }
                                if ( i === 1 ) {
                                    self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
                                }
                            } else {
                                if ( i === 0 ) {
                                    self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
                                }
                                if ( i === 1 ) {
                                    self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
                                }
                            }
                        }
                        lastValPercent = valPercent;
                    });
                } else {
                    value = this.value();
                    valueMin = this._valueMin();
                    valueMax = this._valueMax();
                    valPercent =
                        ( ( valueMax !== valueMin )
                        ? ( value - valueMin ) / ( valueMax - valueMin ) * 100
                        : 0 )
                        * paddedBarPercent / 100 + paddingMinPercent;

                    _set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";

                    this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );

                    if ( oRange === "min" && this.orientation === "horizontal" ) {
                        this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
                    }
                    if ( oRange === "max" && this.orientation === "horizontal" ) {
                        this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
                    }
                    if ( oRange === "min" && this.orientation === "vertical" ) {
                        this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
                    }
                    if ( oRange === "max" && this.orientation === "vertical" ) {
                        this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
                    }
                }
            };

        $.ui.slider.prototype._normValueFromMouse =
            function( position ) {
                var
                    o = this.options,
                    pixelTotal,
                    pixelMouse,
                    percentMouse,
                    valueTotal,
                    valueMouse;

                if ( this.orientation === "horizontal" ) {
                    pixelTotal = this.elementSize.width - (o.paddingMin + o.paddingMax);
                    pixelMouse = position.x - this.elementOffset.left - o.paddingMin - ( this._clickOffset ? this._clickOffset.left : 0 );
                } else {
                    pixelTotal = this.elementSize.height - (o.paddingMin + o.paddingMax);
                    pixelMouse = position.y - this.elementOffset.top - o.paddingMin - ( this._clickOffset ? this._clickOffset.top : 0 );
                }

                percentMouse = ( pixelMouse / pixelTotal );
                if ( percentMouse > 1 ) {
                    percentMouse = 1;
                }
                if ( percentMouse < 0 ) {
                    percentMouse = 0;
                }
                if ( this.orientation === "vertical" ) {
                    percentMouse = 1 - percentMouse;
                }

                valueTotal = this._valueMax() - this._valueMin();
                valueMouse = this._valueMin() + percentMouse * valueTotal;

                return this._trimAlignValue( valueMouse );
            };
    }
)(jQuery);
like image 81
Thomas Avatar answered Nov 09 '22 23:11

Thomas


Would the "snap to increments" coupled with "incompatible" (uneven to the snap values) min and max values give the desired effect? I know that this would more than likely lead to application side value conversion as this probably cannot be obtained using the values used now, but here's a "hack and slash" 'solution' if it works.

What I'm suggesting is set the min value to, say, 750. Snap value to 1200 and max value to 4050. That way the lowest snap is 450 higher than the minimum value and the slider should never reach the leftmost edge. Same for the max value, that's 3 x 1200 + 450 = 4050. The values used here are arbitrary and for example only.

Haven't tested this and have no idea if it works and I know this is not what you were looking for, but just an idea that came to mind, when I checked the examples of how jquery UI slider works at jqueryui.com.

Edit: couldn't let go of this and now I know this works in the way that it prevents the slider from reaching the ends of the slide. You just need to set the initial value accordingly to prevent the slider from being in one end or the other when the page loads.

like image 22
pkauko Avatar answered Nov 10 '22 00:11

pkauko