javascriptgsap

How to get the correct mouse position on mouse move over element?


I'm working on a little thing where an image will follow the mouse once hover on its (in this case) parent element. Could be whatever element. When testing, it works on the first data-tail-list, but when hover on second data-tail-list or third or however many i choose to have in my markup, the image that follows the cursor gets an offset, which increases depending on how far from the browsers top the current hovered data-tail-list is. What am i doing wrong here?

Markup:

        <div class="list w-full h-16 bg-white mb-8" data-tail-list>
          <div class="absolute pointer-events-none w-64 h-96 max-w-full opacity-0 inset-0" data-tail-wrap>
            <div class="absolute w-full h-full inset-0" data-tail-item>
              <img src="./dist/img/test1.jpg">
            </div>
          </div>
        </div>
        <div class="list w-full h-16 bg-white mb-8" data-tail-list>
          <div class="absolute pointer-events-none w-64 h-96 max-w-full opacity-0 inset-0" data-tail-wrap>
            <div class="absolute w-full h-full inset-0" data-tail-item>
              <img src="./dist/img/test2.jpg">
            </div>
          </div>
        </div>

JS:

import gsap from 'gsap'

export default class Tail {
  constructor() {

    const lists = [...document.querySelectorAll('[data-tail-list]')]

    lists.forEach((el) => {
      el.addEventListener('mouseenter', this.onEnter)
      el.addEventListener('mouseleave', this.onLeave)
      el.addEventListener('mousemove', this.onMove)
    })
  }

  onEnter(e) {
    const el = e.currentTarget.querySelectorAll('[data-tail-wrap]')
    gsap.to(el, {
      opacity: 1
    })
  }

  onMove(e) {
    const el = e.currentTarget.querySelectorAll('[data-tail-item]')
    gsap.to(el,{
      x:e.clientX,
      y:e.pageY - e.currentTarget.getBoundingClientRect().top - e.currentTarget.querySelector('[data-tail-wrap]').offsetHeight/2
    })
  }

  onLeave(e) {
    const el = e.currentTarget.querySelector('[data-tail-wrap]')
    gsap.to(el, {
      opacity: 0
    })
  }
}

Solution

  • @Math on comments :

    Ok, do you mind providing some code?

    Would really appreciate it!

    Since you insist...

    Here is only a simple example of moving a Dom element based on the delta X and Y of the mouse movement reported on the moved element.

    const myDiv     = document.querySelector('#my-div');
          myDiv.mov = { x: 0, y: 0, mx:0, my:0 };
    
    myDiv.onmousedown =({clientX:x,clientY:y})=> // on element mouse down
      {
      myDiv.classList.add('onMov');
      Object.assign( myDiv.mov, {x,y});  // get mouse position 
      myDiv.mov.x -= myDiv.mov.mx;       // prepare X delta
      myDiv.mov.y -= myDiv.mov.my;       // prepare Y delta
      }
    window.onmouseup =_=>   // end of moving for any mouse up
      {
      myDiv.classList.remove('onMov')
      }
    window.addEventListener('mousemove', ({clientX:x,clientY:y}) =>  
      {
      if (myDiv.classList.contains('onMov') && x > 0 && y > 0 )
        {
        myDiv.mov.mx = x - myDiv.mov.x;  // report mouse delta X
        myDiv.mov.my = y - myDiv.mov.y;  // report mouse delta y
        myDiv.style.setProperty('--movXY', `${myDiv.mov.mx}px, ${myDiv.mov.my}px`);
        }
      })
    #my-div {
      --movXY    : 0px,0px;
      background : dodgerblue;
      border     : 1px solid #d3d3d3;
      height     : 50px;
      width      : 50px;
      margin     : 30px;
      cursor     : grab;
      transform  : translate(var(--movXY));
      }
    #my-div.onMov {
      cursor : grabbing;
      }
    <div id="my-div"></div>