Add Numbers under UISlider

2019-07-02 01:29发布

问题:

I have a UISlider I implemented with JQuery UI. I want to add a legend under the slider showing the numbers. I followed this answer which showed how to implement that, placing then numbers with percentage values. This way when the sliders size changes, (ex. browser gets resized,) the numbers are still at the correct places.

That works fine and well, but if the browsers window is small, or if there are a lot of numbers for the slider, then the legend number get too close to each other.

Question:
How can I delete a number if they are 'x' amount too close.

Here is what I tried doing:

if (i !== 0) {
    var prevLegendNum_offsetLeft = $('#legendNum' + i).closest('.sliderLegend').find('.sliderLegendNum').offset().left

    var distance = $('#legendNum' + i).offset().left - prevLegendNum_offsetLeft;
    console.log(distance); // Logs: 0

    if (distance <= 35) {
        $('#legendNum' + i).remove();
    }
}

The reason why I had to do the whole thing with prevLegendNum_offsetLeft, and not just $('#legendNum' + (i - 1)) is because, if there are 3 numbers that are less than the distance of 35 away from each other, so 2 numbers behind i will be deleted. It will then try to access $('#legendNum' + (i - 1), but that won't be there, so it will return an error.

When I run the code above, it deletes all numbers besides for the first one.

JSFiddle

$("#slider").slider({
    value: 4,
    min: 1,
    max: 15,
    step: 1
  })
  .each(function() {
    var opt = $(this).data().uiSlider.options;
    var vals = opt.max - opt.min;

    for (var i = 0; i <= vals; i++) {
      var el = $('<div class="sliderLegend"><div class="sliderLegendMark">|</div><div class="sliderLegendNum" id="legendNum' + i + '">' + (i + 2) + '</div></div>').css('left', (i / vals * 100) + '%');
      $('#slider').append(el);

      if (i !== 0) {
        var prevLegendNum_offsetLeft = $('#legendNum' + i).closest('.sliderLegend').find('.sliderLegendNum').offset().left

        var distance = $('#legendNum' + i).offset().left - prevLegendNum_offsetLeft;
        console.log(distance);

        if (distance <= 35) {
          $('#legendNum' + i).remove();
        }
      }
    }

  });
#slider > div {
  position: absolute;
  width: 20px;
  margin-left: -10px;
  text-align: center;
  margin-top: 20px;
}
/* below is not necessary, just for style */

#slider {
  width: 50%;
  margin: 2em auto;
}
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
<div id="slider"></div>

回答1:

You could iterate over all the .sliderLegend elements (except the first one), and compare the element's left position with the closest previous element's right position.

If the right side of the closest previous element is greater than the left side of the current element, then you know that they overlap, and you can remove the element you are currently iterating over.

In the example below, the condition is left < prevRight + 6, so there is a 6px buffer. Just adjust that number accordingly to how much space you want between the numbers.

Updated Example

$('#slider .sliderLegend').slice(1).each(function() {
  var left = $(this).position().left,
    $prev = $(this).prevAll(':has(.sliderLegendNumber)').first(),
    prevRight = $prev.position().left + $prev.width(),
    $item = $(this).is(':last-child') ? $prev : $(this);

  if (left < prevRight + 6) {
    $item.find('.sliderLegendNumber').remove();
  }
});

In addition, part of the problem you were encountering was that all the children div elements had a fixed width of 20px. Due to this, you couldn't accurately calculate the offset left position of the element because the text would overflow. To work around this, I removed the fixed width and added transform: translateX(-50%) in order to center the elements horizontally.

Updated Example

#slider > div {
  position: absolute;
  text-align: center;
  margin-top: 20px;
  transform: translateX(-50%);
}

A range of 1-50 would now generate the following:

A range of 1-100 would generate the following:

Additionally, if you would like to remove the lines as well, remove the entire element rather than just the number: