// ======================================== // 메인 페이지 전용 JavaScript // ======================================== document.addEventListener('DOMContentLoaded', function() { initMainPageAnimations(); initCounterAnimation(); initVideoTabs(); initVideoLazyLoading(); }); // ======================================== // 메인 페이지 애니메이션 // ======================================== function initMainPageAnimations() { // Hero 섹션 애니메이션 const heroElements = document.querySelectorAll('.hero-title, .hero-description, .hero-buttons'); heroElements.forEach((el, index) => { el.style.opacity = '0'; el.style.transform = 'translateY(30px)'; setTimeout(() => { el.style.transition = 'all 0.8s ease'; el.style.opacity = '1'; el.style.transform = 'translateY(0)'; }, 100 * (index + 1)); }); // Feature 카드 애니메이션 const observerOptions = { threshold: 0.2, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { setTimeout(() => { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; }, index * 100); observer.unobserve(entry.target); } }); }, observerOptions); // Feature 카드 초기 상태 설정 및 관찰 document.querySelectorAll('.feature-card').forEach(card => { card.style.opacity = '0'; card.style.transform = 'translateY(30px)'; card.style.transition = 'all 0.6s ease'; observer.observe(card); }); // Service 아이템 애니메이션 document.querySelectorAll('.service-item').forEach(item => { item.style.opacity = '0'; item.style.transform = 'translateX(-30px)'; item.style.transition = 'all 0.6s ease'; observer.observe(item); }); } // ======================================== // 카운터 애니메이션 (선택적) // ======================================== function initCounterAnimation() { const counters = document.querySelectorAll('.counter'); if (counters.length === 0) return; const animateCounter = (counter) => { const target = parseInt(counter.getAttribute('data-target')); const duration = 2000; // 2초 const increment = target / (duration / 16); // 60fps 기준 let current = 0; const updateCounter = () => { current += increment; if (current < target) { counter.textContent = Math.floor(current); requestAnimationFrame(updateCounter); } else { counter.textContent = target; } }; updateCounter(); }; const counterObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateCounter(entry.target); counterObserver.unobserve(entry.target); } }); }, { threshold: 0.5 }); counters.forEach(counter => { counterObserver.observe(counter); }); } // ======================================== // 패럴랙스 효과 (선택적) // ======================================== window.addEventListener('scroll', () => { const scrolled = window.pageYOffset; const parallaxElements = document.querySelectorAll('.parallax'); parallaxElements.forEach(el => { const speed = el.getAttribute('data-speed') || 0.5; el.style.transform = `translateY(${scrolled * speed}px)`; }); }); // ======================================== // 비디오 탭 시스템 // ======================================== function initVideoTabs() { const tabButtons = document.querySelectorAll('.video-tab-btn'); const tabContents = document.querySelectorAll('.video-tab-content'); if (tabButtons.length === 0) return; // 탭이 없으면 종료 // 탭 버튼 클릭 이벤트 tabButtons.forEach(button => { button.addEventListener('click', () => { const targetTab = button.getAttribute('data-tab'); // 모든 탭 버튼에서 active 클래스 제거 tabButtons.forEach(btn => btn.classList.remove('active')); // 클릭된 탭 버튼에 active 클래스 추가 button.classList.add('active'); // 모든 탭 콘텐츠 숨기기 tabContents.forEach(content => { content.classList.remove('active'); }); // 선택된 탭 콘텐츠 표시 const activeContent = document.getElementById(targetTab); if (activeContent) { activeContent.classList.add('active'); // 탭 전환 애니메이션 activeContent.style.opacity = '0'; activeContent.style.transform = 'translateY(20px)'; setTimeout(() => { activeContent.style.transition = 'all 0.3s ease'; activeContent.style.opacity = '1'; activeContent.style.transform = 'translateY(0)'; }, 50); } }); // 키보드 접근성 button.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); button.click(); } }); }); // 파트너 로고 애니메이션 const partnerItems = document.querySelectorAll('.partner-logo-item'); if (partnerItems.length > 0) { const partnerObserver = new IntersectionObserver((entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { setTimeout(() => { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; }, index * 100); partnerObserver.unobserve(entry.target); } }); }, { threshold: 0.1 }); partnerItems.forEach(item => { item.style.opacity = '0'; item.style.transform = 'translateY(30px)'; item.style.transition = 'all 0.6s ease'; partnerObserver.observe(item); }); } // 비디오 아이템 애니메이션 const videoItems = document.querySelectorAll('.live-video-item, .shorts-video-item'); if (videoItems.length > 0) { const videoObserver = new IntersectionObserver((entries) => { entries.forEach((entry, index) => { if (entry.isIntersecting) { setTimeout(() => { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; }, index * 150); videoObserver.unobserve(entry.target); } }); }, { threshold: 0.1 }); videoItems.forEach(item => { item.style.opacity = '0'; item.style.transform = 'translateY(30px)'; item.style.transition = 'all 0.6s ease'; videoObserver.observe(item); }); } } // ======================================== // 비디오 레이지 로딩 // ======================================== function initVideoLazyLoading() { const videoWrappers = document.querySelectorAll('.video-wrapper'); // Intersection Observer를 사용한 레이지 로딩 const observerOptions = { threshold: 0.1, rootMargin: '50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { loadVideo(entry.target); observer.unobserve(entry.target); } }); }, observerOptions); videoWrappers.forEach(wrapper => { observer.observe(wrapper); // 로딩 상태 표시 if (!wrapper.querySelector('.video-loading')) { const loadingDiv = document.createElement('div'); loadingDiv.className = 'video-loading'; loadingDiv.textContent = '비디오 로딩 중...'; loadingDiv.style.cssText = ` position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: var(--text-secondary); font-size: var(--font-sm); z-index: 10; `; wrapper.appendChild(loadingDiv); } }); } // 비디오 로딩 function loadVideo(wrapper) { const iframe = wrapper.querySelector('iframe'); if (iframe && iframe.dataset.src) { // 실제 src 설정 iframe.src = iframe.dataset.src; // 로딩 완료 처리 iframe.addEventListener('load', function() { wrapper.classList.add('loaded'); const loadingDiv = wrapper.querySelector('.video-loading'); if (loadingDiv) { loadingDiv.remove(); } }); // 에러 처리 iframe.addEventListener('error', function() { const loadingDiv = wrapper.querySelector('.video-loading'); if (loadingDiv) { loadingDiv.textContent = '비디오를 로드할 수 없습니다'; loadingDiv.style.color = '#ef4444'; } }); } else { // 이미 src가 설정된 경우 wrapper.classList.add('loaded'); const loadingDiv = wrapper.querySelector('.video-loading'); if (loadingDiv) { loadingDiv.remove(); } } } // ======================================== // 마우스 호버 효과 // ======================================== document.querySelectorAll('.feature-card, .service-item').forEach(card => { card.addEventListener('mouseenter', function(e) { const rect = this.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top; this.style.setProperty('--mouse-x', `${x}px`); this.style.setProperty('--mouse-y', `${y}px`); }); });