How can I get the mouse coordinates relative to a parent div? Javascript

34,436

Solution 1

In essence: 'mouseposition' - 'parent element position' = 'mouseposition relative to parent element'

So here I modified your function:

function onMousemove(e){
    var m_posx = 0, m_posy = 0, e_posx = 0, e_posy = 0,
           obj = this;
    //get mouse position on document crossbrowser
    if (!e){e = window.event;}
    if (e.pageX || e.pageY){
        m_posx = e.pageX;
        m_posy = e.pageY;
    } else if (e.clientX || e.clientY){
        m_posx = e.clientX + document.body.scrollLeft
                 + document.documentElement.scrollLeft;
        m_posy = e.clientY + document.body.scrollTop
                 + document.documentElement.scrollTop;
    }
    //get parent element position in document
    if (obj.offsetParent){
        do { 
            e_posx += obj.offsetLeft;
            e_posy += obj.offsetTop;
        } while (obj = obj.offsetParent);
    }
    // mouse position minus elm position is mouseposition relative to element:
    dbg.innerHTML = ' X Position: ' + (m_posx-e_posx) 
                  + ' Y Position: ' + (m_posy-e_posy);
}

var elem = document.getElementById('container');
elem.addEventListener('mousemove', onMousemove, false);

var dbg=document.getElementById('dbg');  //debut output div instead of console

Here is a working demo fiddle. As you can read in the code, this also looks at the document's scroll position.

PPK's article on 'event properties' and 'find position' are (as always) a good read!

Hope this helps!

Update:
I actually found an error in ppk's code (how rare is that?!): I corrected the erroneous var in:
if (!e) var e = window.event; to if (!e){e = window.event;}

Solution 2

The accepted answer didn't work for me in Chrome. Here's how I solved it:

function relativeCoords ( event ) {
  var bounds = event.target.getBoundingClientRect();
  var x = event.clientX - bounds.left;
  var y = event.clientY - bounds.top;
  return {x: x, y: y};
}

Solution 3

Html

<div id="container" style="position: relative; width: 500px; height: 500px;">
<div style="position: absolute; left: 50px; top: 50px;"></div>
<div style="position: absolute; left: 100px; top: 100px;"></div>
</div>

Javascript

function onMousemove(event) {
    x = event.layerX; // position x relative to div
    y = event.layerY; // position y relative to div 
};

var elem = document.getElementById("container");
elem.addEventListener("mousemove", onMousemove, false);

Solution 4

Get the screenX and screenY properties to see where the mouse is on the screen (and possibly take the scrollHeight into account!).

Then get the left and top of the container element and calculate the offset between them: that is the position of the mouse in the element.

See https://developer.mozilla.org/en-US/docs/DOM/MouseEvent for more details.

Solution 5

With functional components, you can combine useRef with a click event listener (rather than needing to reference the DOM directly):

const MyElement = () => {
  const ref = useRef(null);

  useEffect(() => {
    const currentRef = ref.current;
    if (currentRef) {
      const clickListener = (e) => {
        const rightOfElement = currentRef.getBoundingClientRect().right;
        const leftOfElement = currentRef.getBoundingClientRect().left;
        const mousePosXRelativeToElement = e?.clientX ?? 0;

        const mousePosX = rightOfElement - mousePosXRelativeToElement;
        const fullWidth = rightOfElement - leftOfElement;

        // do something, e.g. changing state based on position
        if (mousePosX / fullWidth < 0.5) {
          setTheme(2);
        } else {
          setTheme(1);
        }
      };
      currentRef.addEventListener("click", clickListener);
      return () => {
        currentRef.removeEventListener("click", clickListener);
      };
    }
  }, [setTheme]);

  return (
    <div className="theme-selector-wrapper">
      <div className="theme-selector" ref={ref}></div>
    </div>
  );
};

Inside useEffect (i.e. once the element is loaded), add an event listener to the element assigned to the ref element which listens for clicks. In this example, I've changed "theme" based on the ratio of X position to the width of the element.

Share:
34,436
GriffLab
Author by

GriffLab

Updated on February 05, 2022

Comments

  • GriffLab
    GriffLab over 2 years

    I currently have a div structured with other elements inside of it.

    Something similar to below;

    <div id="container" style="position: relative; width: 500px; height: 500px;">
         <div style="position: absolute; left: 50px; top: 50px;"></div>
         <div style="position: absolute; left: 100px; top: 100px;"></div>
    </div>
    

    I am trying to get the mouse position relative to the div with the id container.

    So far I have this;

    function onMousemove(event) {
    
        x = event.offsetX;
        y = event.offsetY;
    };
    
    var elem = document.getElementById("container");
    elem.addEventListener("mousemove", onMousemove, false);
    

    This works fine if the div with the id container has no children. When the container div has children it gets the mouse co-ordinates relative to the child rather than the parent.

    What I mean by this is if the mouse was at a position of x: 51, y: 51 relative to the parent div, it would actually return x: 1, y: 1 relative to the child div, using the html given above.

    How can I achieve what I want, no libraries please.

    EDIT

    tymeJV has kindly made a jsfiddle of what is happening above.

    http://jsfiddle.net/N6PJu/1