I am trying to create a pure javascript (no jQuery) magnifier for when I hover over an area on a visible img, allowing me to zoom in to a larger segment of the original (which may be scaled to fit the screen).
[I think] I can make it work for a small example image (one sized 220 x 346px) but when I try a larger (1239 x 1754px) one then it seems to only work when looking at the top left corner of the visible img.Can anyone assist in correcting the code to make this work?
let image = document.getElementsByClassName('visible')[0];
let mag = document.getElementsByClassName('zoomed')[0];
image.addEventListener('mousemove', showMag);
useImage(1);
function useImage(n) {
if (n == 1) image.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Letraset_Lorem_Ipsum.jpg/220px-Letraset_Lorem_Ipsum.jpg';
if (n == 2) image.src = 'https://data.webarchive.org.uk/crawl-test-site/resources/documents/lorem-ipsum.PDFA1-a.png';
document.getElementById('nm').innerHTML = 'Image '+n;
document.getElementById('notes').innerHTML = `${image.naturalWidth}/${image.naturalHeight}`;
}
function showMag() {
const imageRect = image.getBoundingClientRect();
let url = image.src;
let bgi = 'url(' + url + ')';
if (mag.style.backgroundImage !== bgi) mag.style.backgroundImage = bgi;
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
// Position over the visible image....
let hoverX = parseInt(event.clientX - imageRect.left);
let hoverY = parseInt(event.clientY - imageRect.top);
// Position over the zoomed view...
const zoomedX = parseInt(hoverX * scaleX);
const zoomedY = parseInt(hoverY * scaleY);
mag.style.backgroundPosition = -zoomedX + 'px ' + -zoomedY + 'px';
document.getElementById('notes').innerHTML=`<span>w/h=${image.naturalWidth}/${image.naturalHeight}</span> <span>hover x/y=${hoverX}/${hoverY}</span> <span>positioning = ${mag.style.backgroundPosition}</span> <span>scale=${scaleX}</span>`;
}
.container {
white-space:nowrap;
}
img {
vertical-align:top;
}
.visible {
width:30%;
}
.zoomed {
width:400px;
height:400px;
border:solid 1px red;
background-repeat: no-repeat;
background-size:100%;
background-color:grey;
}
span {
background-color:#e8e8e8;
border-radius:9px;
padding:4px;
margin-right:10px;
line-height:30px;
}
<button onClick='useImage(1)'>Image 1</button>
<button onClick='useImage(2)'>Image 2</button>
<hr>
<div id='nm'></div>
<div class='container'>
<img class='visible'>
<img class='zoomed' src=''>
</div>
<div id='notes'></div>
2
Answers
The issue with your code is cause of the calculation of the zoom x and zoom y pos cause when u hovering over the larger image since the natural dimensions of the image are much larger than the displayed dimensions you need to take into account the offset of the visible portion within the larger image to fix this you should multiply the hover x and hover y coordinates by the ratio of the displayed image size to the natural image size additionally when calculating the background position for the zoomed image you need to take into account the offset of the visible image relative to the larger image I jus rewrote it below it should work now bud.
The simplest way to implement a magnifying glass is to:
0..1
background-position
percentage:deltaX|Y * 100 %
background-size
from"auto"
to"cover"
– and you need to do that inside an image’s"load"
event listener. This way, by usingcover
the browser will magnify the image on its own inside the zoom area, and the user can at least either view it a bit zoomed in (if a perfect square) or explore it vertically or horizontally – without any extra effort (code) from your sideExample:
Extras:
"pointermove"
event, to make it handheld, touch devices friendlybackground: no-repeat center;
data-*
attribute where the image index is stored. The images URLs are set inside an Array. On click the index is used instead of a complexif/else
statement like the one you used.