Fix lightbox zooming

This commit is contained in:
2026-05-05 20:54:04 +02:00
parent 5e690e5576
commit 07a5c3baf9

View File

@@ -468,26 +468,24 @@ export default class Lightbox {
event.preventDefault(); event.preventDefault();
const rect = this.image.getBoundingClientRect(); const rect = this.image.getBoundingClientRect();
const oldZoom = parseFloat(this.image.style.getPropertyValue('--scale') || '1'); const oldTransform = this.getImageTransform();
const oldTranslateX = parseFloat(this.image.style.getPropertyValue('--translate-x') || '0'); const oldZoom = oldTransform.scale;
const oldTranslateY = parseFloat(this.image.style.getPropertyValue('--translate-y') || '0');
const maxZoom = Math.max(media.width / Math.max(this.image.width, 1), media.height / Math.max(this.image.height, 1), 1); const maxZoom = Math.max(media.width / Math.max(this.image.width, 1), media.height / Math.max(this.image.height, 1), 1);
const newZoom = Math.min(Math.max(oldZoom + (-Math.sign(event.deltaY) / 10), 1), maxZoom); const newZoom = Math.min(Math.max(oldZoom + (-Math.sign(event.deltaY) / 10), 1), maxZoom);
const offsetX = event.clientX - rect.left; const imageCenterX = rect.left + rect.width / 2 - oldTransform.translateX;
const offsetY = event.clientY - rect.top; const imageCenterY = rect.top + rect.height / 2 - oldTransform.translateY;
let translateX = oldTranslateX + (newZoom - oldZoom) * ((this.image.width / 2) - offsetX); const cursorX = event.clientX - imageCenterX;
let translateY = oldTranslateY + (newZoom - oldZoom) * ((this.image.height / 2) - offsetY); const cursorY = event.clientY - imageCenterY;
const maxTranslateX = (newZoom - 1) * this.image.width / 2; const zoomRatio = newZoom / oldZoom;
const maxTranslateY = (newZoom - 1) * this.image.height / 2; const transform = this.clampImageTransform({
scale: newZoom,
translateX = Math.max(Math.min(translateX, maxTranslateX), -maxTranslateX); translateX: cursorX - zoomRatio * (cursorX - oldTransform.translateX),
translateY = Math.max(Math.min(translateY, maxTranslateY), -maxTranslateY); translateY: cursorY - zoomRatio * (cursorY - oldTransform.translateY)
});
this.container.classList.toggle('moveable', newZoom > 1); this.container.classList.toggle('moveable', newZoom > 1);
this.image.style.setProperty('--scale', String(newZoom)); this.setImageTransform(transform);
this.image.style.setProperty('--translate-x', `${translateX}px`);
this.image.style.setProperty('--translate-y', `${translateY}px`);
} }
onDragStart(event) { onDragStart(event) {
@@ -502,16 +500,13 @@ export default class Lightbox {
onDragMove(event) { onDragMove(event) {
const zoom = parseFloat(this.image.style.getPropertyValue('--scale') || '1'); const zoom = parseFloat(this.image.style.getPropertyValue('--scale') || '1');
let translateX = event.clientX - this.gMouseDownOffsetX; const transform = this.clampImageTransform({
let translateY = event.clientY - this.gMouseDownOffsetY; scale: zoom,
const maxTranslateX = (zoom - 1) * this.image.width / 2; translateX: event.clientX - this.gMouseDownOffsetX,
const maxTranslateY = (zoom - 1) * this.image.height / 2; translateY: event.clientY - this.gMouseDownOffsetY
});
translateX = Math.max(Math.min(translateX, maxTranslateX), -maxTranslateX); this.setImageTransform(transform);
translateY = Math.max(Math.min(translateY, maxTranslateY), -maxTranslateY);
this.image.style.setProperty('--translate-x', `${translateX}px`);
this.image.style.setProperty('--translate-y', `${translateY}px`);
} }
onDragEnd() { onDragEnd() {
@@ -520,9 +515,32 @@ export default class Lightbox {
} }
resetImageTransform() { resetImageTransform() {
this.image.style.setProperty('--scale', '1'); this.setImageTransform({scale: 1, translateX: 0, translateY: 0});
this.image.style.setProperty('--translate-x', '0px'); }
this.image.style.setProperty('--translate-y', '0px');
getImageTransform() {
return {
scale: parseFloat(this.image.style.getPropertyValue('--scale') || '1'),
translateX: parseFloat(this.image.style.getPropertyValue('--translate-x') || '0'),
translateY: parseFloat(this.image.style.getPropertyValue('--translate-y') || '0')
};
}
clampImageTransform(transform) {
const maxTranslateX = (transform.scale - 1) * this.image.width / 2;
const maxTranslateY = (transform.scale - 1) * this.image.height / 2;
return {
scale: transform.scale,
translateX: Math.max(Math.min(transform.translateX, maxTranslateX), -maxTranslateX),
translateY: Math.max(Math.min(transform.translateY, maxTranslateY), -maxTranslateY)
};
}
setImageTransform(transform) {
this.image.style.setProperty('--scale', String(transform.scale));
this.image.style.setProperty('--translate-x', `${transform.translateX}px`);
this.image.style.setProperty('--translate-y', `${transform.translateY}px`);
} }
hideElements(elements) { hideElements(elements) {
@@ -573,4 +591,4 @@ export default class Lightbox {
if (this.options.disableScrolling) document.body.classList.remove('lb-disable-scrolling'); if (this.options.disableScrolling) document.body.classList.remove('lb-disable-scrolling');
this.options.onClosing(); this.options.onClosing();
} }
} }