Home > OS >  how to make scrolling animation tied to a specific div scrollbar
how to make scrolling animation tied to a specific div scrollbar

Time:01-18

I am trying to replicate Apple's scrolling animation but would like to tie the animation to a specific div scrollbar and not the main html/body scrollbar.

I have taken this example below from: https://css-tricks.com/lets-make-one-of-those-fancy-scrolling-animations-used-on-apple-product-pages/

// Canvas settings
const canvas = document.getElementById("hero-lightpass");
const context = canvas.getContext("2d");

canvas.width=1158;
canvas.height=770;


// Preloading images to drastically improve performance
const currentFrame = index => (`https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`);
const frameCount = 148; // There 148 images for that animation-sequence to load
const images = [];

const preloadImages = () => {
    for (let i = 1; i < frameCount; i  ) {
        images[i] = new Image(); // This is functionally equivalent to document.createElement('img').
        images[i].src = currentFrame(i);
    }
};

preloadImages();


// Draw the first image
const img = new Image();
img.src = currentFrame(1);
img.onload = function(){
    context.drawImage(img, 0, 0);
}


// Scroll interactions
const html = document.getElementsByTagName('html');

window.addEventListener('scroll', () => {  
    const scrollTop = html[0].scrollTop;
    // console.log('scrollTop: ', scrollTop);
    // console.log('html.scrollHeight: ', html[0].scrollHeight);
    // console.log('window.innerHeight: ', window.innerHeight);
    const maxScrollTop = html[0].scrollHeight - window.innerHeight;
    const scrollFraction = scrollTop / maxScrollTop;
    const frameIndex = Math.min(
        frameCount - 1,
        Math.floor(scrollFraction * frameCount)
    );
    // console.log('FrameIndex', frameIndex);

    requestAnimationFrame(() => context.drawImage(images[frameIndex   1], 0, 0));

});
html {
  height: 100vh;
}

body {
  background: #000;
  height: 200vh;
}

canvas {
  position: fixed;
  left: 50%;
  top: 50%;
  max-height: 100vh;
  max-width: 100vw;
  transform: translate(-50%, -50%);
}

h1 {
    color: white;
}
<body>
    <canvas id="hero-lightpass"></canvas>  
</body>

I tried putting the canvas inside a DIV, made the DIV scrollable, and tied the JS to that DIV but I am not able to make it work.

Broken example: https://jsfiddle.net/w6o0k3sf/

Any help is greatly appreciated!

CodePudding user response:

Just change html[0] to html

        // Canvas settings
        const canvas = document.getElementById("hero-lightpass");
        const context = canvas.getContext("2d");

        canvas.width = 1158;
        canvas.height = 770;


        // Preloading images to drastically improve performance
        const currentFrame = index => (`https://www.apple.com/105/media/us/airpods-pro/2019/1299e2f5_9206_4470_b28e_08307a42f19b/anim/sequence/large/01-hero-lightpass/${index.toString().padStart(4, '0')}.jpg`);
        const frameCount = 148; // There 148 images for that animation-sequence to load
        const images = [];

        const preloadImages = () => {
          for (let i = 1; i < frameCount; i  ) {
            images[i] = new Image(); // This is functionally equivalent to document.createElement('img').
            images[i].src = currentFrame(i);
          }
        };

        preloadImages();


        // Draw the first image
        const img = new Image();
        img.src = currentFrame(1);
        img.onload = function() {
          context.drawImage(img, 0, 0);
        }


        // Scroll interactions
        const html = document.getElementById('wrap');

        html.addEventListener('scroll', () => {
          const scrollTop = html.scrollTop;
          const maxScrollTop = html.scrollHeight - window.innerHeight;

          const scrollFraction = scrollTop / maxScrollTop;
          const frameIndex = Math.min(
            frameCount - 1,
            Math.floor(scrollFraction * frameCount)
          );
          requestAnimationFrame(() => context.drawImage(images[frameIndex   1], 0, 0));

        });
html {
  height: 100vh;
  overflow: hidden;
}

body {
  margin: 0;
  padding: 0;
}

#wrap {
  height: 400px;
  width: 100vw;
  overflow-y: scroll;
  background: red;
  z-index: 5;
}

#container {
  height: 2000px;
  background: yellow;
}

canvas {
  position: fixed;
  top: 0;
  max-height: 80vh;
  max-width: 80vw;
}
<body>
  <div id="wrap">
    <div id="container">
      <canvas id="hero-lightpass"></canvas>
    </div>
  </div>
</body>

  •  Tags:  
  • Related