Search code examples
javascriptjquery

jQuery set tranform3d effect


enter image description here

Trying to create this mouse tracking effect - which causes a transform3d change on the block and contents - and also adds a flash light where the mouse is.

How would you write this in vanilla js so it's stable - I am not sure on the formula used to calculate these degree changes - as they seem to go min -8 to max 9 degrees.

https://jsfiddle.net/qzo3ck5m/46/

var myElement = $("#p1");

function setTranslate(xPos, yPos, zPos, el) {
  console.log("test");
  el.style.transform = `translate3d(0, 0, 0) scale3d(1, 1, 1) rotateX(${xPos}deg) rotateY(${yPos}deg) rotateZ(0deg) skew(0deg, 0deg)`;
}


myElement.mousemove(function(event) {
  console.log("mousemoveY---", event.clientX, event.clientY);

  let y = event.clientY;
  let x = event.clientX;

  var position = {
    top: myElement[0].offsetTop,
    left: myElement[0].offsetLeft
  };

  console.log("x", x);
  console.log("y", y);

  console.log("position", position);

  let degx = position.left - x;
  let degy = position.top - y;

  console.log("degx", degx);
  console.log("degy", degy);

  let fullDegrees = 8;

  setTranslate(-degx / 20, -degy / 20, 0, myElement[0]);
});


myElement.mouseleave(function() {
  console.log("mouseleave");
  setTranslate(0, 0, 0, myElement[0]);
});
.container {
  padding: 40px;
}

.blockwrapper {
  will-change: transform;
  transform: translate3d(0, 0, 0) scale3d(1, 1, 1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skew(0deg, 0deg);
  margin: 10px;
}

.block {
  background-color: skyblue;
  width: 160px;
  height: 160px;
}

.moved {
  background-color: pink;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="container">
  <div class="blockwrapper">
    <div class="block moved">Moved</div>
  </div>
  <div id="p1" class="blockwrapper">
    <div class="block">Movable</div>
  </div>
</div>


Solution

  • How about calculating the distance between the center of the block and the cursor position?

    Also, if you want to use jQuery, use the $.fn.on method to attach the listeners.

    let sensitivity = 0.5;
    
    function setTranslate($el, x, y, z=0) {
      $el.css({
        transform: `rotateX(${x}deg) rotateY(${y}deg) rotateZ(${z}deg)`
      });
    }
    
    $('.blockwrapper').on({
      mousemove: function(event) {
        const $block = $(event.currentTarget).find('.block');
        const $spotlight = $block.find('.spotlight');
      
        let { clientX: x, clientY: y } = event;
        let rect = $block[0].getBoundingClientRect();
    
        // Calculate the center of the element
        let centerX = rect.left + rect.width / 2;
        let centerY = rect.top + rect.height / 2;
    
        // Calculate the relative position from the center
        let deltaX = (x - centerX);
        let deltaY = (y - centerY);
    
        // Calculate the rotation angles to move away from the cursor
        let rotateX = -deltaY * sensitivity; // Invert to tilt away
        let rotateY = deltaX * sensitivity;  // Invert to tilt away
    
        setTranslate($block, rotateX, rotateY);
    
        // Move the spotlight
        let spotlightSize = $spotlight.width();
        let spotlightX = x - rect.left - spotlightSize / 2;
        let spotlightY = y - rect.top - spotlightSize / 2;
    
        $spotlight.css({
          transform: `translate(${spotlightX}px, ${spotlightY}px)`,
          opacity: 1
        });
      },
      mouseleave: function(event) {
        const $block = $(event.currentTarget).find('.block');
        const $spotlight = $block.find('.spotlight');
      
        setTranslate($block, 0, 0);
    
        // Hide the spotlight
        $spotlight.css({ opacity: 0 });
      }
    });
    body {
      background: #000;
    }
    
    .container {
      padding: 0.5rem;
    }
    
    .blockwrapper {
      display: inline-block;
      perspective: 1000px;
      position: relative;
      overflow: visible;
      margin: 0.5rem;
      background: red;
      width: fit-content;
      border-radius: 2rem;
      will-change: transform;
      transform: translate3d(0, 0, 0) scale3d(1, 1, 1) rotateX(0deg) rotateY(0deg) rotateZ(0deg) skew(0deg, 0deg);
    }
    
    .block {
      position: relative;
      z-index: 1;
      overflow: hidden;
      width: 120px;
      height: 120px;
      padding: 1rem;
      border: thin solid #444;
      border-radius: 1.8rem;
      background-color: #222;
      color: #eee;
      transition: transform 0.5s ease;
    }
    
    .spotlight {
      position: absolute;
      top: 0;
      left: 0;
      width: 80px;
      height: 80px;
      border-radius: 50%;
      pointer-events: none;
      background: rgb(255,255,0);
      background: radial-gradient(circle, rgba(255,255,0,0.5) 0%, rgba(255,255,0,0.1) 25%, transparent 75%);
      transform: translate(-50%, -50%);
      transition: opacity 0.2s ease;
      z-index: 2;
      opacity: 0;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <div class="container">
      <div class="blockwrapper">
        <div class="block">
          Movable #1
          <div class="spotlight"></div>
        </div>
      </div>
      <div class="blockwrapper">
        <div class="block">
          Movable #2
          <div class="spotlight"></div>
        </div>
      </div>
      <div class="blockwrapper">
        <div class="block">
          Movable #3
          <div class="spotlight"></div>
        </div>
      </div>
    </div>