mirror of
https://github.com/upscayl/upscayl.git
synced 2024-11-28 01:10:52 +01:00
105 lines
2.9 KiB
TypeScript
105 lines
2.9 KiB
TypeScript
|
import React, { useRef, useState } from "react";
|
||
|
|
||
|
const LensImage = ({
|
||
|
src,
|
||
|
alt,
|
||
|
lensPosition,
|
||
|
zoomAmount,
|
||
|
}: {
|
||
|
src: string;
|
||
|
alt: string;
|
||
|
lensPosition: { x: number; y: number };
|
||
|
zoomAmount: number;
|
||
|
}) => (
|
||
|
<div className="h-full w-full overflow-hidden">
|
||
|
<img
|
||
|
src={src}
|
||
|
alt={alt}
|
||
|
className="h-full w-full"
|
||
|
style={{
|
||
|
objectFit: "contain",
|
||
|
objectPosition: `${-lensPosition.x}px ${-lensPosition.y}px`,
|
||
|
transform: `scale(${zoomAmount / 100})`,
|
||
|
transformOrigin: "top left",
|
||
|
}}
|
||
|
/>
|
||
|
</div>
|
||
|
);
|
||
|
|
||
|
const LensViewer = ({
|
||
|
zoomAmount,
|
||
|
lensSize,
|
||
|
sanitizedImagePath,
|
||
|
sanitizedUpscaledImagePath,
|
||
|
}: {
|
||
|
zoomAmount: string;
|
||
|
lensSize: number;
|
||
|
sanitizedImagePath: string;
|
||
|
sanitizedUpscaledImagePath: string;
|
||
|
}) => {
|
||
|
const upscaledImageRef = useRef<HTMLImageElement>(null);
|
||
|
|
||
|
const [lensPosition, setLensPosition] = useState({ x: 0, y: 0 });
|
||
|
|
||
|
const handleMouseMoveCompare = (e: React.MouseEvent) => {
|
||
|
if (upscaledImageRef.current) {
|
||
|
const { left, top, width, height } =
|
||
|
upscaledImageRef.current.getBoundingClientRect();
|
||
|
const x = e.clientX - left;
|
||
|
const y = e.clientY - top;
|
||
|
setLensPosition({
|
||
|
x: Math.max(0, Math.min(x - lensSize, width - lensSize * 2)),
|
||
|
y: Math.max(0, Math.min(y - lensSize / 2, height - lensSize)),
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
return (
|
||
|
<div
|
||
|
className="group relative h-full w-full overflow-hidden"
|
||
|
onMouseMove={handleMouseMoveCompare}
|
||
|
>
|
||
|
{/* UPSCALED IMAGE */}
|
||
|
<img
|
||
|
className="h-full w-full object-contain"
|
||
|
src={"file:///" + sanitizedUpscaledImagePath}
|
||
|
alt="Upscaled"
|
||
|
ref={upscaledImageRef}
|
||
|
/>
|
||
|
{/* LENS */}
|
||
|
<div
|
||
|
className="pointer-events-none absolute opacity-0 transition-opacity before:absolute before:left-1/2 before:h-full before:w-[2px] before:bg-white group-hover:opacity-100"
|
||
|
style={{
|
||
|
left: `${lensPosition.x}px`,
|
||
|
top: `${lensPosition.y}px`,
|
||
|
width: lensSize * 2,
|
||
|
height: lensSize,
|
||
|
border: "2px solid white",
|
||
|
boxShadow: "0 0 0 9999px rgba(0, 0, 0, 0.5)",
|
||
|
}}
|
||
|
>
|
||
|
<div className="flex h-full w-full">
|
||
|
<LensImage
|
||
|
src={"file:///" + sanitizedImagePath}
|
||
|
alt="Original"
|
||
|
lensPosition={lensPosition}
|
||
|
zoomAmount={parseInt(zoomAmount)}
|
||
|
/>
|
||
|
<LensImage
|
||
|
src={"file:///" + sanitizedUpscaledImagePath}
|
||
|
alt="Upscaled"
|
||
|
lensPosition={lensPosition}
|
||
|
zoomAmount={parseInt(zoomAmount)}
|
||
|
/>
|
||
|
</div>
|
||
|
<div className="absolute bottom-0 left-0 flex w-full items-center justify-around bg-black bg-opacity-50 p-1 px-2 text-center text-xs text-white backdrop-blur-sm">
|
||
|
<span>Original</span>
|
||
|
<span>Upscayl</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
);
|
||
|
};
|
||
|
|
||
|
export default LensViewer;
|