Create an Image Magnifier with React
Anxiny
Posted on May 2, 2021
Today, let's create a simple image magnifier component.
First, let's create the basic structure of the component.
function ImageMagnifier({
src,
width,
height,
magnifierHeight = 100,
magnifieWidth = 100,
zoomLevel = 1.5
}: {
src: string;
width?: string;
height?: string;
magnifierHeight?: number;
magnifieWidth?: number;
zoomLevel?: number;
}) {
return (
// the container
<div
style={{
position: "relative",
height: height,
width: width
}}
>
// the image
<img
src={src}
style={{ height: height, width: width }}
alt={"img"}
/>
// a div for the magnifier
<div></div>
</div>
);
}
Then, we need to add a state that controll the display of magnifier
const [showMagnifier, setShowMagnifier] = useState(false);
and, the event handler that update the state.
...
<img
src={src}
style={{ height: height, width: width }}
onMouseEnter={(e) => {
setShowMagnifier(true);
}}
onMouseLeave={() => {
setShowMagnifier(false);
}}
alt={"img"}
/>
...
Now, we need to add a state that holds x, y position of magnifier, and update it when mouse move hover the image.
...
const [[x, y], setXY] = useState([0, 0]);
...
<img
...
onMouseMove={(e) => {
// update cursor position
const elem = e.currentTarget;
const { top, left } = elem.getBoundingClientRect();
// calculate cursor position on the image
const x = e.pageX - left - window.pageXOffset;
const y = e.pageY - top - window.pageYOffset;
setXY([x, y]);
}}
...
/>
The pageX/Y
coordinates are relative to the left/top corner of current page.
The pageXOffset/pageYOffset
are the scroll offsets of the page.
The left/top
are the coordinates of the image left/top position.
const x = e.pageX - left - window.pageXOffset;
const y = e.pageY - top - window.pageYOffset;
These two calculations will give us the cursor's x/y coordinates based on the image.
In order to calculate the position of the magnifier, we also need to have the size of image in pixels, so let's update it when mouse is entering the image.
<img
...
onMouseEnter={(e) => {
// update image size and turn-on magnifier
const elem = e.currentTarget;
const { width, height } = elem.getBoundingClientRect();
setSize([width, height]);
setShowMagnifier(true);
}}
...
/>
Now, we can add the position and other basic styles to the magnifier.
<div
style={{
display: showMagnifier ? "" : "none",
position: "absolute",
// prevent magnifier blocks the mousemove event of img
pointerEvents: "none",
// set size of magnifier
height: `${magnifierHeight}px`,
width: `${magnifieWidth}px`,
// move element center to cursor pos
top: `${y - magnifierHeight / 2}px`,
left: `${x - magnifieWidth / 2}px`,
opacity: "1", // reduce opacity so you can verify position
border: "1px solid lightgray", // show the border of magnifier
backgroundColor: "white",
backgroundImage: `url('${src}')`,
backgroundRepeat: "no-repeat",
}}
/>
Then, we need to zoom the image inside the magnifier.
...
//calculate zoomed image size
backgroundSize: `${imgWidth * zoomLevel}px ${imgHeight * zoomLevel}px`,
...
Also, we need to center the image in the magnifier base on cursor position on the image.
...
//calculate position of zoomed image.
backgroundPositionX: `${-x * zoomLevel + magnifieWidth / 2}px`,
backgroundPositionY: `${-y * zoomLevel + magnifierHeight / 2}px`
...
We done it. Here is the full code and a demo:
function ImageMagnifier({
src,
width,
height,
magnifierHeight = 100,
magnifieWidth = 100,
zoomLevel = 1.5
}: {
src: string;
width?: string;
height?: string;
magnifierHeight?: number;
magnifieWidth?: number;
zoomLevel?: number;
}) {
const [[x, y], setXY] = useState([0, 0]);
const [[imgWidth, imgHeight], setSize] = useState([0, 0]);
const [showMagnifier, setShowMagnifier] = useState(false);
return (
<div
style={{
position: "relative",
height: height,
width: width
}}
>
<img
src={src}
style={{ height: height, width: width }}
onMouseEnter={(e) => {
// update image size and turn-on magnifier
const elem = e.currentTarget;
const { width, height } = elem.getBoundingClientRect();
setSize([width, height]);
setShowMagnifier(true);
}}
onMouseMove={(e) => {
// update cursor position
const elem = e.currentTarget;
const { top, left } = elem.getBoundingClientRect();
// calculate cursor position on the image
const x = e.pageX - left - window.pageXOffset;
const y = e.pageY - top - window.pageYOffset;
setXY([x, y]);
}}
onMouseLeave={() => {
// close magnifier
setShowMagnifier(false);
}}
alt={"img"}
/>
<div
style={{
display: showMagnifier ? "" : "none",
position: "absolute",
// prevent magnifier blocks the mousemove event of img
pointerEvents: "none",
// set size of magnifier
height: `${magnifierHeight}px`,
width: `${magnifieWidth}px`,
// move element center to cursor pos
top: `${y - magnifierHeight / 2}px`,
left: `${x - magnifieWidth / 2}px`,
opacity: "1", // reduce opacity so you can verify position
border: "1px solid lightgray",
backgroundColor: "white",
backgroundImage: `url('${src}')`,
backgroundRepeat: "no-repeat",
//calculate zoomed image size
backgroundSize: `${imgWidth * zoomLevel}px ${
imgHeight * zoomLevel
}px`,
//calculate position of zoomed image.
backgroundPositionX: `${-x * zoomLevel + magnifieWidth / 2}px`,
backgroundPositionY: `${-y * zoomLevel + magnifierHeight / 2}px`
}}
></div>
</div>
);
}
Thank you all!
Posted on May 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.