diff --git a/Studio_Image/커튼 걷은 360 이미지.webp b/Studio_Image/커튼 걷은 360 이미지.webp new file mode 100644 index 0000000..098ba29 Binary files /dev/null and b/Studio_Image/커튼 걷은 360 이미지.webp differ diff --git a/Studio_Image/커튼친 360 이미지.webp b/Studio_Image/커튼친 360 이미지.webp new file mode 100644 index 0000000..989cb88 Binary files /dev/null and b/Studio_Image/커튼친 360 이미지.webp differ diff --git a/css/gallery.css b/css/gallery.css index 23a1f6a..8521742 100644 --- a/css/gallery.css +++ b/css/gallery.css @@ -234,6 +234,291 @@ 100% { transform: rotate(360deg); } } +/* 360도 이미지 뷰어 스타일 */ +.panorama-section { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + padding: var(--spacing-3xl) 0; + margin: var(--spacing-3xl) 0; + border-radius: var(--border-radius); +} + +.panorama-section h2 { + text-align: center; + font-size: var(--font-4xl); + margin-bottom: var(--spacing-md); + color: var(--text-dark); +} + +.panorama-section .section-subtitle { + text-align: center; + font-size: var(--font-lg); + color: var(--text-light); + margin-bottom: var(--spacing-2xl); +} + +.panorama-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); + gap: var(--spacing-xl); + margin-top: var(--spacing-2xl); +} + +.panorama-viewer { + position: relative; + background: var(--bg-white); + border-radius: var(--border-radius); + overflow: hidden; + box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12); + transition: var(--transition); + cursor: grab; +} + +.panorama-viewer:hover { + transform: translateY(-5px); + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.18); +} + +.panorama-viewer:active { + cursor: grabbing; +} + +.panorama-clickable { + cursor: pointer; +} + +.panorama-clickable:hover { + transform: scale(1.02); +} + +.panorama-clickable:hover .panorama-help { + opacity: 1; + transform: scale(1.1); +} + +.panorama-container { + position: relative; + width: 100%; + height: 300px; + overflow: hidden; +} + +.panorama-preview { + width: 100%; + height: 100%; + background-size: cover; + background-position: center; + background-repeat: no-repeat; + position: relative; +} + +.panorama-controls { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: linear-gradient(transparent, rgba(0, 0, 0, 0.8)); + padding: var(--spacing-lg); + display: flex; + justify-content: space-between; + align-items: center; +} + +.panorama-title { + color: var(--text-white); + font-weight: 600; + font-size: var(--font-base); +} + +.panorama-buttons { + display: flex; + gap: var(--spacing-sm); +} + +.panorama-btn { + background: rgba(255, 255, 255, 0.2); + border: 1px solid rgba(255, 255, 255, 0.3); + color: var(--text-white); + padding: var(--spacing-xs) var(--spacing-sm); + border-radius: var(--border-radius-sm); + cursor: pointer; + font-size: var(--font-sm); + transition: var(--transition); + backdrop-filter: blur(10px); +} + +.panorama-btn:hover { + background: var(--primary-color); + border-color: var(--primary-color); + transform: translateY(-2px); +} + +.panorama-btn.active { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.panorama-indicator { + position: absolute; + top: var(--spacing-md); + right: var(--spacing-md); + background: rgba(0, 0, 0, 0.7); + color: var(--text-white); + padding: var(--spacing-xs) var(--spacing-sm); + border-radius: var(--border-radius-full); + font-size: var(--font-xs); + font-weight: 500; +} + +.panorama-help { + position: absolute; + top: var(--spacing-md); + left: var(--spacing-md); + background: rgba(255, 136, 0, 0.9); + color: var(--text-white); + padding: var(--spacing-xs) var(--spacing-sm); + border-radius: var(--border-radius-sm); + font-size: var(--font-xs); + animation: fadeInOut 3s ease-in-out; +} + +@keyframes fadeInOut { + 0%, 100% { opacity: 0; } + 20%, 80% { opacity: 1; } +} + +/* Pannellum 360도 이미지 전체화면 모달 */ +.panorama-modal { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.95); + z-index: 2000; +} + +.panorama-modal.active { + display: block; +} + +.panorama-modal-content { + position: relative; + width: 100vw; + height: 100vh; +} + +.panorama-modal-viewer { + width: 100%; + height: 100%; +} + +.panorama-modal-controls { + position: absolute; + bottom: 0; + left: 0; + right: 0; + background: linear-gradient(transparent, rgba(0, 0, 0, 0.9)); + padding: var(--spacing-xl); + display: flex; + justify-content: space-between; + align-items: center; +} + +.panorama-modal-title { + color: var(--text-white); + font-weight: 600; + font-size: var(--font-xl); +} + +.panorama-modal-buttons { + display: flex; + gap: var(--spacing-md); +} + +.panorama-modal-btn { + background: rgba(255, 255, 255, 0.2); + border: 1px solid rgba(255, 255, 255, 0.3); + color: var(--text-white); + padding: var(--spacing-sm) var(--spacing-lg); + border-radius: var(--border-radius); + cursor: pointer; + font-size: var(--font-base); + transition: var(--transition); + backdrop-filter: blur(10px); + font-weight: 500; +} + +.panorama-modal-btn:hover { + background: var(--primary-color); + border-color: var(--primary-color); + transform: translateY(-2px); +} + +.panorama-modal-btn.active { + background: var(--primary-color); + border-color: var(--primary-color); +} + +.panorama-modal-close { + position: absolute; + top: var(--spacing-lg); + right: var(--spacing-lg); + background: rgba(0, 0, 0, 0.7); + color: var(--text-white); + width: 50px; + height: 50px; + border-radius: 50%; + border: 2px solid rgba(255, 255, 255, 0.3); + cursor: pointer; + display: flex; + align-items: center; + justify-content: center; + font-size: var(--font-xl); + transition: var(--transition); + backdrop-filter: blur(10px); +} + +.panorama-modal-close:hover { + background: var(--primary-color); + border-color: var(--primary-color); + transform: scale(1.1); +} + +.panorama-modal-close::before { + content: '✕'; + font-weight: bold; +} + +.panorama-modal-help { + position: absolute; + top: var(--spacing-lg); + left: var(--spacing-lg); + background: rgba(255, 136, 0, 0.9); + color: var(--text-white); + padding: var(--spacing-sm) var(--spacing-lg); + border-radius: var(--border-radius); + font-size: var(--font-base); + font-weight: 500; + animation: fadeInOut 4s ease-in-out; + backdrop-filter: blur(10px); +} + +.panorama-modal-indicator { + position: absolute; + top: var(--spacing-lg); + left: 50%; + transform: translateX(-50%); + background: rgba(0, 0, 0, 0.7); + color: var(--text-white); + padding: var(--spacing-sm) var(--spacing-lg); + border-radius: var(--border-radius-full); + font-size: var(--font-base); + font-weight: 600; + border: 2px solid rgba(255, 255, 255, 0.3); + backdrop-filter: blur(10px); +} + /* 반응형 디자인 */ @media (max-width: 768px) { .page-header h1 { @@ -322,4 +607,60 @@ font-size: var(--font-xs); padding: var(--spacing-xs) var(--spacing-md); } + + .panorama-grid { + grid-template-columns: 1fr; + gap: var(--spacing-lg); + } + + .panorama-container { + height: 250px; + } + + .panorama-controls { + padding: var(--spacing-md); + } + + .panorama-title { + font-size: var(--font-sm); + } + + .panorama-btn { + font-size: var(--font-xs); + padding: var(--spacing-xs); + } + + .panorama-modal-content { + width: 95vw; + height: 60vh; + } + + .panorama-modal-controls { + padding: var(--spacing-lg); + } + + .panorama-modal-title { + font-size: var(--font-base); + } + + .panorama-modal-btn { + font-size: var(--font-sm); + padding: var(--spacing-xs) var(--spacing-md); + } + + .panorama-modal-close { + width: 40px; + height: 40px; + font-size: var(--font-base); + } + + .panorama-modal-help { + font-size: var(--font-sm); + padding: var(--spacing-xs) var(--spacing-md); + } + + .panorama-modal-indicator { + font-size: var(--font-sm); + padding: var(--spacing-xs) var(--spacing-md); + } } \ No newline at end of file diff --git a/gallery.html b/gallery.html index 906227a..cd25683 100644 --- a/gallery.html +++ b/gallery.html @@ -39,6 +39,10 @@ + + + + @@ -117,8 +121,45 @@ + +
+
+

360° Studio View

+

드래그하여 스튜디오를 360도로 둘러보세요

+ +
+
+
+
+
클릭하여 360도로 보기
+
360° VR
+
+
+
스튜디오 전경 (커튼 열림)
+
+
+ +
+
+
+
클릭하여 360도로 보기
+
360° VR
+
+
+
스튜디오 전경 (커튼 닫힘)
+
+
+
+
+
+ + \ No newline at end of file diff --git a/js/gallery.js b/js/gallery.js index 930d3fb..9e2993c 100644 --- a/js/gallery.js +++ b/js/gallery.js @@ -6,6 +6,7 @@ document.addEventListener('DOMContentLoaded', function() { initGallery(); initLightbox(); initGalleryAnimations(); + initPannellumViewers(); }); // 갤러리 초기화 @@ -263,4 +264,202 @@ function handleSwipe() { previousImage(); // 오른쪽으로 스와이프 = 이전 이미지 } } +} + +// ======================================== +// Pannellum 기반 360도 이미지 뷰어 기능 +// ======================================== + +let currentPanoramaViewer = null; + +function initPannellumViewers() { + // 모달 생성 + createPannellumModal(); + + // 미리보기 이미지 설정 + initPanoramaPreviews(); +} + +function initPanoramaPreviews() { + const containers = document.querySelectorAll('.panorama-clickable'); + + containers.forEach(container => { + const preview = container.querySelector('.panorama-preview'); + const imageSrc = container.dataset.image; + const title = container.dataset.title; + + // 미리보기 이미지 설정 + preview.style.backgroundImage = `url('${imageSrc}')`; + + // 클릭 이벤트 - 전체화면 Pannellum 뷰어 열기 + container.addEventListener('click', () => { + openPannellumModal(imageSrc, title); + }); + + // 도움말 자동 숨김 + setTimeout(() => { + const help = container.querySelector('.panorama-help'); + if (help) { + help.style.opacity = '0'; + setTimeout(() => help.remove(), 1000); + } + }, 4000); + }); +} + +function createPannellumModal() { + const modalHTML = ` +
+
+
+
+
+
+ + + +
+
+ +
+
+ `; + + document.body.insertAdjacentHTML('beforeend', modalHTML); + + // 모달 이벤트 리스너 설정 + setupPannellumModalListeners(); +} + +function setupPannellumModalListeners() { + const modal = document.getElementById('pannellum-modal'); + const closeBtn = document.getElementById('pannellum-modal-close'); + const resetBtn = document.getElementById('pannellum-reset-btn'); + const autoBtn = document.getElementById('pannellum-auto-btn'); + const fullscreenBtn = document.getElementById('pannellum-fullscreen-btn'); + + let isAutoRotating = false; + + // 모달 닫기 이벤트 + closeBtn.addEventListener('click', closePannellumModal); + + // ESC 키로 모달 닫기 + document.addEventListener('keydown', (e) => { + if (e.key === 'Escape' && modal.classList.contains('active')) { + closePannellumModal(); + } + }); + + // 리셋 버튼 + resetBtn.addEventListener('click', () => { + if (currentPanoramaViewer) { + currentPanoramaViewer.setPitch(0); + currentPanoramaViewer.setYaw(0); + stopAutoRotate(); + } + }); + + // 자동 회전 버튼 + autoBtn.addEventListener('click', () => { + if (isAutoRotating) { + stopAutoRotate(); + } else { + startAutoRotate(); + } + }); + + // 전체화면 버튼 + fullscreenBtn.addEventListener('click', () => { + if (currentPanoramaViewer) { + currentPanoramaViewer.toggleFullscreen(); + } + }); + + function startAutoRotate() { + if (currentPanoramaViewer) { + currentPanoramaViewer.startAutoRotate(0.5); // 초당 0.5도 회전 + isAutoRotating = true; + autoBtn.innerHTML = ' 정지'; + autoBtn.classList.add('active'); + } + } + + function stopAutoRotate() { + if (currentPanoramaViewer) { + currentPanoramaViewer.stopAutoRotate(); + isAutoRotating = false; + autoBtn.innerHTML = ' 자동회전'; + autoBtn.classList.remove('active'); + } + } +} + +function openPannellumModal(imageSrc, title) { + const modal = document.getElementById('pannellum-modal'); + const modalTitle = document.getElementById('pannellum-modal-title'); + + modalTitle.textContent = title; + modal.classList.add('active'); + document.body.style.overflow = 'hidden'; + + // Pannellum 뷰어 초기화 + currentPanoramaViewer = pannellum.viewer('pannellum-viewer', { + type: 'equirectangular', + panorama: imageSrc, + autoLoad: true, + autoRotate: 0, + compass: true, + northOffset: 0, + preview: imageSrc, + hfov: 100, + minHfov: 50, + maxHfov: 120, + pitch: 0, + yaw: 0, + mouseZoom: true, + keyboardZoom: true, + draggable: true, + disableKeyboardCtrl: false, + showControls: false, + showFullscreenCtrl: false, + showZoomCtrl: false, + hotSpotDebug: false, + backgroundColor: [0, 0, 0], + orientationOnByDefault: false + }); + + // 뷰어 로드 완료 이벤트 + currentPanoramaViewer.on('load', function() { + console.log('Pannellum 360도 뷰어 로드 완료'); + }); +} + +function closePannellumModal() { + const modal = document.getElementById('pannellum-modal'); + const autoBtn = document.getElementById('pannellum-auto-btn'); + + // 자동 회전 정지 + if (autoBtn.classList.contains('active')) { + autoBtn.click(); + } + + // 뷰어 정리 + if (currentPanoramaViewer) { + currentPanoramaViewer.destroy(); + currentPanoramaViewer = null; + } + + modal.classList.remove('active'); + document.body.style.overflow = ''; + + // 뷰어 컨테이너 초기화 + document.getElementById('pannellum-viewer').innerHTML = ''; } \ No newline at end of file