Add pan and zoom support to SVG image viewer
Some checks are pending
MSBuild / build (push) Waiting to run
MSBuild / publish (push) Blocked by required conditions

This commit is contained in:
ema
2025-06-30 07:32:46 +08:00
parent 0a8039d962
commit f9b075dfa3

View File

@@ -33,29 +33,79 @@
const base64 = encodeSvgToBase64(fixSvgSize(svgString));
const img = new Image();
img.src = `data:image/svg+xml;base64,${base64}`;
img.style.transform = "scale(1)";
img.draggable = false;
let scale = 1;
let offsetX = 0;
let offsetY = 0;
let startX = 0;
let startY = 0;
let isDragging = false;
let imgNaturalWidth = 0;
let imgNaturalHeight = 0;
let canDragX = false;
let canDragY = false;
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
function updateTransform() {
img.style.transform = `scale(${scale})`;
// Calculate draggable range
const wrapperRect = wrapper.getBoundingClientRect();
const w = imgNaturalWidth * scale;
const h = imgNaturalHeight * scale;
canDragX = w > wrapperRect.width;
canDragY = h > wrapperRect.height;
const maxOffsetX = canDragX ? (w - wrapperRect.width) / 2 : 0;
const maxOffsetY = canDragY ? (h - wrapperRect.height) / 2 : 0;
offsetX = canDragX ? clamp(offsetX, -maxOffsetX, maxOffsetX) : 0;
offsetY = canDragY ? clamp(offsetY, -maxOffsetY, maxOffsetY) : 0;
img.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
}
img.onload = function () {
imgNaturalWidth = img.naturalWidth;
imgNaturalHeight = img.naturalHeight;
updateTransform();
};
document.addEventListener("wheel", (e) => {
e.preventDefault();
const scaleFactor = 1.2;
const prevScale = scale;
scale *= (e.deltaY < 0 ? scaleFactor : 1 / scaleFactor);
// Zoom based on window center, do not adjust offsetX/offsetY
updateTransform();
}, { passive: false });
// Add double-click event to reset zoom
// Drag events
img.addEventListener("mousedown", (e) => {
if (!(canDragX || canDragY)) return;
isDragging = true;
startX = e.clientX - offsetX;
startY = e.clientY - offsetY;
});
document.addEventListener("mousemove", (e) => {
if (!isDragging) return;
if (canDragX) offsetX = e.clientX - startX; else offsetX = 0;
if (canDragY) offsetY = e.clientY - startY; else offsetY = 0;
updateTransform();
});
document.addEventListener("mouseup", () => {
isDragging = false;
});
document.addEventListener("mouseleave", () => {
isDragging = false;
});
// Double-click to reset zoom and position
wrapper.addEventListener("dblclick", () => {
scale = 1;
offsetX = 0;
offsetY = 0;
updateTransform();
});
wrapper.appendChild(img);
updateTransform();
})();