Get the offset position of an HTML5 range slider handle

Viewed 13343

Is there any way to get the pixel position of the slider handle of an HTML5 range input ?

<input type="range" id="combicalc_contribution-slider" min="1" max="50" value="25">

I have tried calculating the position using a combination of max, min & value to work out the percentage 'down the track' but the calcualted value varies to the left at lower values and the right at higher values.

Here's the code for that:

var sliderWidth = slider[0]['clientWidth'];
var sliderPos = slider[0]['valueAsNumber'] / slider[0]['max'];
jQuery(id).closest('.sliderContainer').append('<div class="sTt">' + val + '</div>');
var sTtWidth = jQuery(id).closest('.sliderContainer').find('.sTt').outerWidth(true) / 2;
var ttPos = (sliderWidth * sliderPos);
ttPos = ttPos - sTtWidth;
ttPos = ttPos + 'px';
jQuery('.sTt').css({'left': ttPos});

The overall aim is to place a 'tooltip' above the slider handle as it moves with the value in it.

Here's a jsFiddle which highlights the issue

4 Answers

Try this

val = slider.val();

// Measure width of slider element. adjust by 15 to account for padding/border
width = slider.width() - 15;

// Calculate percentage between left and right of input
min = slider.attr('min');
max = slider.attr('max');
percent = (val - min) / (max - min);

// Janky value to get pointer to line up better
offset = -3;

// the position of the output
newPosition = width * percent + offset;

slider.next('output')
  .css({left: newPosition})
  .text(val);

Adapted from here

I ran into this same problem, where the label position was skewed at the far ends of the slider: skewed slider label

I noticed that the problem incrementally improved as you move towards the center of the slider and then incrementally got worse as you moved toward the other end:

perfectly centered slider label

I think what is happening is that because the thumb must not extend beyond the bounds of the slider track, half of the thumb's width is incrementally shaved from the thumb's position as it moves down the slider. The end result is that when the thumb's edge (not its center) reaches the end of the slider, the slider value is at its min or max.

So, to fix the skewed label, we need to calculate that dynamic offset. Here is an extra verbose offset calculation in an attempt to better explain the problem (and solution):

var half_thumb_width = 25/2;

var half_label_width = $(range_input).prev('span.rs-label').outerWidth()/2;

var slider_width = $(range_input).width();
var center_position = slider_length/2;

var percent_of_range = (range_input.value / (range_input.max - range_input.min));
var value_px_position = percent_of_range * slider_length;
var dist_from_center = value_px_position - center_position;
var percent_dist_from_center = dist_from_center / center_position;

var offset = percent_dist_from_center * half_thumb_width;

var final_label_position = value_px_position - half_label_width - offset;

I put together a quick demo of the problem and solution here: codepen demo

It was fun to figure out, but I hope this can help prevent others from spending the time.

This worked for me:

var slider = $("#combicalc_contribution-slider")[0];
var sliderPos = slider.value / slider.max;

var pixelPostion = slider.clientWidth * sliderPos;
//this is your pixel value
console.log(pixelPostion);

The pixel value was calculated properly for values from 1 to 50, on your example.

Here is an alternative solution, basically get the mouse position and use that instead of the slider position. (some tweaking required, possibly)

Fiddle here: https://jsfiddle.net/brightertools/qdhp2g17/5/

CSS:

.sliderHolder{
  margin: 0;
  padding: 0;
  position: relative;
  border: 1px solid silver;
  #slider{
    width: 100%;
  }
  .tt{
    position: absolute;
    border: 1px solid grey;
    top: 20px;
    margin: 5px;
  }
}

HTML:

<div class="sliderHolder">
<input type="range" min="0" max="100" id="slider" />
</div>

JS:

var dragging = false;
jQuery('#slider').on('input',function(){
  dragging = true;
});
jQuery('#slider').on('mouseup',function(){
  dragging = false;
});
jQuery('#slider').on('mousemove',function(e){
if (dragging == false)
{
    return;
}
jQuery('.tt').remove();
var mouseX = e.clientX - 14;
  jQuery('.tt').remove();
  var slider = jQuery('#slider');
    var sliderValue = jQuery('#slider').val();
   jQuery('.sliderHolder').append('<div class="tt">' + sliderValue + '</div>');
  jQuery('.tt').css({'left':mouseX + 'px'});
})
Related