I'm using gsap (version 3.11.5) in reactjs project. Basically, I want to hide shapes when scroll to end of the first page. When scroll back to top, it will also tag along again (using scrub: true
). For now, it still appear even though it ends of first page.Is there any way to implmenet by using gsap scroll trigger?
import { useLayoutEffect, useRef } from "react";
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";
import "./App.css";
gsap.registerPlugin(ScrollTrigger);
function App() {
const app = useRef(null);
const tl = useRef();
function random(min, max) {
const delta = max - min;
return (direction = 1) => (min + delta * Math.random()) * direction;
}
const randomX = random(5, 10);
const randomY = random(5, 10);
const randomTime = random(3, 5);
const randomTime2 = random(5, 10);
const randomAngle = random(1, 1.5);
useLayoutEffect(() => {
let ctx = gsap.context(() => {
let proxy = { skew: 1 },
skewSetter = gsap.quickSetter(".shape", "skewY", "deg"),
clamp = gsap.utils.clamp(-200, 200);
// first page scroll skew animation
ScrollTrigger.create({
onUpdate: (self) => {
let skew = clamp(self.getVelocity() / 200);
if (Math.abs(skew) > Math.abs(proxy.skew)) {
proxy.skew = skew;
gsap.to(proxy, {
skew: 0,
duration: 0.8,
ease: "power3",
overwrite: true,
onUpdate: () => skewSetter(proxy.skew),
});
}
},
});
gsap.set(".shape", { transformOrigin: "right center", force3D: true });
function moveX(target, direction) {
gsap.to(target, randomTime(), {
x: randomX(direction),
ease: "Sine.easeInOut",
onComplete: moveX,
onCompleteParams: [target, direction * -1],
});
}
function moveY(target, direction) {
gsap.to(target, randomTime(), {
y: randomY(direction),
ease: "Sine.easeInOut",
onComplete: moveY,
onCompleteParams: [target, direction * -1],
});
}
function rotate(target, direction) {
gsap.to(target, randomTime2(), {
rotation: randomAngle(direction),
// delay: randomDelay(),
ease: "Sine.easeInOut",
onComplete: rotate,
onCompleteParams: [target, direction * -1],
});
}
gsap.utils.toArray(".shape").forEach((star) => {
moveX(star, 1);
moveY(star, -1);
rotate(star, -1);
});
// shapes fixed
tl.current = gsap.to(".shapes", {
scrollTrigger: {
trigger: ".first-page",
scrub: true,
markers: true,
pin: true,
start: "0%",
end: "100%",
onComplete:function() {
console.log('end')
}
},
});
// second page
// scale text when scroll
tl.current = gsap.timeline({
scrollTrigger: {
trigger: ".second-page",
start: "0%",
end: "200%",
scrub: true,
pin: true,
},
});
tl.current.fromTo(".text", { scale: 0.5 }, { scale: 1.2 });
}, app);
return () => ctx.revert();
}, []);
return (
<div ref={app}>
<nav>
<a href="#">Logo</a>
{/* <div className="hamburgers">Icon</div> */}
</nav>
<div className="shapes">
{[1, 2, 3, 4].map((index) => {
return (
<div
className={`shape item-${index}`}
data-test={index}
key={index}
></div>
);
})}
</div>
<section className="first-page">
</section>
<section className="second-page">
<h1 className="text">Second Page</h1>
</section>
<section className="third-page">
<h1 className="">Third Page</h1>
</section>
</div>
);
}
export default App;
App.css
nav {
position: fixed;
width: 100%;
padding: 0px 50px;
min-height: 8vh;
z-index: 10;
display: flex;
align-items: center;
justify-content: space-between;
}
.first-page {
min-height: 300vh;
background-color: white;
color: #000;
}
.second-page {
height: 100vh;
background-color: green;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.third-page {
height: 100vh;
background-color: yellow;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
.shapes {
position: fixed;
width: 100%;
height: 100vh;
z-index: 1;
}
.shape {
width: 100px;
height: 300px;
background-color: red;
/* background: rgb(9,9,121); */
/* background: linear-gradient(180deg, rgba(9,9,121,1) 2%, rgba(0,212,255,0.28895308123249297) 89%); */
}
.shape.item-1 {
position: absolute;
top: 0;
left: 0;
}
.shape.item-2 {
position: absolute;
top: 50px;
left: 40%;
}
.shape.item-3 {
position: absolute;
right: 50px;
bottom: 0;
}
.shape.item-4 {
position: absolute;
left: 0;
bottom: 0;
}