Skip to content

Instantly share code, notes, and snippets.

@lynnjinjie
Created August 11, 2024 14:04
Show Gist options
  • Select an option

  • Save lynnjinjie/a8a34ccd239c88940720e9614edacc87 to your computer and use it in GitHub Desktop.

Select an option

Save lynnjinjie/a8a34ccd239c88940720e9614edacc87 to your computer and use it in GitHub Desktop.
react-pic-zoom
import { cn } from '@/lib/utils'
import { useRef, useState, type MouseEvent } from 'react'
interface Props {
url: string
scale?: number
}
export default function PicZoom({ url, scale }: Props) {
const [maskPosition, setMaskPosition] = useState<{
left: number
top: number
}>({ left: 0, top: 0 })
const [bigImgPosition, setBigImgPosition] = useState<{
left: number
top: number
}>({ left: 0, top: 0 })
const [isShowZoom, setIsShowZoom] = useState(false)
const boxRef = useRef<HTMLDivElement | null>(null)
const smallBoxRef = useRef<HTMLDivElement | null>(null)
const maskBoxRef = useRef<HTMLDivElement | null>(null)
const bigImgRef = useRef<HTMLImageElement | null>(null)
const handleSmallBoxOver = (e: MouseEvent) => {
setIsShowZoom(true)
}
const handleSmallBoxOut = (e: MouseEvent) => {
setIsShowZoom(false)
}
const handleSmallBoxMove = (e: MouseEvent) => {
const box = boxRef.current
const smallBox = smallBoxRef.current
const maskBox = maskBoxRef.current
const bigImg = bigImgRef.current
if (box && smallBox && maskBox && bigImg) {
const { left, top } = box.getBoundingClientRect()
let x = e.clientX - left - maskBox.offsetWidth / 2
let y = e.clientY - top - maskBox.offsetHeight / 2
x < 0 && (x = 0)
y < 0 && (y = 0)
let c = smallBox.offsetHeight / 2
y > c && (y = c)
let l = smallBox.offsetWidth / 2
x > l && (x = l)
setMaskPosition({ left: x, top: y })
let u = smallBox.offsetWidth / bigImg.offsetWidth
let d = smallBox.offsetHeight / bigImg.offsetHeight
setBigImgPosition({ left: -x / u, top: -y / d })
}
}
return (
<div ref={boxRef} className="relative w-[300px]">
<div
ref={smallBoxRef}
className="relative h-[300px] overflow-hidden text-center"
onMouseOver={handleSmallBoxOver}
onMouseMove={handleSmallBoxMove}
onMouseOut={handleSmallBoxOut}
>
<img className="h-full w-auto object-contain" src={url} alt="image" />
<div
ref={maskBoxRef}
className={cn(
'bg-[#f5cda3] opacity-40 cursor-move size-[150px] absolute',
isShowZoom ? 'block' : 'hidden'
)}
style={{
left: maskPosition.left,
top: maskPosition.top,
}}
></div>
</div>
<div
className={cn(
'absolute left-[330px] top-0 size-[420px] border border-zinc-300 overflow-hidden',
isShowZoom ? 'block' : 'hidden'
)}
>
<img
ref={bigImgRef}
className="size-[800px] absolute object-contain max-w-none max-h-none"
src={url}
alt="big-image"
style={{
left: bigImgPosition.left,
top: bigImgPosition.top,
}}
/>
</div>
</div>
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment