图像序列在进入视图之前开始动画

Image sequence starts animating before it's in view

我正在尝试复制苹果的图像排序动画 - https://www.apple.com/airpods-pro/. I've managed to track down a few examples and they all work great but they all trigger at the top of the page and I want mine to trigger in the middle of the page. I've tried attaching the trigger event to the #graphHolder container but it still starts cycling through the images as soon as you scroll at the top of the page. Can anyone point to where I'm going wrong? Here's a jsfiddle - https://jsfiddle.net/mvyw2bc3/2/

const html = document.documentElement;
const canvas = document.getElementById("hero-lightpass");
const context = canvas.getContext("2d");

const frameCount = 132;
const currentFrame = index => ( `https://res.cloudinary.com/icebreakernz/image/upload/v1623273037/globalcampaign/plastic-free/sequence-test/IB-Graph_Animation${index.toString().padStart(4, '0')}.jpg`
)

const preloadImages = () => {
  for (let i = 1; i < frameCount; i++) {
    const img = new Image();
    img.src = currentFrame(i);
  }
};

const img = new Image()
img.src = currentFrame(1);
canvas.width=1920;
canvas.height=1080;
img.onload=function(){
  context.drawImage(img, 0, 0);
}

const updateImage = index => {
  img.src = currentFrame(index);
  context.drawImage(img, 0, 0);
}

window.addEventListener('scroll', () => {  
  const scrollTop = html.scrollTop;
  const maxScrollTop = html.scrollHeight - window.innerHeight;
  const scrollFraction = scrollTop / maxScrollTop;
  const frameIndex = Math.min(
    frameCount - 1,
    Math.ceil(scrollFraction * frameCount)
  );
  
  requestAnimationFrame(() => updateImage(frameIndex + 1))
});

preloadImages()

你不能做一个相交观察器并让它在被推到图像底部的 div 上触发(可能有一个绝对位置和底部零或者你知道什么)然后在观察者中触发任何回调函数?我不确定这是否有任何帮助,但这是我制作的一个函数,可让您在元素相交时调用回调函数

export const elementObserver = (callback, options) => {
 if (typeof options.element != "undefined") {
   return new IntersectionObserver(
     (entries, observer) => {
       entries.forEach(entry => {
         let target = entry.target;
         if (entry.isIntersecting) {
           callback(options);
         }
       });
     },
     {
       threshold: 0.5
     }
   ).observe(options.element);
 }
}

您需要在 javascript 映射中传递所有回调函数变量,并且映射必须有一个名为 'element' 的键才能工作(元素是要监视的元素intersection) ...也是在它的当前状态下,它是用 es6 编写的,但你可以很容易地翻译它。 哦,也许可以玩一下阈值,但它可以设置为 1 以进一步延迟动作

对于遇到同样问题的任何人,我最终选择 ScrollTrigger which made it super simple. Check out my fiddle here to see it working as it should - https://jsfiddle.net/jdrebugL/

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

canvas.width = 1920;
canvas.height = 1080;

const frameCount = 132;
const currentFrame = index => ( `https://res.cloudinary.com/icebreakernz/image/upload/v1623273037/globalcampaign/plastic-free/sequence-test/IB-Graph_Animation${(index + 1).toString().padStart(4, '0')}.jpg`
);

const images = []
const airpods = {
  frame: 0
};

for (let i = 0; i < frameCount; i++) {
  const img = new Image();
  img.src = currentFrame(i);
  images.push(img);
}

gsap.to(airpods, {
  frame: frameCount - 1,
  snap: "frame",
  scrollTrigger: {
    scrub: 1,
    trigger: "#hero-lightpass",
    start: "top top",
    pin: true
  },
  onUpdate: render // use animation onUpdate instead of scrollTrigger's onUpdate
});

images[0].onload = render;

function render() {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.drawImage(images[airpods.frame], 0, 0); 
}