304 lines
10 KiB
JavaScript
304 lines
10 KiB
JavaScript
// ========================================
|
|
// 메인 페이지 전용 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`);
|
|
});
|
|
}); |