You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
148 lines
3.8 KiB
148 lines
3.8 KiB
import { useEffect, useRef } from "react"; |
|
import { gsap } from "gsap"; |
|
import { ScrollTrigger } from "gsap/ScrollTrigger"; |
|
import uamImg from "../../../public/images/uam-silver.png"; |
|
gsap.registerPlugin(ScrollTrigger); |
|
|
|
function MainAirspaceTransition() { |
|
const sectionRef = useRef(null); |
|
const leftRef = useRef(null); |
|
const rightRef = useRef(null); |
|
const lineRef = useRef([]); |
|
const dotRef = useRef(null); |
|
const uamImageRef = useRef(null); // ← 추가 |
|
const isMobile = window.innerWidth <= 768; |
|
|
|
useEffect(() => { |
|
const ctx = gsap.context(() => { |
|
gsap.set(rightRef.current, { xPercent: 100 }); |
|
gsap.set(lineRef.current, { scaleX: 0, transformOrigin: "left center" }); |
|
gsap.set(dotRef.current, { x: -320, opacity: 0, scale: 1 }); |
|
gsap.set(".airspace-uam-content", { opacity: 0, y: 36 }); |
|
gsap.set(uamImageRef.current, { opacity: 0 }); // ← 추가 |
|
// dot 초기 x 이동거리 |
|
gsap.set(dotRef.current, { |
|
x: isMobile ? -160 : -320, |
|
opacity: 0, |
|
scale: 1, |
|
}); |
|
const tl = gsap.timeline({ |
|
scrollTrigger: { |
|
trigger: sectionRef.current, |
|
start: "top top", |
|
end: "+=2100", |
|
scrub: 1, |
|
pin: true, |
|
anticipatePin: 1, |
|
}, |
|
}); |
|
|
|
tl.to(lineRef.current, { |
|
scaleX: 1, |
|
stagger: 0.08, |
|
duration: 0.7, |
|
ease: "none", |
|
}); |
|
|
|
tl.to( |
|
dotRef.current, |
|
{ |
|
x: 0, |
|
opacity: 1, |
|
duration: 0.7, |
|
ease: "none", |
|
}, |
|
"<0.1", |
|
); |
|
|
|
tl.to(leftRef.current, { |
|
xPercent: -100, |
|
duration: 1, |
|
ease: "none", |
|
}); |
|
|
|
tl.to( |
|
rightRef.current, |
|
{ |
|
xPercent: 0, |
|
duration: 1, |
|
ease: "none", |
|
}, |
|
"<", |
|
); |
|
|
|
tl.call(() => { |
|
dotRef.current?.classList.add("is-zooming"); |
|
}); |
|
|
|
tl.to(dotRef.current, { |
|
x: 0, |
|
y: 0, |
|
scale: isMobile ? 42 : 52, |
|
duration: 1.2, |
|
ease: "power2.inOut", |
|
}); |
|
// airspace-uam-content + UAM 이미지 동시 등장 ← 수정 |
|
tl.to( |
|
[".airspace-uam-content", uamImageRef.current], |
|
{ |
|
opacity: 1, |
|
y: 0, |
|
duration: 0.8, |
|
ease: "power2.out", |
|
}, |
|
"-=0.35", |
|
); |
|
}, sectionRef); |
|
|
|
return () => ctx.revert(); |
|
}, []); |
|
|
|
return ( |
|
<section className="airspace-transition-section" ref={sectionRef}> |
|
<div className="airspace-panel airspace-panel--utm" ref={leftRef}> |
|
<p>UTM SYSTEM</p> |
|
<h2>드론 하늘길에서</h2> |
|
</div> |
|
|
|
<div className="airspace-panel airspace-panel--uam" ref={rightRef}> |
|
<p>UAM SYSTEM</p> |
|
<h2> |
|
도심 항공 |
|
<span className="airspace-mobile-br"> </span> |
|
네트워크로 |
|
</h2> |
|
</div> |
|
|
|
<div className="airspace-lines"> |
|
{[0, 1, 2, 3].map((item) => ( |
|
<span |
|
key={item} |
|
className={`airspace-line airspace-line--${item + 1}`} |
|
ref={(el) => { |
|
lineRef.current[item] = el; |
|
}} |
|
/> |
|
))} |
|
</div> |
|
|
|
{/* 동그라미 + UAM 이미지 */} |
|
<div className="airspace-moving-dot" ref={dotRef}> |
|
<div className="airspace-dot-image" ref={uamImageRef}> |
|
<img src={uamImg} alt="UAM Aircraft" /> |
|
</div> |
|
</div> |
|
|
|
<div className="airspace-uam-content"> |
|
<p>UAM NETWORK</p> |
|
<h2>Urban Air Mobility</h2> |
|
<span> |
|
도심 내 버티포트, 운항 경로, 항공 교통 데이터를 <br /> |
|
하나의 네트워크로 연결해 미래형 항공 이동 환경을 구축합니다. |
|
</span> |
|
</div> |
|
</section> |
|
); |
|
} |
|
|
|
export default MainAirspaceTransition;
|
|
|