2

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>
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
Shayan Kanwal
  • 542
  • 4
  • 15
  • Is it really about the top and the bottom of the page, or is the rotation dependent on how much of the image is visible in the window? What should your desired effect look like? – MauriceNino Jun 22 '21 at 08:28
  • @MauriceNino The effect should like when the Image comes in the viewport height that image's rotateX have to become zero bit by bit as the scroll number increases – Shayan Kanwal Jun 22 '21 at 08:37
  • 1
    Just to make sure I understand, what you want is: as the image becomes visible in the viewport, bit by bit, it rotates from 70deg about the X axis to have got to 0degree rotation as it disappears off the top of the viewport - and vice versa? Is that right? IntersectionObserver will be useful here. – A Haworth Jun 22 '21 at 08:53
  • @AHaworth Every thing is fine that I want but what do you mean by as it disappears oof the top of the viewport – Shayan Kanwal Jun 22 '21 at 08:57
  • @AHaworth Now I understood Yes this is all I want – Shayan Kanwal Jun 22 '21 at 09:00
  • @MauriceNino AHaworth has posted what I want You can check out this – Shayan Kanwal Jun 22 '21 at 09:18
  • @ShayanKanwal I have posted you a solution for your problem. With that, you should get your desired outcome, or be able to change it to fit your needs. – MauriceNino Jun 22 '21 at 09:31

1 Answers1

1

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>
MauriceNino
  • 6,214
  • 1
  • 23
  • 60
  • The logic seems a bit complex but anyways Thanks a lot :). – Shayan Kanwal Jun 22 '21 at 09:33
  • I wanna know why the image is rotatingX after I passed the image and scrolled down and if this question seems useful you can upvote this – Shayan Kanwal Jun 22 '21 at 09:35
  • @ShayanKanwal well what you are trying to do is not a trivial subject, so of course the logic will be a bit complex. Mind that this is already the simplified version, without checking for intersections manually. – MauriceNino Jun 22 '21 at 09:35
  • @ShayanKanwal that's because it fades out of the viewport again. Check the code and docs please, there is even a pretty interactive example that shows you the percentages and stuff like that. – MauriceNino Jun 22 '21 at 09:36
  • Ok I will play with code and if I run into confusion I will ask you. By the way if this question seems useful you can upvote this It means a lot to me. – Shayan Kanwal Jun 22 '21 at 09:40
  • @ShayanKanwal Sure, but if there are bigger questions, you might be better off asking a new question to specifically target those. I have edited your question, to make it more widely applicable. – MauriceNino Jun 22 '21 at 09:45
  • Yes, Thanks again and I think you have edited my question does it effects my reputation on the site – Shayan Kanwal Jun 22 '21 at 09:47
  • @ShayanKanwal yes I have and no it does not affect your reputation. Maybe it even has a positive effect, because if people understand the question better, they might give an upvote ;) – MauriceNino Jun 22 '21 at 09:48
  • I appreciate that this answer has been accepted so it must be OK, but it isn't actually doing what the comments suggest (rotate as the image comes up the screen to the top) and I agree it is overly complex for what is needed here. – A Haworth Jun 22 '21 at 10:20
  • @AHaworth Yes, Sir do you have any easy logic to create this – Shayan Kanwal Jun 22 '21 at 10:35
  • @AHaworth as I have understood it in the original question, it should rotate from 70deg to 0deg while getting into the viewport and doing the same on the way out. I'm open to suggestions about complexity, but I don't really know how this should be done a lot simpler (other than omit a few minor things from the example from the docs). But feel free to prove me wrong. – MauriceNino Jun 22 '21 at 10:58
  • If there was no "in viewport" part in the question, the answer could be a lot simpler, yes. But as I understood it (from the original question) it has to do with the image going into the viewport. – MauriceNino Jun 22 '21 at 10:59