feat: 画布点阵背景固定大小不随缩放变化,图片双击放大预览
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-02-02 12:34:13 +08:00
parent 84726009ff
commit e314edb283
2 changed files with 45 additions and 10 deletions

View File

@ -228,22 +228,20 @@ export function CanvasWorkspace() {
onMouseLeave={handleMouseUp}
onWheel={handleWheel}
>
{/* 点阵背景 - 浅色模式 */}
{/* 点阵背景 - 浅色模式(固定大小,不随缩放变化) */}
<div
className="absolute inset-0 pointer-events-none dark:hidden"
style={{
backgroundImage: `radial-gradient(rgba(0,0,0,0.1) 1px, transparent 1px)`,
backgroundSize: `${20 * viewport.zoom}px ${20 * viewport.zoom}px`,
backgroundPosition: `${viewport.x}px ${viewport.y}px`,
backgroundImage: `radial-gradient(rgba(0,0,0,0.08) 1px, transparent 1px)`,
backgroundSize: `20px 20px`,
}}
/>
{/* 深色模式点阵 */}
{/* 深色模式点阵(固定大小,不随缩放变化) */}
<div
className="absolute inset-0 pointer-events-none hidden dark:block"
style={{
backgroundImage: `radial-gradient(rgba(255,255,255,0.05) 1px, transparent 1px)`,
backgroundSize: `${20 * viewport.zoom}px ${20 * viewport.zoom}px`,
backgroundPosition: `${viewport.x}px ${viewport.y}px`,
backgroundImage: `radial-gradient(rgba(255,255,255,0.04) 1px, transparent 1px)`,
backgroundSize: `20px 20px`,
}}
/>

View File

@ -46,6 +46,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
const [resizeHeight, setResizeHeight] = useState(1024);
const [isUploading, setIsUploading] = useState(false);
const [annotatorOpen, setAnnotatorOpen] = useState(false);
const [fullscreenPreviewOpen, setFullscreenPreviewOpen] = useState(false);
// 文件输入的 ref
const fileInputRef = useRef<HTMLInputElement>(null);
@ -417,13 +418,17 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{/* 图片内容 - 使用 object-contain 保持原始比例 */}
{/* 图片内容 - 使用 object-contain 保持原始比例,双击可放大查看 */}
{data.src ? (
<img
src={data.src}
alt={data.prompt || "图片"}
className="w-full h-full object-contain bg-muted/30"
className="w-full h-full object-contain bg-muted/30 cursor-pointer"
draggable={false}
onDoubleClick={(e) => {
e.stopPropagation();
setFullscreenPreviewOpen(true);
}}
/>
) : data.status === 'generating' ? (
<div className="w-full h-full flex flex-col items-center justify-center bg-muted">
@ -797,6 +802,38 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
onCancel={() => setAnnotatorOpen(false)}
/>
)}
{/* 双击放大预览弹窗 */}
{fullscreenPreviewOpen && data.src && createPortal(
<div
className="fixed inset-0 z-[9999] bg-black/90 flex items-center justify-center cursor-zoom-out"
onClick={() => setFullscreenPreviewOpen(false)}
>
{/* 关闭按钮 */}
<button
className="absolute top-4 right-4 p-2 rounded-full bg-white/10 hover:bg-white/20 transition-colors"
onClick={() => setFullscreenPreviewOpen(false)}
>
<svg className="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
{/* 图片 */}
<img
src={data.src}
alt={data.prompt || "图片预览"}
className="max-w-[95vw] max-h-[95vh] object-contain"
onClick={(e) => e.stopPropagation()}
/>
{/* 底部提示 */}
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 text-white/60 text-sm">
点击任意位置关闭
</div>
</div>,
document.body
)}
</>
);
}