UNPKG

@kyverus/react-custom-magnifier

Version:
185 lines (150 loc) 5.56 kB
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;