fix: zoom
This commit is contained in:
@@ -14,12 +14,14 @@ class ImageGallery extends HTMLElement {
|
||||
this.isDragging = false;
|
||||
this.startX = 0;
|
||||
this.startY = 0;
|
||||
this.lastTranslateX = 0;
|
||||
this.lastTranslateY = 0;
|
||||
|
||||
// Pinch zoom state
|
||||
this.initialPinchDistance = 0;
|
||||
this.initialZoom = 1;
|
||||
this.pinchCenterX = 0;
|
||||
this.pinchCenterY = 0;
|
||||
this.initialTranslateX = 0;
|
||||
this.initialTranslateY = 0;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
@@ -117,16 +119,56 @@ class ImageGallery extends HTMLElement {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const delta = e.deltaY > 0 ? -0.1 : 0.1;
|
||||
this.zoom(delta);
|
||||
const delta = e.deltaY > 0 ? -0.15 : 0.15;
|
||||
|
||||
// Get mouse position relative to modal content center
|
||||
const modalContent = this.shadowRoot.querySelector(".modal-content");
|
||||
const rect = modalContent.getBoundingClientRect();
|
||||
const mouseX = e.clientX - rect.left - rect.width / 2;
|
||||
const mouseY = e.clientY - rect.top - rect.height / 2;
|
||||
|
||||
this.zoomToPoint(delta, mouseX, mouseY);
|
||||
}
|
||||
|
||||
zoomToPoint(delta, pointX, pointY) {
|
||||
const modalImage = this.shadowRoot.querySelector(".modal-image");
|
||||
if (!modalImage) return;
|
||||
|
||||
const prevZoom = this.currentZoom;
|
||||
const newZoom = Math.max(1, Math.min(4, this.currentZoom + delta));
|
||||
|
||||
if (newZoom === prevZoom) return;
|
||||
|
||||
// Calculate new translate to zoom towards point
|
||||
if (newZoom === 1) {
|
||||
this.translateX = 0;
|
||||
this.translateY = 0;
|
||||
} else {
|
||||
const zoomRatio = newZoom / prevZoom;
|
||||
this.translateX = pointX - (pointX - this.translateX) * zoomRatio;
|
||||
this.translateY = pointY - (pointY - this.translateY) * zoomRatio;
|
||||
}
|
||||
|
||||
this.currentZoom = newZoom;
|
||||
this.updateImageTransform(false);
|
||||
modalImage.style.cursor = this.currentZoom > 1 ? "grab" : "default";
|
||||
}
|
||||
|
||||
handleTouchStart(e) {
|
||||
if (e.touches.length === 2) {
|
||||
// Pinch zoom start
|
||||
e.preventDefault();
|
||||
this.isDragging = false; // Stop any ongoing drag
|
||||
this.initialPinchDistance = this.getPinchDistance(e.touches);
|
||||
this.initialZoom = this.currentZoom;
|
||||
this.initialTranslateX = this.translateX;
|
||||
this.initialTranslateY = this.translateY;
|
||||
|
||||
// Get pinch center relative to viewport
|
||||
const modalContent = this.shadowRoot.querySelector(".modal-content");
|
||||
const rect = modalContent.getBoundingClientRect();
|
||||
this.pinchCenterX = ((e.touches[0].clientX + e.touches[1].clientX) / 2) - rect.left - rect.width / 2;
|
||||
this.pinchCenterY = ((e.touches[0].clientY + e.touches[1].clientY) / 2) - rect.top - rect.height / 2;
|
||||
} else if (e.touches.length === 1 && this.currentZoom > 1) {
|
||||
// Single touch drag when zoomed
|
||||
this.startDrag(e);
|
||||
@@ -134,21 +176,27 @@ class ImageGallery extends HTMLElement {
|
||||
}
|
||||
|
||||
handleTouchMove(e) {
|
||||
if (e.touches.length === 2) {
|
||||
// Pinch zoom
|
||||
if (e.touches.length === 2 && this.initialPinchDistance > 0) {
|
||||
// Pinch zoom with zoom-to-point
|
||||
e.preventDefault();
|
||||
const currentDistance = this.getPinchDistance(e.touches);
|
||||
const scale = currentDistance / this.initialPinchDistance;
|
||||
const newZoom = Math.max(1, Math.min(4, this.initialZoom * scale));
|
||||
const prevZoom = this.currentZoom;
|
||||
|
||||
this.currentZoom = newZoom;
|
||||
|
||||
if (this.currentZoom === 1) {
|
||||
this.translateX = 0;
|
||||
this.translateY = 0;
|
||||
} else {
|
||||
// Adjust translate to zoom towards pinch center
|
||||
const zoomRatio = this.currentZoom / this.initialZoom;
|
||||
this.translateX = this.pinchCenterX - (this.pinchCenterX - this.initialTranslateX) * zoomRatio;
|
||||
this.translateY = this.pinchCenterY - (this.pinchCenterY - this.initialTranslateY) * zoomRatio;
|
||||
}
|
||||
|
||||
this.updateImageTransform();
|
||||
this.updateImageTransform(false); // No transition during pinch
|
||||
|
||||
const modalImage = this.shadowRoot.querySelector(".modal-image");
|
||||
if (modalImage) {
|
||||
@@ -209,7 +257,12 @@ class ImageGallery extends HTMLElement {
|
||||
this.translateX = clientX - this.startX;
|
||||
this.translateY = clientY - this.startY;
|
||||
|
||||
this.updateImageTransform();
|
||||
// Use no transition during drag for smooth movement
|
||||
const modalImage = this.shadowRoot.querySelector(".modal-image");
|
||||
if (modalImage) {
|
||||
modalImage.style.transition = "none";
|
||||
modalImage.style.transform = `scale(${this.currentZoom}) translate(${this.translateX / this.currentZoom}px, ${this.translateY / this.currentZoom}px)`;
|
||||
}
|
||||
}
|
||||
|
||||
endDrag() {
|
||||
@@ -224,10 +277,19 @@ class ImageGallery extends HTMLElement {
|
||||
}
|
||||
}
|
||||
|
||||
updateImageTransform() {
|
||||
updateImageTransform(useTransition = true) {
|
||||
const modalImage = this.shadowRoot.querySelector(".modal-image");
|
||||
if (modalImage) {
|
||||
if (!useTransition) {
|
||||
modalImage.style.transition = "none";
|
||||
}
|
||||
modalImage.style.transform = `scale(${this.currentZoom}) translate(${this.translateX / this.currentZoom}px, ${this.translateY / this.currentZoom}px)`;
|
||||
|
||||
// Force reflow and restore transition
|
||||
if (!useTransition) {
|
||||
modalImage.offsetHeight; // Force reflow
|
||||
modalImage.style.transition = "transform 0.2s ease";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,13 +300,25 @@ class ImageGallery extends HTMLElement {
|
||||
if (modal && modalImage && this.images[index]) {
|
||||
modalImage.src = this.images[index];
|
||||
|
||||
// Reset zoom and pan
|
||||
// Reset all state
|
||||
this.currentZoom = 1;
|
||||
this.translateX = 0;
|
||||
this.translateY = 0;
|
||||
this.updateImageTransform();
|
||||
this.isDragging = false;
|
||||
this.initialPinchDistance = 0;
|
||||
this.initialZoom = 1;
|
||||
this.initialTranslateX = 0;
|
||||
this.initialTranslateY = 0;
|
||||
|
||||
// Reset transform without transition
|
||||
modalImage.style.transition = "none";
|
||||
modalImage.style.transform = "scale(1) translate(0px, 0px)";
|
||||
modalImage.style.cursor = "default";
|
||||
|
||||
// Force reflow then restore transition
|
||||
modalImage.offsetHeight;
|
||||
modalImage.style.transition = "transform 0.2s ease";
|
||||
|
||||
modal.classList.add("open");
|
||||
document.body.style.overflow = "hidden";
|
||||
}
|
||||
@@ -278,10 +352,19 @@ class ImageGallery extends HTMLElement {
|
||||
resetZoom() {
|
||||
const modalImage = this.shadowRoot.querySelector(".modal-image");
|
||||
if (modalImage) {
|
||||
// Reset all state
|
||||
this.currentZoom = 1;
|
||||
this.translateX = 0;
|
||||
this.translateY = 0;
|
||||
this.updateImageTransform();
|
||||
this.isDragging = false;
|
||||
this.initialPinchDistance = 0;
|
||||
this.initialZoom = 1;
|
||||
this.initialTranslateX = 0;
|
||||
this.initialTranslateY = 0;
|
||||
|
||||
// Ensure transition is enabled for smooth reset animation
|
||||
modalImage.style.transition = "transform 0.3s ease";
|
||||
modalImage.style.transform = "scale(1) translate(0px, 0px)";
|
||||
modalImage.style.cursor = "default";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user