图像序列在它出现之前开始动画

Posted

技术标签:

【中文标题】图像序列在它出现之前开始动画【英文标题】:Image sequence starts animating before it's in view 【发布时间】:2021-08-29 22:03:06 【问题描述】:

我正在尝试复制苹果的图像排序动画 - https://www.apple.com/airpods-pro/。我设法找到了一些示例,它们都运行良好,但它们都在页面顶部触发,我希望我的在页面中间触发。我已经尝试将触发事件附加到#graphHolder 容器,但只要您在页面顶部滚动,它仍然会开始循环浏览图像。谁能指出我哪里出错了?这是一个 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()

【问题讨论】:

【参考方案1】:

对于遇到同样问题的任何人,我最终选择了ScrollTrigger,这使它变得超级简单。在这里查看我的小提琴,看看它应该如何工作 - 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); 

【讨论】:

【参考方案2】:

难道你不能做一个交点观察者,让它在一个被推到图像底部的 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 映射中传递所有回调函数变量,并且映射必须有一个名为“元素”的键才能工作(元素是要监视交叉点的元素)......也在它的当前状态它是用 es6 编写的,但您可以轻松翻译它。 哦,也许可以使用阈值,但将其设置为 1 以进一步延迟动作

【讨论】:

感谢您的回复!最后我最终选择了 gsaps scrollTrigger。是一个非常优雅的解决方案。 太棒了!很高兴你找到了一个好的解决方案。您提到的插件听起来不错,但是如果您要走这条路,您可能应该考虑摇树,因为该插件可能比您需要的要多得多,而且您不希望所有这些额外的 js 拖慢您的速度。跨度> 是的,当然,谢天谢地,当您滚动浏览页面的其余部分时,我的设计中有很多动画元素,因此非常适合我的需要。我最初使用的是scrollmagic,但已经将其替换为支持此功能,否则如果它是一次性的,我会按照您所说的那样使用精简版。

以上是关于图像序列在它出现之前开始动画的主要内容,如果未能解决你的问题,请参考以下文章

简析拓扑排序

FireStoreRecyclerAdapter 只在它之前出现的东西之后显示结果?

PPT幻灯片中图表动画播放效果为:出现、按序列怎么设置?

Spotify API,预加载封面艺术

对于动画出现抖动的样子! 我们应该怎么解决呢!!!

为啥在屏幕上绘制图像之前不会出现内存不足的问题?