How to animate rotateX on scroll in pure JS?

Viewed 78

I am trying to create a scroll effect with an image whose rotateX is something like 70deg (or any number).

Whenever someone scrolls the image into viewport, the rotateX of the image has to become 0deg.

In the same way, if someone scrolls the image out of the viewport, the rotateX of the image has to become 70deg again

Here is my code:

let a = 70
function test(){
let image = document.querySelector("img");
let imageTop = image.getBoundingClientRect().top;
  
let screenpos = window.innerHeight /2
// console.log("test")
   if(imageTop < screenpos){
    image.style.border = "5px solid green"
    // console.log(window.scrollY/10)
     
    image.style.transform = `rotateX(${a=a-2}deg)`
    // console.log("its reached ")
  }

  
}


window.addEventListener("scroll",function(){
   test()
})
body {
  background-color: #ccc;
  text-align: center;
  margin-top: 100px;
  font-family: sans-serif;
}
.bgcolor {
  background-color: black;
  color: rgba(255, 255, 255, 0.8);
}
div{
  perspective:800px;
  margin-top:400px;
  margin-bottom:200px;
}
div img {
  transform:rotateX(66deg);
  transition:.9s;
/*   border: 1px solid #000; */
  
  }
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h1>Scroll Please</h1>
  <div><img src="https://cdn.pixabay.com/photo/2021/06/10/22/14/stork-6327150__340.jpg" alt="Bird Image"></div>
  
</body>
</html>

1 Answers

I have created you a small snippet using the example from the Mozilla docs of the Intersection Observer API.

To get a better understanding of everthing going on, feel free to check out the linked docs.

const image = document.querySelector("img");

// Create the Observer on page load
window.addEventListener("load", (event) => {
  createObserver();
}, false);

// Setup the Observer
function createObserver() {
  let observer;

  let options = {
    root: null,
    rootMargin: "0px",
    threshold: buildThresholdList()
  };

  observer = new IntersectionObserver(handleIntersect, options);
  observer.observe(image);
}

// Getting an array with 1000 values between 0.0 and 1.0
function buildThresholdList() {
  let thresholds = [];
  let numSteps = 1000;

  for (let i=1.0; i<=numSteps; i++) {
    let ratio = i/numSteps;
    thresholds.push(ratio);
  }

  thresholds.push(0);
  return thresholds;
}

// What to do with the observer intersections
function handleIntersect(entries, observer) {
  entries.forEach((entry) => {
    // Only get values between 0 and 0.5, so that the image only 
    // ...starts animating when half visible
    const maxxedIntersect = entry.intersectionRatio > 0.5 
        ? entry.intersectionRatio - 0.5 
        : 0;
    
    // Scale the number (0.0 ... 0.5) between 0 and 70
    const scaled = scaleBetween(maxxedIntersect, 0, 70, 0, 0.5);
    
    // Get the value that the thing should rotate
    // When the element is fully visible, the scaled value will be 70, 
    // ... so we have to sub from 70 to get 0 in this example
    const rotateValue = parseInt(70 - scaled);
    
    // Apply the style
    image.style.transform = `rotateX(${rotateValue}deg)`
  });
}

// Helper function for scaling numbers between min and max
// Look here: https://stackoverflow.com/a/31687097/9150652
function scaleBetween(unscaledNum, minAllowed, maxAllowed, min, max) {
  return (maxAllowed - minAllowed) * (unscaledNum - min) / (max - min) + minAllowed;
}
body {
  background-color: #ccc;
  text-align: center;
  margin-top: 100px;
  font-family: sans-serif;
}
.bgcolor {
  background-color: black;
  color: rgba(255, 255, 255, 0.8);
}
div > img{
  margin-top: 400px;
  margin-bottom: 600px;
  perspective: 800px;
  border: 5px solid green;
  transition: .1s;
}
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  </head>
  <body>
    <h1>Scroll Please</h1>
    <div>
      <img src="https://cdn.pixabay.com/photo/2021/06/10/22/14/stork-6327150__340.jpg" 
           alt="Bird Image">
    </div>
  </body>
</html>

Related