图像序列在进入视图之前开始动画
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);
}
我正在尝试复制苹果的图像排序动画 - 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);
}