Mapping event client position to element position

by balefrost

HTML

<div class="scroller">
    <div class="target"></div>
    <div class="anchor"></div>
</div>
<div class="feedback"></div>

CSS

.scroller {
    width: 350px;
    height: 350px;
    border: 3px solid #000;
    overflow: scroll;
    position: relative;
}

.target {
    position: absolute;
    top: 100px;
    left: 100px;
    width: 500px;
    height: 500px;
    background-color: #dd0;
    border: 5px dashed orange;
}

.anchor {
    position: absolute;
    top: 1000px;
    left: 1000px;
    width: 1px;
    height: 1px;
 }

.feedback {
    white-space: pre;
    font-family: monospace;
}

JavaScript

var cssPixels = (function () {
    var regexp = /(\d+)px/;
    return function cssPixels(str) {
        return parseInt(regexp.exec(str)[1], 10)
    }
})();

var t = document.querySelector(".target");
var feedback = document.querySelector(".feedback");

function getOffsetTotal(elm) {
    var offset = [0, 0];
    while(elm !== null) {
        var computed = window.getComputedStyle(elm);
        offset[0] += elm.offsetLeft - elm.scrollLeft + cssPixels(computed.borderLeftWidth);
        offset[1] += elm.offsetTop - elm.scrollTop + cssPixels(computed.borderTopWidth);
        elm = elm.offsetParent;
    }
    
    return offset;
}

function getEventPos(e, elm) {
    var offsets = getOffsetTotal(elm);
    return [e.clientX - offsets[0], e.clientY - offsets[1]];
}

t.addEventListener("mousemove", function(e) {
    var offset = getOffsetTotal(t);
    var eventPos = getEventPos(e, t);
    feedback.textContent = e.clientX + " " + e.clientY + "\n" + offset[0] + " " + offset[1] + "\n" + eventPos[0] + " " + eventPos[1];
});