So I have a page with images that can be clicked on to show a zoomed-in image. I want to allow the user to zoom in further, with pinch motions/wheel on various parts of the image as, as one normally can in a browser. However, once they click on the image to zoom out, I want the original scale of the page to be restored, regardless of how much they zoomed in.
Since there seems to be no way to directly set browsers’ zoom level via js, I thought to override the browser zoom and code my own. On zoom, the zoom-container-container fills up and covers the whole page. Then I override the default for the “wheel” event (ctrlKey == true). But I don’t override it for when ctrlKey == false and I set zoom-container-container to use scroll for overflow so that I can use the browser’s normal scroll functionality to move around inside the zoomed image.
It works correctly when starting from scale = 1, but I’m having trouble with the scenario where I’m already zoomed a little and move my cursor to another part of the image to zoom further. Doing so, the focus of the zoom always jumps further than it’s supposed to, but I’m not sure why. Maybe setting the transform-origin is not the right approach…
html
<div class="zoom-container-container">
<div class="zoom-container">
<img class="zoom-image">
</div>
</div>
css
.zoom-container-container
{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow-y: scroll;
overflow-x: auto;
z-index: -99;
background-color: var(--background-color);
pointer-events: auto;
opacity: 0.0;
transition-property: opacity, z-index;
transition-duration: 0.25s, 0s;
transition-delay: 0.0s, 0.25s;
}
.zoom-container
{
position: relative;
width: 100%;
height: 100%;
transform-origin: var(--zoom-origin-x) var(--zoom-origin-y);
transform: scale(var(--zoom-scale));
}
.zoom-image
{
position:relative;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 100%;
height: 100%;
object-fit: contain;
}
.zoom-container-container.visible
{
z-index: 99;
cursor:zoom-out;
opacity: 1.0;
transition-property: opacity, z-index;
transition-delay: 0s, 0s;
}
js events:
zoomImage.addEventListener('pointerup', (e) =>
{
if(e.button == 0)
{
zoomOut();
}
zoomScale = 1.0;
zoomContainer.style.setProperty('--zoom-scale', zoomScale);
zoomContainer.style.setProperty('--zoom-origin-x', `${50}%`);
zoomContainer.style.setProperty('--zoom-origin-y', `${50}%`);
});
zoomImage.addEventListener('wheel', (e) =>
{
const rect = zoomContainer.getBoundingClientRect();
if(e.ctrlKey)
{
const cursorX = e.clientX - rect.left;
const cursorY = e.clientY - rect.top;
const newScale = Math.max(1.0, zoomScale - e.deltaY * zoomScaleMult);
zoomScale = newScale;
const originX = (cursorX / rect.width) * 100;
const originY = (cursorY / rect.height) * 100;
zoomContainer.style.setProperty('--zoom-origin-x', `${originX}%`);
zoomContainer.style.setProperty('--zoom-origin-y', `${originY}%`);
zoomContainer.style.setProperty('--zoom-scale', zoomScale);
e.stopPropagation();
e.preventDefault();
}
});