Fix : 360 모바일 개선
This commit is contained in:
parent
95eaf73e30
commit
ca88e829ad
@ -440,7 +440,6 @@
|
|||||||
height: 100vh;
|
height: 100vh;
|
||||||
background: rgba(0, 0, 0, 0.95);
|
background: rgba(0, 0, 0, 0.95);
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-modal.active {
|
.panorama-modal.active {
|
||||||
@ -515,7 +514,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,7 +547,6 @@
|
|||||||
font-size: 0.875rem;
|
font-size: 0.875rem;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
min-width: 80px;
|
min-width: 80px;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
}
|
}
|
||||||
@ -594,7 +591,6 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
backdrop-filter: blur(10px);
|
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
font-family: Arial, sans-serif;
|
font-family: Arial, sans-serif;
|
||||||
}
|
}
|
||||||
@ -651,7 +647,6 @@
|
|||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
width: 90%;
|
width: 90%;
|
||||||
z-index: 200;
|
z-index: 200;
|
||||||
backdrop-filter: blur(20px);
|
|
||||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||||
display: none;
|
display: none;
|
||||||
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8);
|
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.8);
|
||||||
@ -696,10 +691,8 @@
|
|||||||
|
|
||||||
/* 서버 호환성을 위한 추가 스타일 */
|
/* 서버 호환성을 위한 추가 스타일 */
|
||||||
.panorama-modal {
|
.panorama-modal {
|
||||||
/* 서버에서 배경 블러 지원 안될 때 대비 */
|
/* 깔끔한 배경 - 블러 효과 제거 */
|
||||||
background: rgba(0, 0, 0, 0.95) !important;
|
background: rgba(0, 0, 0, 0.95) !important;
|
||||||
backdrop-filter: blur(5px);
|
|
||||||
-webkit-backdrop-filter: blur(5px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-viewer-container {
|
.panorama-viewer-container {
|
||||||
@ -728,45 +721,69 @@
|
|||||||
padding: 3rem 0;
|
padding: 3rem 0;
|
||||||
margin: 3rem 0;
|
margin: 3rem 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-section h2 {
|
.panorama-section h2 {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-grid {
|
.panorama-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-container {
|
.panorama-container {
|
||||||
height: 250px;
|
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 {
|
.panorama-modal-close {
|
||||||
width: 44px;
|
width: 44px;
|
||||||
height: 44px;
|
height: 44px;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
right: 20px;
|
right: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-modal-close .close-icon::before,
|
.panorama-modal-close .close-icon::before,
|
||||||
.panorama-modal-close .close-icon::after {
|
.panorama-modal-close .close-icon::after {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-modal-controls {
|
.panorama-modal-controls {
|
||||||
padding: 1.5rem;
|
padding: 1.5rem;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-control-buttons {
|
.panorama-control-buttons {
|
||||||
gap: 1rem;
|
gap: 1rem;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panorama-btn {
|
.panorama-btn {
|
||||||
min-width: 70px;
|
min-width: 70px;
|
||||||
padding: 0.75rem 1rem;
|
padding: 0.75rem 1rem;
|
||||||
|
|||||||
@ -375,25 +375,32 @@ class Easy360Viewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setupImageSize() {
|
setupImageSize() {
|
||||||
// 이미지 자연 어숙비를 유지하면서 컨테이너 높이에 맞춤
|
// 컨테이너 크기 가져오기
|
||||||
const containerHeight = this.container.clientHeight;
|
const containerHeight = this.container.clientHeight;
|
||||||
const containerWidth = this.container.clientWidth;
|
const containerWidth = this.container.clientWidth;
|
||||||
const imageAspectRatio = this.image.naturalWidth / this.image.naturalHeight;
|
const imageAspectRatio = this.image.naturalWidth / this.image.naturalHeight;
|
||||||
|
|
||||||
// 360도 이미지는 매우 가로가 기므로 컨테이너보다 훨씬 커야 함
|
// 모바일에서 줌 시 경계 문제 해결을 위한 더 정확한 크기 계산
|
||||||
let imageWidth = containerHeight * imageAspectRatio;
|
let imageHeight = containerHeight * this.zoom;
|
||||||
|
let imageWidth = imageHeight * imageAspectRatio;
|
||||||
// 컨테이너보다 작으면 컨테이너 너비에 맞춤
|
|
||||||
if (imageWidth < containerWidth * 2) {
|
// 360도 이미지는 매우 가로가 길므로 최소 크기 보장
|
||||||
imageWidth = containerWidth * 3; // 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.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.width = Math.round(imageWidth) + 'px';
|
||||||
this.imageWrapper.style.height = Math.round(containerHeight) + 'px';
|
this.imageWrapper.style.height = Math.round(containerHeight) + 'px';
|
||||||
|
|
||||||
// 단일 이미지 너비 저장
|
// 단일 이미지 너비 저장
|
||||||
this.singleImageWidth = imageWidth;
|
this.singleImageWidth = imageWidth;
|
||||||
}
|
}
|
||||||
@ -553,13 +560,17 @@ class Easy360Viewer {
|
|||||||
|
|
||||||
updatePosition(currentX) {
|
updatePosition(currentX) {
|
||||||
const deltaX = currentX - this.lastX;
|
const deltaX = currentX - this.lastX;
|
||||||
|
|
||||||
// 좌우 이동 (드래그 방향과 반대)
|
// 좌우 이동 (드래그 방향과 반대)
|
||||||
this.currentX -= deltaX;
|
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.updateTransform();
|
||||||
this.lastX = currentX;
|
this.lastX = currentX;
|
||||||
}
|
}
|
||||||
@ -583,32 +594,55 @@ class Easy360Viewer {
|
|||||||
|
|
||||||
handleResize() {
|
handleResize() {
|
||||||
if (this.image && this.image.complete) {
|
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.setupImageSize();
|
||||||
this.createDuplicateImages(); // 이미지 다시 생성
|
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();
|
this.updateTransform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTransform() {
|
updateTransform() {
|
||||||
if (!this.imageWrapper || !this.singleImageWidth) return;
|
if (!this.imageWrapper || !this.singleImageWidth) return;
|
||||||
|
|
||||||
// 무한 스크롤 처리 - 더 부드럽게
|
// 무한 스크롤 처리 - 튀는 버그 방지를 위한 부드러운 전환
|
||||||
if (this.currentX <= 0) {
|
const threshold = this.singleImageWidth * 0.1; // 10% 여유 공간
|
||||||
this.currentX = this.singleImageWidth;
|
|
||||||
} else if (this.currentX >= this.singleImageWidth * 2) {
|
// 왼쪽 경계 처리 - 부드러운 전환
|
||||||
this.currentX = this.singleImageWidth;
|
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 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})`;
|
const transform = `translateX(${translateX}px) scale(${scale})`;
|
||||||
this.imageWrapper.style.transform = transform;
|
this.imageWrapper.style.transform = transform;
|
||||||
|
|
||||||
// 브라우저 호환성
|
// 브라우저 호환성
|
||||||
this.imageWrapper.style.webkitTransform = transform;
|
this.imageWrapper.style.webkitTransform = transform;
|
||||||
this.imageWrapper.style.msTransform = transform;
|
this.imageWrapper.style.msTransform = transform;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user