Skip to content

Commit 3f4c5bc

Browse files
committed
Changes to make slider handles not overlap, from #3467
http://dev.jqueryui.com/ticket/3467 http://chadnorwood.com/code/slider-fix.html
1 parent a8311f9 commit 3f4c5bc

File tree

1 file changed

+120
-32
lines changed

1 file changed

+120
-32
lines changed

ui/jquery.ui.slider.js

Lines changed: 120 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* jQuery UI Slider @VERSION
2+
* jQuery UI Slider 1.8.1 handle overlap patch by chadnorwood.com
33
*
44
* Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)
55
* Dual licensed under the MIT (MIT-LICENSE.txt)
@@ -181,24 +181,24 @@ $.widget( "ui.slider", $.ui.mouse, {
181181
newVal = self._valueMax();
182182
break;
183183
case $.ui.keyCode.PAGE_UP:
184-
newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
184+
newVal = curVal + ( (self._valueMax() - self._valueMin()) / numPages );
185185
break;
186186
case $.ui.keyCode.PAGE_DOWN:
187-
newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
187+
newVal = curVal - ( (self._valueMax() - self._valueMin()) / numPages );
188188
break;
189189
case $.ui.keyCode.UP:
190190
case $.ui.keyCode.RIGHT:
191191
if ( curVal === self._valueMax() ) {
192192
return;
193193
}
194-
newVal = self._trimAlignValue( curVal + step );
194+
newVal = curVal + step;
195195
break;
196196
case $.ui.keyCode.DOWN:
197197
case $.ui.keyCode.LEFT:
198198
if ( curVal === self._valueMin() ) {
199199
return;
200200
}
201-
newVal = self._trimAlignValue( curVal - step );
201+
newVal = curVal - step;
202202
break;
203203
}
204204

@@ -219,6 +219,12 @@ $.widget( "ui.slider", $.ui.mouse, {
219219

220220
});
221221

222+
223+
this._sliderPixels = ( this.orientation === "vertical" ) ? this.element.outerHeight() : this.element.outerWidth();
224+
this._handleSizePixels = ( this.orientation === "vertical" ) ? this.handles.outerHeight() : this.handles.outerWidth();
225+
this._handleSizePercent = 100 * this._handleSizePixels / this._sliderPixels;
226+
//console.log('slider.chad.js:_create sliderPixels='+this._sliderPixels +' _handleSizePixels='+this._handleSizePixels +' _handleSizePercent='+this._handleSizePercent );
227+
222228
this._refreshValue();
223229

224230
this._animateOff = false;
@@ -248,6 +254,8 @@ $.widget( "ui.slider", $.ui.mouse, {
248254
var o = this.options,
249255
position,
250256
normValue,
257+
percentValue,
258+
direction,
251259
distance,
252260
closestHandle,
253261
self,
@@ -259,41 +267,53 @@ $.widget( "ui.slider", $.ui.mouse, {
259267
if ( o.disabled ) {
260268
return false;
261269
}
262-
263270
this.elementSize = {
264271
width: this.element.outerWidth(),
265272
height: this.element.outerHeight()
266273
};
267274
this.elementOffset = this.element.offset();
268275

276+
// find closest handle to mouse
269277
position = { x: event.pageX, y: event.pageY };
270-
normValue = this._normValueFromMouse( position );
271-
distance = this._valueMax() - this._valueMin() + 1;
278+
percentValue = 100 * this._percentValueFromMouse( position );
279+
distance = 106; // any number greater than 100 percent
280+
direction = ( this.orientation === "vertical" ) ? 'bottom' : 'left';
281+
272282
self = this;
273283
this.handles.each(function( i ) {
274-
var thisDistance = Math.abs( normValue - self.values(i) );
284+
var thisDistance = percentValue - parseFloat( $(this).css(direction) );
285+
if (thisDistance > 0) {
286+
thisDistance= thisDistance - self._handleSizePercent; // account for the closer edge of handle
287+
if (thisDistance < 0)
288+
thisDistance = 0; // clicked inside handle
289+
} else {
290+
thisDistance = - thisDistance;
291+
}
292+
293+
//console.log('slider.chad.js:_mouseCapture i='+i +' distance='+distance +' thisDistance='+thisDistance +' percentValue='+percentValue +' self._handleSizePercent='+self._handleSizePercent );
294+
275295
if ( distance > thisDistance ) {
276296
distance = thisDistance;
277297
closestHandle = $( this );
278298
index = i;
279299
}
280300
});
281301

282-
// workaround for bug #3736 (if both handles of a range are at 0,
302+
// NOT NEEDED - workaround for bug #3736 (if both handles of a range are at 0,
283303
// the first is always used as the one with least distance,
284304
// and moving it is obviously prevented by preventing negative ranges)
285-
if( o.range === true && this.values(1) === o.min ) {
286-
index += 1;
287-
closestHandle = $( this.handles[index] );
288-
}
305+
//if( o.range === true && this.values(1) === o.min ) {
306+
// index += 1;
307+
// closestHandle = $( this.handles[index] );
308+
//}
289309

290310
allowed = this._start( event, index );
291311
if ( allowed === false ) {
292312
return false;
293313
}
294314
this._mouseSliding = true;
295315

296-
self._handleIndex = index;
316+
this._handleIndex = index;
297317

298318
closestHandle
299319
.addClass( "ui-state-active" )
@@ -311,6 +331,7 @@ $.widget( "ui.slider", $.ui.mouse, {
311331
};
312332

313333
normValue = this._normValueFromMouse( position );
334+
314335
this._slide( event, index, normValue );
315336
this._animateOff = true;
316337
return true;
@@ -323,7 +344,7 @@ $.widget( "ui.slider", $.ui.mouse, {
323344
_mouseDrag: function( event ) {
324345
var position = { x: event.pageX, y: event.pageY },
325346
normValue = this._normValueFromMouse( position );
326-
347+
327348
this._slide( event, this._handleIndex, normValue );
328349

329350
return false;
@@ -348,6 +369,44 @@ $.widget( "ui.slider", $.ui.mouse, {
348369
},
349370

350371
_normValueFromMouse: function( position ) {
372+
var pixelMouse,
373+
pixelRangeSlider,
374+
percentMouse,
375+
valueTotal,
376+
valueMouse;
377+
378+
pixelRangeSlider = this._sliderPixels - (2 * this._handleSizePixels);
379+
380+
if ( this.orientation === "horizontal" ) {
381+
// pixelMouse gets pixels of Handle Center, even if user clicks edge of handle
382+
pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
383+
percentMouse = (pixelMouse - this._handleSizePixels * (0.5 + this._handleIndex) ) / pixelRangeSlider;
384+
} else {
385+
pixelMouse = position.y - this.elementOffset.top;
386+
percentMouse = (pixelMouse - this._handleSizePixels * (0.5 + (1 - this._handleIndex)) ) / pixelRangeSlider;
387+
}
388+
389+
if ( percentMouse > 1 ) {
390+
percentMouse = 1;
391+
}
392+
if ( percentMouse < 0 ) {
393+
percentMouse = 0;
394+
}
395+
if ( this.orientation === "vertical" ) {
396+
percentMouse = 1 - percentMouse;
397+
}
398+
399+
valueTotal = this._valueMax() - this._valueMin();
400+
valueMouse = this._valueMin() + percentMouse * valueTotal;
401+
402+
//console.log('slider.chad.js:_normValueFromMouse i='+this._handleIndex +' _sliderPixels='+this._sliderPixels +' pixelRangeSlider='+pixelRangeSlider
403+
// +" x="+position.x+" y="+position.y +' elementOffset.top='+this.elementOffset.top +' pixelMouse='+Math.round(pixelMouse)
404+
// +' -- percentMouse='+percentMouse +' valueTotal='+valueTotal +' valueMouse='+valueMouse );
405+
406+
return this._trimAlignValue( valueMouse );
407+
},
408+
409+
_percentValueFromMouse: function( position ) {
351410
var pixelTotal,
352411
pixelMouse,
353412
percentMouse,
@@ -356,10 +415,10 @@ $.widget( "ui.slider", $.ui.mouse, {
356415

357416
if ( this.orientation === "horizontal" ) {
358417
pixelTotal = this.elementSize.width;
359-
pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
418+
pixelMouse = position.x - this.elementOffset.left;
360419
} else {
361420
pixelTotal = this.elementSize.height;
362-
pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
421+
pixelMouse = position.y - this.elementOffset.top;
363422
}
364423

365424
percentMouse = ( pixelMouse / pixelTotal );
@@ -372,12 +431,14 @@ $.widget( "ui.slider", $.ui.mouse, {
372431
if ( this.orientation === "vertical" ) {
373432
percentMouse = 1 - percentMouse;
374433
}
434+
435+
// console.log('slider.chad.js:_percentValueFromMouse _sliderPixels='+this._sliderPixels
436+
// +" y="+position.y +' elementOffset.top='+this.elementOffset.top +' pixelMouse='+pixelMouse +' pixelTotal='+pixelTotal
437+
// +' -- percentMouse='+percentMouse );
375438

376-
valueTotal = this._valueMax() - this._valueMin();
377-
valueMouse = this._valueMin() + percentMouse * valueTotal;
378-
379-
return this._trimAlignValue( valueMouse );
439+
return parseFloat( percentMouse.toFixed(5) );
380440
},
441+
381442

382443
_start: function( event, index ) {
383444
var uiHash = {
@@ -406,6 +467,7 @@ $.widget( "ui.slider", $.ui.mouse, {
406467
}
407468

408469
if ( newVal !== this.values( index ) ) {
470+
//console.log('slider.chad.js:_slide handle_index='+index+' origVal='+this.values(index)+' newVal='+newVal+' otherVal='+otherVal);
409471
newValues = this.values();
410472
newValues[ index ] = newVal;
411473
// A slide can be canceled by returning false from the slide callback
@@ -591,12 +653,12 @@ $.widget( "ui.slider", $.ui.mouse, {
591653
if ( val > this._valueMax() ) {
592654
return this._valueMax();
593655
}
594-
var step = ( this.options.step > 0 ) ? this.options.step : 1,
656+
var step = this.options.step,
595657
valModStep = val % step,
596658
alignValue = val - valModStep;
597659

598-
if ( Math.abs(valModStep) * 2 >= step ) {
599-
alignValue += ( valModStep > 0 ) ? step : ( -step );
660+
if ( valModStep >= ( step / 2 ) ) {
661+
alignValue += step;
600662
}
601663

602664
// Since JavaScript has problems with large floats, round
@@ -619,30 +681,56 @@ $.widget( "ui.slider", $.ui.mouse, {
619681
animate = ( !this._animateOff ) ? o.animate : false,
620682
valPercent,
621683
_set = {},
622-
lastValPercent,
684+
lastValPercent = 0,
685+
pixelPercent,
686+
val2pixel,
687+
h0Percent,
688+
h1Percent,
689+
rangeOffsetPercent,
690+
rangeSizePercent,
623691
value,
624692
valueMin,
625693
valueMax;
626694

627695
if ( this.options.values && this.options.values.length ) {
628696
this.handles.each(function( i, j ) {
697+
629698
valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;
630-
_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
699+
700+
val2pixel = (self._sliderPixels - 2 * self._handleSizePixels) / self._sliderPixels;
701+
pixelPercent = valPercent * val2pixel;
702+
703+
h0Percent = Math.round(pixelPercent);
704+
h1Percent = Math.round(pixelPercent + self._handleSizePercent);
705+
rangeOffsetPercent = Math.floor(pixelPercent + self._handleSizePercent);
706+
rangeSizePercent = Math.ceil(
707+
self._handleSizePercent*0.3 + // extend range into handle to make sure its long enough
708+
val2pixel * (valPercent - lastValPercent) );
709+
710+
//console.log('slider.chad.js:_refreshValue index='+i +' val='+self.values(i) +' valPercent='+valPercent
711+
// +' rangeOffsetPercent='+rangeOffsetPercent+' rangeSizePercent='+rangeSizePercent +' h0Percent='+h0Percent +' h1Percent='+h1Percent
712+
// +' pixelPercent='+pixelPercent +' handlePercent='+self._handleSizePixels);
713+
714+
// update the handle
715+
_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = (i ? h1Percent : h0Percent) + "%";
631716
$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
717+
718+
// update the range in middle
632719
if ( self.options.range === true ) {
633720
if ( self.orientation === "horizontal" ) {
634721
if ( i === 0 ) {
635-
self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
722+
self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: rangeOffsetPercent + "%" }, o.animate );
636723
}
637724
if ( i === 1 ) {
638-
self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
725+
self.range[ animate ? "animate" : "css" ]( { width: rangeSizePercent + "%" }, { queue: false, duration: o.animate } );
639726
}
640727
} else {
641728
if ( i === 0 ) {
642-
self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
729+
self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: rangeOffsetPercent + "%" }, o.animate );
643730
}
644731
if ( i === 1 ) {
645-
self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
732+
//self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
733+
self.range[ animate ? "animate" : "css" ]( { height: rangeSizePercent + "%" }, { queue: false, duration: o.animate } );
646734
}
647735
}
648736
}
@@ -676,7 +764,7 @@ $.widget( "ui.slider", $.ui.mouse, {
676764
});
677765

678766
$.extend( $.ui.slider, {
679-
version: "@VERSION"
767+
version: "1.8.1"
680768
});
681769

682770
}(jQuery));

0 commit comments

Comments
 (0)