fix(canvas): split compare into two panes for transparent outputs
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-01 02:12:59 +08:00
parent a1035c5dae
commit 7c69ccefc2

View File

@ -287,6 +287,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
// 文件输入的 ref
const fileInputRef = useRef<HTMLInputElement>(null);
const containerRef = useRef<HTMLDivElement>(null);
const compareFrameRef = useRef<HTMLDivElement>(null);
const updateNode = useCanvasStore((state) => state.updateNode);
const deleteNode = useCanvasStore((state) => state.deleteNode);
@ -387,6 +388,17 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
}
}, [hasCompareSource, isThisNodePicking]);
const updateCompareSplitByClientX = useCallback((clientX: number) => {
const frame = compareFrameRef.current;
if (!frame) return;
const rect = frame.getBoundingClientRect();
if (rect.width <= 0) return;
const rawPercent = ((clientX - rect.left) / rect.width) * 100;
setCompareSplitPercent(Math.max(0, Math.min(100, rawPercent)));
}, []);
useEffect(() => {
if (!isCompareMode) return;
@ -1589,6 +1601,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
<div className="relative w-full h-full">
{isCompareMode && hasCompareSource ? (
<div
ref={compareFrameRef}
className="relative h-full w-full overflow-hidden bg-muted/30 select-none cursor-col-resize"
style={{ touchAction: "none" }}
data-canvas-no-drag="true"
@ -1600,22 +1613,31 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
updateCompareSplitByClientX(event.clientX);
}}
>
<img
src={compareSource}
alt={`${displayTitle}-原图`}
className="absolute inset-0 h-full w-full object-contain"
draggable={false}
/>
<div
className="pointer-events-none absolute inset-0 overflow-hidden"
style={{
clipPath: `inset(0 ${100 - compareSplitPercent}% 0 0)`,
}}
>
<div className="absolute inset-0 bg-muted/30" />
<img
src={data.src}
alt={displayTitle}
className="absolute inset-0 h-full w-full object-contain"
draggable={false}
/>
</div>
<div
className="pointer-events-none absolute inset-0 overflow-hidden"
style={{
clipPath: `inset(0 0 0 ${compareSplitPercent}%)`,
}}
>
<div className="absolute inset-0 bg-muted/30" />
<img
src={data.src}
alt={displayTitle}
className="h-full w-full object-contain"
src={compareSource}
alt={`${displayTitle}-原图`}
className="absolute inset-0 h-full w-full object-contain"
draggable={false}
/>
</div>
@ -1631,10 +1653,10 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
&lt;&gt;
</div>
<div className="pointer-events-none absolute left-2 top-2 rounded bg-black/55 px-1.5 py-0.5 text-[10px] text-white">
原图
新图
</div>
<div className="pointer-events-none absolute right-2 top-2 rounded bg-black/55 px-1.5 py-0.5 text-[10px] text-white">
新图
原图
</div>
</div>
) : (