162 lines
4.4 KiB
JavaScript
162 lines
4.4 KiB
JavaScript
/**
|
|
* intro-events.js
|
|
* 이벤트 리스너 설정
|
|
*/
|
|
|
|
/**
|
|
* 모든 이벤트 리스너 등록
|
|
*/
|
|
function initEventListeners() {
|
|
// 마우스 휠 이벤트
|
|
document.addEventListener("wheel", (e) => {
|
|
resetAutoScrollTimer();
|
|
if (e.deltaY > 0) handleScrollDown();
|
|
else handleScrollUp();
|
|
});
|
|
|
|
// 터치 이벤트
|
|
let touchStartY = 0;
|
|
document.addEventListener(
|
|
"touchstart",
|
|
(e) => {
|
|
touchStartY = e.touches[0].clientY;
|
|
resetAutoScrollTimer();
|
|
},
|
|
{ passive: true }
|
|
);
|
|
|
|
document.addEventListener(
|
|
"touchend",
|
|
(e) => {
|
|
const diff = touchStartY - e.changedTouches[0].clientY;
|
|
if (Math.abs(diff) > 60) {
|
|
if (diff > 0) handleScrollDown();
|
|
else handleScrollUp();
|
|
}
|
|
},
|
|
{ passive: true }
|
|
);
|
|
|
|
// 키보드 이벤트
|
|
document.addEventListener("keydown", (e) => {
|
|
if (["ArrowDown", "PageDown", " "].includes(e.key)) {
|
|
e.preventDefault();
|
|
resetAutoScrollTimer();
|
|
handleScrollDown();
|
|
} else if (["ArrowUp", "PageUp"].includes(e.key)) {
|
|
e.preventDefault();
|
|
resetAutoScrollTimer();
|
|
handleScrollUp();
|
|
}
|
|
});
|
|
|
|
// 마우스 움직임 이벤트 (Section 3 마스크 효과)
|
|
// requestAnimationFrame을 사용하여 부드러운 업데이트 보장
|
|
let rafId = null;
|
|
let lastMouseEvent = null;
|
|
|
|
document.addEventListener("mousemove", (e) => {
|
|
if (typeof INTRO_STATE !== 'undefined' && INTRO_STATE.currentSection === 2) {
|
|
// 마지막 마우스 이벤트 저장
|
|
lastMouseEvent = e;
|
|
|
|
// 이미 요청된 애니메이션 프레임이 없으면 새로 요청
|
|
if (rafId === null) {
|
|
rafId = requestAnimationFrame(() => {
|
|
if (lastMouseEvent) {
|
|
handleMouseMoveOnSection3(lastMouseEvent);
|
|
}
|
|
rafId = null;
|
|
lastMouseEvent = null;
|
|
});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Section 3의 마우스 움직임 처리 (마스크 효과)
|
|
* @param {MouseEvent} e - 마우스 이벤트
|
|
*/
|
|
function handleMouseMoveOnSection3(e) {
|
|
try {
|
|
// 입력 검증
|
|
if (!e || typeof e.clientX !== 'number' || typeof e.clientY !== 'number') {
|
|
return;
|
|
}
|
|
|
|
const maskContainer = document.getElementById("maskContainer");
|
|
if (!maskContainer) {
|
|
return; // 요소가 없으면 조용히 종료
|
|
}
|
|
|
|
const mouseX = e.clientX;
|
|
const mouseY = e.clientY;
|
|
|
|
const mainContainer = document.getElementById("mainContainer");
|
|
if (!mainContainer) {
|
|
return;
|
|
}
|
|
|
|
const mainContainerRect = mainContainer.getBoundingClientRect();
|
|
const h1Elements = mainContainer.querySelectorAll("p");
|
|
const ctaBtn = document.querySelector(".cta-btn");
|
|
let hovering = false;
|
|
let isCtaBtnHovering = false;
|
|
|
|
// .cta-btn 위에 마우스가 있는지 먼저 체크
|
|
if (ctaBtn) {
|
|
try {
|
|
const ctaRect = ctaBtn.getBoundingClientRect();
|
|
if (
|
|
mouseX >= ctaRect.left &&
|
|
mouseX <= ctaRect.right &&
|
|
mouseY >= ctaRect.top &&
|
|
mouseY <= ctaRect.bottom
|
|
) {
|
|
hovering = true;
|
|
isCtaBtnHovering = true;
|
|
}
|
|
} catch (error) {
|
|
console.warn('[IntroEvents] CTA 버튼 체크 중 오류:', error);
|
|
}
|
|
}
|
|
|
|
// p 요소들 체크
|
|
try {
|
|
h1Elements.forEach((element) => {
|
|
try {
|
|
const h1Rect = element.getBoundingClientRect();
|
|
if (
|
|
mouseX >= h1Rect.left &&
|
|
mouseX <= h1Rect.right &&
|
|
mouseY >= h1Rect.top &&
|
|
mouseY <= h1Rect.bottom
|
|
) {
|
|
hovering = true;
|
|
}
|
|
} catch (error) {
|
|
// 개별 요소 체크 실패는 무시
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.warn('[IntroEvents] 요소 체크 중 오류:', error);
|
|
}
|
|
|
|
// .cta-btn 위에 있을 때만 세로 위치 고정, 그 외에는 마우스 위치 따라감
|
|
const targetY = isCtaBtnHovering
|
|
? mainContainerRect.top + mainContainerRect.height / 2.3
|
|
: mouseY;
|
|
|
|
// CSS 변수 설정 (안전하게)
|
|
const x = Math.max(0, Math.min(mouseX, window.innerWidth));
|
|
const y = Math.max(0, Math.min(targetY, window.innerHeight));
|
|
const targetSize = hovering ? 380 : 30;
|
|
|
|
maskContainer.style.setProperty("--x", `${x}px`);
|
|
maskContainer.style.setProperty("--y", `${y}px`);
|
|
maskContainer.style.setProperty("--size", `${targetSize}px`);
|
|
} catch (error) {
|
|
console.error('[IntroEvents] handleMouseMoveOnSection3 오류:', error);
|
|
}
|
|
} |