Fix : 360 모바일 개선

This commit is contained in:
qsxft258@gmail.com 2025-09-17 22:45:06 +09:00
parent 95eaf73e30
commit ca88e829ad
2 changed files with 98 additions and 47 deletions

View File

@ -440,7 +440,6 @@
height: 100vh;
background: rgba(0, 0, 0, 0.95);
z-index: 2000;
backdrop-filter: blur(5px);
}
.panorama-modal.active {
@ -515,7 +514,6 @@
display: flex;
justify-content: space-between;
align-items: center;
backdrop-filter: blur(10px);
z-index: 10;
}
@ -549,7 +547,6 @@
font-size: 0.875rem;
font-weight: 500;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
min-width: 80px;
font-family: inherit;
}
@ -594,7 +591,6 @@
justify-content: center;
font-size: 20px;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
z-index: 100;
font-family: Arial, sans-serif;
}
@ -651,7 +647,6 @@
max-width: 500px;
width: 90%;
z-index: 200;
backdrop-filter: blur(20px);
border: 2px solid rgba(255, 255, 255, 0.2);
display: none;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8);
@ -696,10 +691,8 @@
/* 서버 호환성을 위한 추가 스타일 */
.panorama-modal {
/* 서버에서 배경 블러 지원 안될 때 대비 */
/* 깔끔한 배경 - 블러 효과 제거 */
background: rgba(0, 0, 0, 0.95) !important;
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
}
.panorama-viewer-container {
@ -728,45 +721,69 @@
padding: 3rem 0;
margin: 3rem 0;
}
.panorama-section h2 {
font-size: 2rem;
}
.panorama-grid {
grid-template-columns: 1fr;
gap: 1.5rem;
padding: 0 15px;
}
.panorama-container {
height: 250px;
}
/* 모바일 360도 뷰어 컨테이너 최적화 - 경계 문제 해결 */
.panorama-viewer-container {
/* GPU 가속 활성화로 부드러운 렌더링 */
transform: translateZ(0);
-webkit-transform: translateZ(0);
will-change: transform;
/* 터치 시 확대/축소 제어 */
touch-action: pan-x pinch-zoom;
-webkit-overflow-scrolling: touch;
/* 경계 부분 매끄럽게 처리 */
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
}
/* 모바일 줌 시 이미지 품질 개선 */
.panorama-viewer-container img {
/* 확대 시에도 선명한 이미지 유지 */
image-rendering: -webkit-optimize-contrast;
image-rendering: crisp-edges;
/* 경계 부분 부드럽게 처리 */
backface-visibility: hidden;
-webkit-backface-visibility: hidden;
}
.panorama-modal-close {
width: 44px;
height: 44px;
top: 20px;
right: 20px;
}
.panorama-modal-close .close-icon::before,
.panorama-modal-close .close-icon::after {
width: 16px;
}
.panorama-modal-controls {
padding: 1.5rem;
flex-direction: column;
gap: 1rem;
align-items: center;
}
.panorama-control-buttons {
gap: 1rem;
justify-content: center;
}
.panorama-btn {
min-width: 70px;
padding: 0.75rem 1rem;

View File

@ -375,25 +375,32 @@ class Easy360Viewer {
}
setupImageSize() {
// 이미지 자연 어숙비를 유지하면서 컨테이너 높이에 맞춤
// 컨테이너 크기 가져오기
const containerHeight = this.container.clientHeight;
const containerWidth = this.container.clientWidth;
const imageAspectRatio = this.image.naturalWidth / this.image.naturalHeight;
// 360도 이미지는 매우 가로가 기므로 컨테이너보다 훨씬 커야 함
let imageWidth = containerHeight * imageAspectRatio;
// 컨테이너보다 작으면 컨테이너 너비에 맞춤
if (imageWidth < containerWidth * 2) {
imageWidth = containerWidth * 3; // 360도를 위해 충분히 큼
// 모바일에서 줌 시 경계 문제 해결을 위한 더 정확한 크기 계산
let imageHeight = containerHeight * this.zoom;
let imageWidth = imageHeight * imageAspectRatio;
// 360도 이미지는 매우 가로가 길므로 최소 크기 보장
const minWidth = Math.max(containerWidth * 3, imageWidth);
imageWidth = minWidth;
imageHeight = imageWidth / imageAspectRatio;
// 줌 레벨에 따른 크기 조정 (모바일 확대 시 경계 문제 해결)
if (this.zoom > 1) {
imageHeight = Math.max(containerHeight, imageHeight);
imageWidth = imageHeight * imageAspectRatio;
}
// 이미지 크기 설정 - 브라우저 호환성 개선
// 이미지 크기 설정 - 픽셀 완벽 정렬로 경계 문제 방지
this.image.style.width = Math.round(imageWidth) + 'px';
this.image.style.height = Math.round(containerHeight) + 'px';
this.image.style.height = Math.round(imageHeight) + 'px';
this.imageWrapper.style.width = Math.round(imageWidth) + 'px';
this.imageWrapper.style.height = Math.round(containerHeight) + 'px';
// 단일 이미지 너비 저장
this.singleImageWidth = imageWidth;
}
@ -553,13 +560,17 @@ class Easy360Viewer {
updatePosition(currentX) {
const deltaX = currentX - this.lastX;
// 좌우 이동 (드래그 방향과 반대)
this.currentX -= deltaX;
// 속도 계산 (관성용)
this.velocity = -deltaX * 0.1;
// 속도 계산 (관성용) - 더 부드러운 관성 적용
this.velocity = -deltaX * 0.15;
// 극한 속도 제한 (튀는 현상 방지)
const maxVelocity = this.singleImageWidth * 0.05;
this.velocity = Math.max(-maxVelocity, Math.min(maxVelocity, this.velocity));
this.updateTransform();
this.lastX = currentX;
}
@ -583,32 +594,55 @@ class Easy360Viewer {
handleResize() {
if (this.image && this.image.complete) {
// 리사이즈 시 비율 유지
const oldRatio = this.currentX / this.singleImageWidth;
// 리사이즈 시 비율 유지하되, 튀는 현상 방지
const oldRatio = (this.currentX - this.singleImageWidth) / this.singleImageWidth;
const oldImageWidth = this.singleImageWidth;
this.setupImageSize();
this.createDuplicateImages(); // 이미지 다시 생성
this.currentX = this.singleImageWidth * oldRatio; // 비율 유지
// 정규화된 위치로 복원 (중앙 이미지 기준)
this.currentX = this.singleImageWidth + (this.singleImageWidth * oldRatio);
// 경계값 확인 및 보정
if (this.currentX < 0) this.currentX += this.singleImageWidth;
if (this.currentX > this.singleImageWidth * 2) this.currentX -= this.singleImageWidth;
this.updateTransform();
}
}
updateTransform() {
if (!this.imageWrapper || !this.singleImageWidth) return;
// 무한 스크롤 처리 - 더 부드럽게
if (this.currentX <= 0) {
this.currentX = this.singleImageWidth;
} else if (this.currentX >= this.singleImageWidth * 2) {
this.currentX = this.singleImageWidth;
// 무한 스크롤 처리 - 튀는 버그 방지를 위한 부드러운 전환
const threshold = this.singleImageWidth * 0.1; // 10% 여유 공간
// 왼쪽 경계 처리 - 부드러운 전환
if (this.currentX < -threshold) {
this.currentX = this.singleImageWidth + (this.currentX + threshold);
}
// 부드러운 변환을 위해 소수점 제거
// 오른쪽 경계 처리 - 부드러운 전환
else if (this.currentX > this.singleImageWidth * 2 + threshold) {
this.currentX = this.singleImageWidth + (this.currentX - this.singleImageWidth * 2 - threshold);
}
// 정확한 무한 루프 경계 처리 (튀는 현상 방지)
const normalizedX = ((this.currentX % this.singleImageWidth) + this.singleImageWidth) % this.singleImageWidth;
const actualX = normalizedX + this.singleImageWidth;
// 현재 위치와 목표 위치의 차이가 큰 경우만 보정 (부드러운 회전 유지)
if (Math.abs(this.currentX - actualX) > this.singleImageWidth * 0.5) {
this.currentX = actualX;
}
// 고정밀 변환 계산 (소수점 2자리까지 유지하여 부드러움 보장)
const translateX = Math.round(-this.currentX * 100) / 100;
const scale = Math.round(this.zoom * 100) / 100;
const scale = Math.round(this.zoom * 1000) / 1000;
const transform = `translateX(${translateX}px) scale(${scale})`;
this.imageWrapper.style.transform = transform;
// 브라우저 호환성
this.imageWrapper.style.webkitTransform = transform;
this.imageWrapper.style.msTransform = transform;