Mousemove event - div position based on mouse position is inverting

Viewed 563

Edit - here is a fiddle: http://jsfiddle.net/cLahpqoj/1/ and here is an example of what i'm trying to do: https://www.seventh.tv/


perhaps my math on setting door position is bad and screwing things up. noticed the mouse postion and door position are changing places in values. logging:

{doorX: -1066, x: 396, doorY: -1367, y: 164}
{doorX: 396, x: -1065, doorY: 164, y: -1367}

from:

   let mouseX =  e.offsetX;
        let mouseY = e.offsetY;

        let doorX = currentDoorRect.x;
        let doorY = currentDoorRect.y;

        let x = doorX;
        let y = doorY;

        x =  -( x + (mouseX) );
        y =  -( y + (mouseY) );

        let transform = 'translate(' + x + 'px,' + y + 'px)';
        currentDoor.style.transform = transform;




          console.log( {
            doorX,
            x,
            doorY,
            y
          });


I'm trying to move a div with the transform:translate(x,y) css property based on the current div position and the mouse position.

I'm logging the x and y values passed to the transform change and noticing for every value change, there is one proceeding one with something like x: -1, y:0 and then immediately back to what the value should be (i.e x:-563, y:424)

I'm using Vue.js and the function is :

<template>
  <div ref="test-container" id="test-container" class="h-full relative" 
  @mousedown.prevent="disableMiddleClickScroll"
  @mousemove="moveDoors"
  @wheel="disableWheelScroll">
    <div
      :ref="`door-${index}`"
      v-for="index in numDoors" :key="index"
      class="door bg-gray-300 p-8  text-center rounded flex-none">
      Door
      </div>
  </div>
</template>

...

moveDoors(e) {
        let mouseX =  e.offsetX;
        let mouseY = e.offsetY;

   
          let currentDoor = this.$refs[`door-1`];
          let currentDoorRect = currentDoor.getBoundingClientRect();

          let doorX = currentDoorRect.x;
          let doorY = currentDoorRect.y;

          let x =  -( doorX + (mouseX) );
          let y =  -( doorY + (mouseY) );

          console.log( {
            x,
            y
          });

          let transform = 'translate(' + x + 'px,' + y + 'px)';
          currentDoor.style.transform = transform;

    
        
      },

the event is called like this:

example of console log:

{x: 1, y: -0}
{x: -547, y: -426}
{x: 1, y: -0}
{x: -545, y: -426}
{x: -0, y: 1}
{x: -544, y: -425}
{x: -0, y: 1}
{x: -546, y: -424}
{x: -1, y: -0}

The container css is:

#test-container {
  position: fixed;
    left: 0%;
    top: 0%;
    right: 0%;
    bottom: 0%;
    
}

Please let me know if there's not enough information to debug. I think this is all that is relevant.

1 Answers

If what you want is what this website is doing, then yes, your math is not the ones you need, and your strategy is also a bit off.
What they do there is a simple mapping from the viewport position to the content's one. You don't need to move each element on their own, but only the main container.

Basically, if you move your cursor to the center of the viewport, the content will move so that its center is at the center of the viewport. If you move it to the top left corner of the screen, then the content will move so that you see the top left corner of the content.

To do this, there are multiple strategies. One is to map the mouse position to a [0, 1] range, and then multiply this ratio by the content's size. You then just have to adjust for half the viewport size for the whole to be correctly centered.

const content = document.querySelector(".content");

document.onmousemove = (evt) => {
  // the mouse position (in the viewport)
  const viewport_x = evt.clientX;
  const viewport_y = evt.clientY;
  // the viewport size
  const viewport_width  = window.innerWidth;
  const viewport_height = window.innerHeight;
  // the mouse position, still relative to the viewport
  // but in a range [0, 1]
  const ratio_x = viewport_x / viewport_width;
  const ratio_y = viewport_y / viewport_height;
  
  // our content's size
  const content_rect = content.getBoundingClientRect();
  const content_width = content_rect.width;
  const content_height = content_rect.height;
  // transform the mouse position to the content's position
  const content_x = content_width * ratio_x;
  const content_y = content_height * ratio_y;
  // remove it from half the size of the viewport
  // so that aiming at the center of the viewport
  // shows the center of our content
  const translate_x = viewport_width  / 2 - content_x;
  const translate_y = viewport_height / 2 - content_y;

  content.style.setProperty("--translate-x", translate_x + "px");
  content.style.setProperty("--translate-y", translate_y + "px");

};
.content {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  transition: transform .5s ease-out;
  width: 150vw;
  height: 250vh;
  transform: translate(var(--translate-x), var(--translate-y));
  --translate-x: -25vw; /* (150vw - 100vw) / 2 */
  --translate-y: -75vh; /* (250vh - 100vw) / 2 */
}
.frame {
  border: 1px solid;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  counter-increment: frame;
}
.frame::after {
  content: counter(frame);
}
body, :root {
  overflow: auto;
  border: 0px;
}
<div class="content">
  <div class="frame"></div>  
  <div class="frame"></div>
  <div class="frame"></div>

  <div class="frame"></div>
  <div class="frame"></div>
  <div class="frame"></div>

  <div class="frame"></div>
  <div class="frame"></div>
  <div class="frame"></div>

  <div class="frame"></div>
  <div class="frame"></div>
  <div class="frame"></div>

  <div class="frame"></div>
  <div class="frame"></div>
  <div class="frame"></div>
</div>

Related