Search code examples
javascripthtmlwidthmouseeventpercentage

Get percentage clicked of elements width along the x-axis


I have a page structure that looks like in the image below. When clicking anywhere in the #progress element I want to calculate how many percentages of it's full width that was clicked.

How can this be done?

< 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


Solution

  • You can get the percentage click position of an elements width along the x-axis like:

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

    e.clientX provides the horizontal coordinate within the application's client area at which the event occurred. source

    Example progress bar:

    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>