Created
March 3, 2024 21:44
-
-
Save guilhermerodz/404c1a6ca25a01173a64d9afb6fad1d0 to your computer and use it in GitHub Desktop.
react magnifier
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use client' | |
import * as React from 'react' | |
import { cn } from '@/lib/cn' | |
import Image from 'next/image' | |
export default function Home() { | |
const mirrorRef = React.useRef<HTMLDivElement>(null) | |
const mainRef = React.useRef<HTMLDivElement>(null) | |
const [isMagnifying, setIsMagnifying] = React.useState(false) | |
function mouseMove(e: React.MouseEvent<HTMLDivElement>) { | |
const main = mainRef.current | |
const mirror = mirrorRef.current | |
if (!main || !mirror) return | |
const mainRect = main.getBoundingClientRect() | |
const mirrorRect = mirror.getBoundingClientRect() | |
// get x and y offset within main | |
const x = e.clientX - mainRect.left | |
const y = e.clientY - mainRect.top | |
const diffX = mirrorRect.width - mainRect.width | |
const diffY = mirrorRect.height - mainRect.height | |
const px = x / mainRect.width | |
const py = y / mainRect.height | |
const tx = px * diffX - diffX / 2 | |
const ty = py * diffY - diffY / 2 | |
mirror.style.setProperty('--ox', `${tx}px`) | |
mirror.style.setProperty('--oy', `${ty}px`) | |
} | |
return ( | |
<div className="w-screen h-screen"> | |
<div | |
className="absolute w-[300px] h-[300px] left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 border border-[red] overflow-hidden" | |
onMouseOver={() => setIsMagnifying(true)} | |
onMouseLeave={() => setIsMagnifying(false)} | |
onMouseMove={mouseMove} | |
> | |
<MainLayer ref={mainRef} /> | |
{isMagnifying && <MirrorLayer ref={mirrorRef} />} | |
</div> | |
</div> | |
) | |
} | |
const MainLayer = React.forwardRef< | |
HTMLDivElement, | |
React.HTMLAttributes<HTMLDivElement> | |
>((props, ref) => { | |
return ( | |
<div ref={ref} className="relative w-full h-full"> | |
<Image src="/placeholder.svg" fill alt="Arthur" /> | |
</div> | |
) | |
}) | |
MainLayer.displayName = 'MainLayer' | |
const MirrorLayer = React.forwardRef< | |
HTMLDivElement, | |
React.HTMLAttributes<HTMLDivElement> | |
>((props, ref) => { | |
return ( | |
<div | |
ref={ref} | |
className={cn( | |
'absolute pointer-events-none inset-0 border border-[green]', | |
'[--ox:0] [--oy:0]', | |
'[transform:scale(1.5)_translate(var(--ox),var(--oy))]', | |
)} | |
// IMPORTANT: prevent any user input such as pointer-events or keyboard | |
> | |
<MainLayer /> | |
</div> | |
) | |
}) | |
MirrorLayer.displayName = 'MirrorLayer' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment