Skip to content

Instantly share code, notes, and snippets.

@jackbkennedy
Created November 2, 2023 09:49
Show Gist options
  • Save jackbkennedy/ecf37762a527ba4c00d48894351dfeff to your computer and use it in GitHub Desktop.
Save jackbkennedy/ecf37762a527ba4c00d48894351dfeff to your computer and use it in GitHub Desktop.
A react image component that focuses an image in the middle of the page and zooms in to make it easier to see.
import React, { useEffect, useRef, useState } from 'react';
import ReactDOM from 'react-dom';
type ZoomableImageProps = {
url: string;
style?: React.CSSProperties; // for custom styles
className?: string; // to allow custom classes
};
/*
* A component that displays an image and allows it to be zoomed in/out
* by clicking on it.
*/
export const ZoomableImageComponent: React.FC<ZoomableImageProps> = ({
url,
style,
className,
}) => {
const [isZoomed, setIsZoomed] = useState(false);
const imageRef = useRef<HTMLImageElement>(null);
const handleImageClick = (e: React.MouseEvent) => {
e.stopPropagation();
setIsZoomed(!isZoomed);
};
useEffect(() => {
const handleDocumentClick = () => {
setIsZoomed(false);
};
if (isZoomed) {
document.addEventListener('click', handleDocumentClick);
}
return () => {
document.removeEventListener('click', handleDocumentClick);
};
}, [isZoomed]);
const zoomedImage = (
<>
<div
style={{
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
zIndex: 999998,
}}
/>
<img
src={url}
alt="Zoomed"
style={{
position: 'fixed',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%) scale(2)',
maxWidth: '35%',
maxHeight: '35%',
zIndex: 999999,
cursor: 'zoom-out',
}}
/>
</>
);
// Default styles that can be overridden by passing a `style` prop
const defaultStyles = {
width: '580px',
height: '420px',
borderRadius: '6px',
position: 'relative',
...style, // spread in additional styles if provided
};
return (
<div style={defaultStyles} className={className}>
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%' }}>
<button onClick={handleImageClick} style={{ background: 'none', border: 'none', padding: 0 }}>
<img
ref={imageRef}
src={url}
alt="Thumbnail"
style={{
maxWidth: '100%',
maxHeight: '100%',
borderRadius: '6px',
cursor: 'zoom-in',
transition: 'transform 0.3s',
zIndex: isZoomed ? 999999 : 1,
}}
/>
</button>
</div>
{isZoomed && ReactDOM.createPortal(zoomedImage, document.body)}
</div>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment