I have the following simple code that pans and zooms an image (slightly modified from [here]:(https://www.cssscript.com/image-zoom-hover-effect/)
function imageZoom(container, img) {
container.addEventListener("mousemove", onZoom);
container.addEventListener("mouseover", onZoom);
container.addEventListener("mouseleave", offZoom);
function onZoom(e) {
let offset = container.getBoundingClientRect();
const x = e.clientX - offset.left;
const y = e.clientY - offset.top;
img.style.transformOrigin = `${x}px ${y}px`;
img.style.transform = "scale(2.5)";
}
function offZoom(e) {
img.style.transformOrigin = `center center`;
img.style.transform = "scale(1)";
}
}
This works well when the image is proportional to container. I need it to work with random-sized images inside square containers, with the ability to show the entire image via pan & zoom.
I've tried multiplying X and Y by
let coefX= img.naturalWidth / container.offsetWidth
let coefY= img.naturalHeight / container.offsetHeight
respectively, but that resulted in the image leaving the container altogether. I feel like the math is simple and obvious, but I can't seem to grasp it - other attempts I've made resulted in similar problems.
I always wanted to make that effect. I "found" this online. This solution features only pan, no zoom. With an added bonus of a safe zone around the frame.
// container, image are defined
function panImage(event) {
// Adjust this value to control the buffer area around the frame
const buffer = 10;
const containerRect = container.getBoundingClientRect();
const mouseX = event.clientX - containerRect.left;
const mouseY = event.clientY - containerRect.top;
const maxX = image.clientWidth - container.clientWidth;
const maxY = image.clientHeight - container.clientHeight;
const xPercentage = (mouseX - buffer) / (container.clientWidth - buffer * 2);
const yPercentage = (mouseY - buffer) / (container.clientHeight - buffer * 2);
const offsetX = Math.min(Math.max(0, xPercentage * maxX), maxX);
const offsetY = Math.min(Math.max(0, yPercentage * maxY), maxY);
image.style.transform = `translate(-${offsetX}px, -${offsetY}px)`;
}
#container {
width: 200px;
height: 150px;
overflow: hidden;
border: 1px solid red;
}
#image {
transform: translate(0, 0);
transition: all 0.25s ease;
}
<div id="container" onmousemove="panImage(event)">
<img id="image" src="https://picsum.photos/412/370">
</div>