Как выровнять метки данных в ползунке диапазона между минимальным и максимальным значениями

#javascript #html #css

Вопрос:

Это очень специфично и отчасти случайно, и ответы, которые я нашел, не совсем соответствуют этому конкретному варианту использования. Для краткости, вот ссылка на демо-версию CodePen:

https://codepen.io/mikejandreau/pen/GRWNprN

Как вы, вероятно, можете видеть с первого взгляда, у меня есть четыре метки данных, которые не совпадают с ползунком диапазона при его перемещении. Минимальные и максимальные значения в порядке, у меня проблемы только со средними значениями.

Это основано на примере, в котором были только минимальные/максимальные значения, и я пытаюсь его настроить. Я попытался добавить дополнительные атрибуты данных между data-min-label-id и data-max-label-id , хотя это не сработало так хорошо.

Как обычно, я, вероятно, упускаю что-то очевидное. Мы будем очень признательны за любую помощь или указания.

 <div id="wrapper">
  <div id="sliderContainer">

    <div class="tick-slider">

      <div class="tick-slider-header">
        <span><label for="weightSlider">Slider</label></span>
      </div>
      
      <div class="tick-slider-background"></div>
      <div id="weightProgress" class="tick-slider-progress"></div>
      <div id="weightTicks" class="tick-slider-tick-container"></div>
      <input
             id="weightSlider"
             class="tick-slider-input"
             type="range"
             min="0"
             max="5000"
             step="1000"
             value="1000"
             data-tick-step="1000"
             data-tick-id="weightTicks"
             data-value-id="weightValue"
             data-progress-id="weightProgress"
             data-handle-size="18"
             data-min-label-id="weightLabelMin"
             data-max-label-id="weightLabelMax"
             />

      <div class="tick-slider-value-container">
        <div id="weightLabelMin" class="tick-slider-label">0</div>

        <!-- I want to align these 4 items -->
        <div id="weightLabelA" class="tick-slider-label">1000</div>
        <div id="weightLabelB" class="tick-slider-label">2000</div>
        <div id="weightLabelC" class="tick-slider-label">3000</div>
        <div id="weightLabelD" class="tick-slider-label">4000</div> 

        <div id="weightLabelMax" class="tick-slider-label">5000</div>
        <div id="weightValue" class="tick-slider-value"></div>
      </div>
    </div>
  </div>
 
 function init() {
    const sliders = document.getElementsByClassName("tick-slider-input");

    for (let slider of sliders) {
        slider.oninput = onSliderInput;
        updateValue(slider);
        updateValuePosition(slider);
        updateLabels(slider);
        updateProgress(slider);
        setTicks(slider);
    }
}

function onSliderInput(event) {
    updateValue(event.target);
    updateValuePosition(event.target);
    updateLabels(event.target);
    updateProgress(event.target);
}

function updateValue(slider) {
    let value = document.getElementById(slider.dataset.valueId);

    value.innerHTML = "<div>"   slider.value   "</div>";
}

function updateValuePosition(slider) {
    let value = document.getElementById(slider.dataset.valueId);

    const percent = getSliderPercent(slider);

    const sliderWidth = slider.getBoundingClientRect().width;
    const valueWidth = value.getBoundingClientRect().width;
    const handleSize = slider.dataset.handleSize;

    let left = percent * (sliderWidth - handleSize)   handleSize / 2 - valueWidth / 2;

    left = Math.min(left, sliderWidth - valueWidth);
    left = slider.value === slider.min ? 0 : left;

    value.style.left = left   "px";
}

function updateLabels(slider) {
    const value = document.getElementById(slider.dataset.valueId);
    const minLabel = document.getElementById(slider.dataset.minLabelId);
    const maxLabel = document.getElementById(slider.dataset.maxLabelId);

    const valueRect = value.getBoundingClientRect();
    const minLabelRect = minLabel.getBoundingClientRect();
    const maxLabelRect = maxLabel.getBoundingClientRect();

    const minLabelDelta = valueRect.left - (minLabelRect.left);
    const maxLabelDelta = maxLabelRect.left - valueRect.left;

    const deltaThreshold = 32;

    if (minLabelDelta < deltaThreshold) minLabel.classList.add("hidden");
    else minLabel.classList.remove("hidden");

    if (maxLabelDelta < deltaThreshold) maxLabel.classList.add("hidden");
    else maxLabel.classList.remove("hidden");
}

function updateProgress(slider) {
    let progress = document.getElementById(slider.dataset.progressId);
    const percent = getSliderPercent(slider);

    progress.style.width = percent * 100   "%";
}

function getSliderPercent(slider) {
    const range = slider.max - slider.min;
    const absValue = slider.value - slider.min;

    return absValue / range;
}

function setTicks(slider) {
    let container = document.getElementById(slider.dataset.tickId);
    const spacing = parseFloat(slider.dataset.tickStep);
    const sliderRange = slider.max - slider.min;
    const tickCount = sliderRange / spacing   1; //  1 to account for 0

    for (let ii = 0; ii < tickCount; ii  ) {
        let tick = document.createElement("span");

        tick.className = "tick-slider-tick";

        container.appendChild(tick);
    }
}

function onResize() {
    const sliders = document.getElementsByClassName("tick-slider-input");

    for (let slider of sliders) {
        updateValuePosition(slider);
    }
}

window.onload = init;
window.addEventListener("resize", onResize);