@kyverus/react-custom-magnifier
Version:
A Customizable React Component for Magnifying Images
185 lines (150 loc) • 5.56 kB
JSX
import React, { useState, useEffect, useRef } from "react";
import { isTouchDevice } from "../../utils/utils";
import "./ImageMagnifier.css";
import { MagnifierDisplay } from "../MagnifierDisplay/MagnifierDisplay";
import { MagnifierCursor } from "../MagnifierCursor/MagnifierCursor";
function ImageMagnifier({ src, initialWidth, fixedWidth, cursorOnly }) {
const [magnifierSize, setMagnifierSize] = useState({ width: 0, height: 0 });
const [cursorPosition, setCursorPosition] = useState({ x: 0, y: 0 });
const [displayPosition, setDisplayPosition] = useState({ x: 0, y: 0 });
const [zoomPosition, setZoomPosition] = useState({ x: 0, y: 0 });
const [canFit, setCanFit] = useState(false);
const touch = isTouchDevice();
useEffect(() => {
checkImageWidth();
}, [window.innerWidth, magnifierSize]);
function checkImageWidth() {
const parent = document.getElementById("magnifier").parentElement;
const parentWidth =
parent.id == "root" ? window.innerWidth : parent.clientWidth;
let width = initialWidth
? initialWidth
: fixedWidth
? "max-content"
: "100%";
if (initialWidth && !fixedWidth) {
if (initialWidth >= parentWidth) {
width = "100%";
}
}
const magnifierAndBoxWidth =
document.getElementById("magnifier").clientWidth * 1.5;
if (magnifierAndBoxWidth >= window.innerWidth) {
setCanFit(false);
} else {
setCanFit(true);
}
const image = document.getElementById("magnifier-image");
if (image.style.width != width) {
image.style.width = width;
}
}
useEffect(() => {
const resizeObserver = new ResizeObserver((entries) => {
for (const entry of entries) {
if (entry.contentBoxSize) {
setMagnifierSize({
width: entry.contentRect.width,
height: entry.contentRect.height,
});
setDisplayPosition({
x: entry.contentRect.width,
y: entry.contentRect.height / 2,
});
}
}
});
const magnifier = document.getElementById("magnifier");
resizeObserver.observe(magnifier);
return () => {
resizeObserver.unobserve(magnifier);
};
}, []);
function onMouseMove(event) {
const magnifier = document.getElementById("magnifier");
const cursor = document.getElementById("magnifier-cursor");
const cursorWidth = cursor.clientWidth;
const cursorHeight = cursor.clientHeight;
cursorHandler(magnifier, event, cursorWidth, cursorHeight);
zoomHandler(magnifier, event, cursorWidth, cursorHeight);
}
function cursorHandler(magnifier, event, cursorWidth, cursorHeight) {
var rect = magnifier.getBoundingClientRect();
let mouseX = event.clientX - cursorWidth / 2;
let mouseY = event.clientY - cursorHeight / 2;
mouseX = limitValue(mouseX, rect.left, rect.right - cursorWidth);
mouseY = limitValue(mouseY, rect.top, rect.bottom - cursorHeight);
setCursorPosition({
x: mouseX,
y: mouseY,
});
}
function zoomHandler(magnifier, event, cursorWidth, cursorHeight) {
const rect = magnifier.getBoundingClientRect();
const cursorDivider = cursorOnly || !canFit ? 4 : 2;
let x = event.clientX - rect.left - cursorWidth / cursorDivider;
let y = event.clientY - rect.top - cursorHeight / cursorDivider;
let boundedMagnifierWidth =
magnifier.clientWidth - cursorWidth / cursorDivider;
let boundedMagnifierHeight =
magnifier.clientHeight - cursorHeight / cursorDivider;
x = limitValue(x, 0, boundedMagnifierWidth);
y = limitValue(y, 0, boundedMagnifierHeight);
let zoomPosX =
(x * 100) / (magnifier.clientWidth - cursorWidth / (cursorDivider / 2));
let zoomPosy =
(y * 100) / (magnifier.clientHeight - cursorHeight / (cursorDivider / 2));
zoomPosX = limitValue(zoomPosX, 0, 100);
zoomPosy = limitValue(zoomPosy, 0, 100);
setZoomPosition({
x: zoomPosX,
y: zoomPosy,
});
}
function limitValue(value, min, max) {
if (value <= min) return min;
if (value >= max) return max;
return value;
}
function showImage() {
document.getElementById("magnifier-cursor").style.display = "block";
if (!cursorOnly && canFit) {
document.getElementById("magnifier-display").style.display = "block";
}
}
function hideImage() {
document.getElementById("magnifier-cursor").style.display = "none";
if (!cursorOnly && canFit) {
document.getElementById("magnifier-display").style.display = "none";
}
}
return (
<div
id="magnifier"
onMouseMove={!touch ? onMouseMove : undefined}
onMouseLeave={!touch ? hideImage : undefined}
onMouseEnter={!touch ? showImage : undefined}
>
<img id="magnifier-image" src={src} />
{!touch && (
<MagnifierCursor
src={src}
cursorPosition={cursorPosition}
zoomPosition={zoomPosition}
magnifierSize={magnifierSize}
cursorOnly={cursorOnly}
canFit={canFit}
/>
)}
{canFit && !cursorOnly && !touch && (
<MagnifierDisplay
src={src}
displayPosition={displayPosition}
zoomPosition={zoomPosition}
magnifierSize={magnifierSize}
/>
)}
</div>
);
}
export default ImageMagnifier;