Получить процентное соотношение щелчков элементов по оси X - PullRequest
1 голос
/ 04 мая 2019

У меня есть структура страницы, которая выглядит как на картинке ниже. При щелчке в любом месте элемента #progress я хочу рассчитать, сколько процентов от его полной ширины было нажато.

Как это можно сделать?

< div id="progress" onMouseUp={ e => this._seekTo(e) }></div>

...

_seekTo(event) {
    var progress = document.getElementById('progress');
    console.log((event.clientX - progress.offsetLeft) / progress.offsetWidth * 100)
}

example

1 Ответ

1 голос
/ 04 мая 2019

Вы можете получить позицию щелчка в процентах ширины элементов вдоль оси x, например:

document.getElementById('progress').addEventListener('click', function(e) {
    var bcr = this.getBoundingClientRect();
    console.log('You clicked to ', (e.clientX - bcr.left) / bcr.width);
});

Проблема при вычислениях с e.clientX и element.offsetLeft заключается в том, что они представляют две разные вещи.

element.offsetLeft - это целое число, представляющее смещение влево в пикселях от ближайшего относительно расположенного родительского элемента. источник

e.clientX предоставляет горизонтальную координату в клиентской области приложения, в которой произошло событие (в отличие от координаты на странице). источник

Это вызывает проблемы, если пользователь, например, выполняет вертикальную прокрутку. Вы можете использовать e.pageX, тогда оба они основаны на DOM, но вам все равно нужно суммировать все offsetLeft s от родительских элементов element, чтобы обе позиции относились к левому краю всего документа.

Пример индикатора выполнения:

function mouseSliderPosition(element, e) {
    var bcr = element.getBoundingClientRect();
    return {
        x: Math.min(Math.max(0, (e.clientX - bcr.left) / bcr.width), 1),
        y: Math.min(Math.max(0, (e.clientY - bcr.top) / bcr.height), 1)
    }
};

function activateSlider(e) {
    if (e.touches && e.touches.length > 1) {
        return;
    }
    e.preventDefault();

    window.activeSlider = this;
    handleSliderMove(e);
}


function handleSliderMove(e) {
    if (e.touches && e.touches.length > 1) {
        return;
    }
    if (window.activeSlider) {
        var progressBar = window.activeSlider.getElementsByClassName('progress-bar')[0];
        var progressFill = window.activeSlider.getElementsByClassName('progress-fill')[0];
        var value = mouseSliderPosition(progressBar, e.touches && e.touches[0] || e).x;
        progressFill.style.transform = 'scaleX(' + value + ')';
    }
}

function deactivateSlider(e) {
    if (e.touches && e.touches.length > 0) {
        return;
    }
    this.activeSlider = null;
}


document.querySelector('.progress-slider').addEventListener('mousedown', activateSlider)
document.querySelector('.progress-slider').addEventListener('touchstart', activateSlider)
window.addEventListener('mousemove', handleSliderMove);
window.addEventListener('mouseup', deactivateSlider);
window.addEventListener('touchmove', handleSliderMove);
window.addEventListener('touchend', deactivateSlider);
window.activeSlider = null;
.progress-slider {
    padding: 10px;
    cursor: pointer;
}

.progress-bar {
    height: 2px;
    background: rgba(100,100,100,0.5);
}

.progress-slider:hover .progress-bar {
    height: 3px;
}

.progress-fill {
    height: 100%;
    background: rgba(255, 0, 0, 0.7);
    transform-origin: 0 50%;
    transform: scaleX(0);
}
<div class="progress-slider">
  <div class="progress-bar"><div class="progress-fill"></div></div>
</div>
...