// ========================================
// Gallery 페이지 전용 JavaScript
// ========================================
document.addEventListener('DOMContentLoaded', function() {
initGallery();
initLightbox();
initGalleryAnimations();
initPhotoSphereViewers();
});
// 갤러리 초기화
function initGallery() {
const galleryItems = document.querySelectorAll('.gallery-item');
galleryItems.forEach((item, index) => {
const img = item.querySelector('.gallery-img');
// 이미지 클릭 시 라이트박스 열기
img.addEventListener('click', () => openLightbox(index));
// 이미지 로딩 에러 처리
img.addEventListener('error', function() {
this.src = 'images/placeholder.jpg';
this.alt = '이미지를 불러올 수 없습니다';
});
// 레이지 로딩 구현
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src || img.src;
img.classList.remove('lazy');
imageObserver.unobserve(img);
}
});
});
if (img.dataset.src) {
imageObserver.observe(img);
}
}
});
}
// 라이트박스 기능
let currentImageIndex = 0;
const galleryImages = document.querySelectorAll('.gallery-img');
function initLightbox() {
// 라이트박스 HTML 생성
const lightboxHTML = `
`;
document.body.insertAdjacentHTML('beforeend', lightboxHTML);
// ESC 키로 라이트박스 닫기
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeLightbox();
if (e.key === 'ArrowLeft') previousImage();
if (e.key === 'ArrowRight') nextImage();
});
// 배경 클릭으로 라이트박스 닫기
document.getElementById('lightbox').addEventListener('click', function(e) {
if (e.target === this) closeLightbox();
});
}
function openLightbox(index) {
currentImageIndex = index;
const lightbox = document.getElementById('lightbox');
const lightboxImg = document.getElementById('lightbox-img');
const lightboxCaption = document.getElementById('lightbox-caption');
const currentImg = galleryImages[index];
const caption = currentImg.closest('.gallery-item').querySelector('.gallery-caption');
lightboxImg.src = currentImg.src;
lightboxImg.alt = currentImg.alt;
lightboxCaption.textContent = caption ? caption.textContent : currentImg.alt;
lightbox.classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
const lightbox = document.getElementById('lightbox');
lightbox.classList.remove('active');
document.body.style.overflow = '';
}
function nextImage() {
currentImageIndex = (currentImageIndex + 1) % galleryImages.length;
openLightbox(currentImageIndex);
}
function previousImage() {
currentImageIndex = (currentImageIndex - 1 + galleryImages.length) % galleryImages.length;
openLightbox(currentImageIndex);
}
// 갤러리 애니메이션
function initGalleryAnimations() {
const galleryItems = document.querySelectorAll('.gallery-item');
// Intersection Observer를 사용한 애니메이션
const observerOptions = {
threshold: 0.1,
rootMargin: '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);
galleryItems.forEach(item => {
item.style.opacity = '0';
item.style.transform = 'translateY(30px)';
item.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
observer.observe(item);
});
}
// 갤러리 필터 기능 (향후 확장용)
function initGalleryFilters() {
const filterButtons = document.querySelectorAll('.filter-btn');
const galleryItems = document.querySelectorAll('.gallery-item');
filterButtons.forEach(btn => {
btn.addEventListener('click', function() {
// 활성 버튼 업데이트
filterButtons.forEach(b => b.classList.remove('active'));
this.classList.add('active');
const filter = this.dataset.filter;
galleryItems.forEach(item => {
if (filter === 'all' || item.dataset.category === filter) {
item.style.display = 'block';
setTimeout(() => {
item.style.opacity = '1';
item.style.transform = 'scale(1)';
}, 10);
} else {
item.style.opacity = '0';
item.style.transform = 'scale(0.8)';
setTimeout(() => {
item.style.display = 'none';
}, 300);
}
});
});
});
}
// 이미지 프리로딩
function preloadImages() {
galleryImages.forEach(img => {
const imagePreload = new Image();
imagePreload.src = img.src;
});
}
// 갤러리 검색 기능 (향후 확장용)
function initGallerySearch() {
const searchInput = document.getElementById('gallery-search');
const galleryItems = document.querySelectorAll('.gallery-item');
if (searchInput) {
searchInput.addEventListener('input', function() {
const searchTerm = this.value.toLowerCase();
galleryItems.forEach(item => {
const caption = item.querySelector('.gallery-caption');
const alt = item.querySelector('.gallery-img').alt;
const text = (caption ? caption.textContent : '') + ' ' + alt;
if (text.toLowerCase().includes(searchTerm)) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
});
}
}
// 이미지 로딩 상태 표시
function showGalleryLoading() {
const loading = document.querySelector('.gallery-loading');
if (loading) {
loading.style.display = 'block';
}
}
function hideGalleryLoading() {
const loading = document.querySelector('.gallery-loading');
if (loading) {
loading.style.display = 'none';
}
}
// 갤러리 그리드 리사이즈 최적화
let resizeTimeout;
window.addEventListener('resize', function() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(function() {
// 갤러리 그리드 재조정 로직
const galleryGrid = document.querySelector('.gallery-grid');
if (galleryGrid) {
galleryGrid.style.opacity = '0.8';
setTimeout(() => {
galleryGrid.style.opacity = '1';
}, 100);
}
}, 250);
});
// 터치 이벤트 지원 (모바일)
let touchStartX = 0;
let touchEndX = 0;
document.addEventListener('touchstart', function(e) {
if (document.getElementById('lightbox').classList.contains('active')) {
touchStartX = e.changedTouches[0].screenX;
}
});
document.addEventListener('touchend', function(e) {
if (document.getElementById('lightbox').classList.contains('active')) {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
}
});
function handleSwipe() {
const swipeThreshold = 50;
const diff = touchStartX - touchEndX;
if (Math.abs(diff) > swipeThreshold) {
if (diff > 0) {
nextImage(); // 왼쪽으로 스와이프 = 다음 이미지
} else {
previousImage(); // 오른쪽으로 스와이프 = 이전 이미지
}
}
}
// ========================================
// Photo Sphere Viewer - 진짜 360도 VR 뷰어
// ========================================
let currentPhotoSphereViewer = null;
function initPhotoSphereViewers() {
// 모달 생성
createPhotoSphereModal();
// 미리보기 설정
initPhotoSpherePreviews();
}
function initPhotoSpherePreviews() {
const containers = document.querySelectorAll('.panorama-clickable');
containers.forEach(container => {
const imageSrc = container.dataset.image;
const title = container.dataset.title;
// 클릭 이벤트
container.addEventListener('click', () => {
openPhotoSphereModal(imageSrc, title);
});
// 도움말 자동 숨김
setTimeout(() => {
const help = container.querySelector('.panorama-help');
if (help) {
help.style.opacity = '0';
setTimeout(() => help.remove(), 1000);
}
}, 4000);
});
}
function createPhotoSphereModal() {
const modalHTML = `
360° VR 조작법
🖱️ 드래그: 전방향 회전
📱 터치: 터치 후 드래그
🖱️ 휠: 줌 인/아웃
📱 핀치: 줌 인/아웃
⌨️ 화살표: 방향 이동
⌨️ +/-: 줌 조절
⌨️ ESC: 닫기
`;
document.body.insertAdjacentHTML('beforeend', modalHTML);
setupPhotoSphereModalListeners();
}
function setupPhotoSphereModalListeners() {
const modal = document.getElementById('photosphere-modal');
const closeBtn = document.getElementById('photosphere-modal-close');
const resetBtn = document.getElementById('photosphere-reset-btn');
const autoBtn = document.getElementById('photosphere-auto-btn');
const fullscreenBtn = document.getElementById('photosphere-fullscreen-btn');
const helpBtn = document.getElementById('photosphere-help-btn');
const helpText = document.getElementById('photosphere-help-text');
let isAutoRotating = false;
let helpVisible = false;
// 모달 닫기
closeBtn.addEventListener('click', closePhotoSphereModal);
modal.addEventListener('click', (e) => {
if (e.target === modal) closePhotoSphereModal();
});
// ESC 키
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modal.classList.contains('active')) {
closePhotoSphereModal();
}
});
// 리셋 버튼
resetBtn.addEventListener('click', () => {
if (currentPhotoSphereViewer) {
currentPhotoSphereViewer.animate({
yaw: 0,
pitch: 0,
zoom: 50,
speed: '2rpm'
});
}
});
// 자동 회전 버튼
autoBtn.addEventListener('click', () => {
if (currentPhotoSphereViewer) {
if (isAutoRotating) {
currentPhotoSphereViewer.stopAutorotate();
autoBtn.innerHTML = ' 자동회전';
autoBtn.classList.remove('active');
isAutoRotating = false;
} else {
currentPhotoSphereViewer.startAutorotate();
autoBtn.innerHTML = ' 정지';
autoBtn.classList.add('active');
isAutoRotating = true;
}
}
});
// 전체화면 버튼
fullscreenBtn.addEventListener('click', () => {
if (currentPhotoSphereViewer) {
currentPhotoSphereViewer.enterFullscreen();
}
});
// 도움말 버튼
helpBtn.addEventListener('click', () => {
helpVisible = !helpVisible;
helpText.style.display = helpVisible ? 'block' : 'none';
helpBtn.classList.toggle('active', helpVisible);
});
// 도움말 자동 숨김
setTimeout(() => {
helpText.style.display = 'none';
}, 6000);
}
function openPhotoSphereModal(imageSrc, title) {
const modal = document.getElementById('photosphere-modal');
const modalTitle = document.getElementById('photosphere-modal-title');
const viewerContainer = document.getElementById('photosphere-viewer');
modalTitle.textContent = title;
modal.classList.add('active');
document.body.style.overflow = 'hidden';
// Photo Sphere Viewer 생성
try {
currentPhotoSphereViewer = new PhotoSphereViewer.Viewer({
container: viewerContainer,
panorama: imageSrc,
caption: title,
loadingImg: imageSrc, // 로딩 중 미리보기
touchmoveTwoFingers: true,
mousewheelCtrlKey: false,
defaultYaw: 0,
defaultPitch: 0,
defaultZoomLvl: 50,
minFov: 30,
maxFov: 90,
autorotateDelay: null,
autorotateIdle: false,
autorotateSpeed: '2rpm',
fisheye: false,
navbar: [
'zoom',
'move',
'fullscreen',
{
title: '자동회전',
content: '🔄',
onClick: () => {
const autoBtn = document.getElementById('photosphere-auto-btn');
autoBtn.click();
}
}
]
});
// 이벤트 리스너
currentPhotoSphereViewer.addEventListener('ready', () => {
console.log('Photo Sphere Viewer 준비 완료');
});
currentPhotoSphereViewer.addEventListener('autorotate', () => {
console.log('자동 회전 시작');
});
currentPhotoSphereViewer.addEventListener('autorotate-stop', () => {
console.log('자동 회전 정지');
});
} catch (error) {
console.error('Photo Sphere Viewer 초기화 실패:', error);
alert('360도 뷰어를 로드할 수 없습니다. 페이지를 새로고침해주세요.');
}
}
function closePhotoSphereModal() {
const modal = document.getElementById('photosphere-modal');
const autoBtn = document.getElementById('photosphere-auto-btn');
// 뷰어 정리
if (currentPhotoSphereViewer) {
currentPhotoSphereViewer.destroy();
currentPhotoSphereViewer = null;
}
// 버튼 초기화
autoBtn.innerHTML = ' 자동회전';
autoBtn.classList.remove('active');
modal.classList.remove('active');
document.body.style.overflow = '';
// 컨테이너 정리
document.getElementById('photosphere-viewer').innerHTML = '';
}