feat: 优化画布缩放交互 - 滚轮直接缩放,添加缩放控制按钮

This commit is contained in:
Your Name 2026-02-03 10:19:10 +08:00
parent ff5e78c5a9
commit be6f22b3d6

View File

@ -9,6 +9,8 @@ import { ImageNode } from "./nodes/ImageNode";
import { TextNode } from "./nodes/TextNode"; import { TextNode } from "./nodes/TextNode";
import { VideoNode } from "./nodes/VideoNode"; import { VideoNode } from "./nodes/VideoNode";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Minus, Plus } from "lucide-react";
// 性能优化:判断节点是否在视口内 // 性能优化:判断节点是否在视口内
function isNodeInViewport( function isNodeInViewport(
@ -112,12 +114,21 @@ export function CanvasWorkspace() {
// 处理滚轮缩放 // 处理滚轮缩放
const handleWheel = useCallback((e: React.WheelEvent) => { const handleWheel = useCallback((e: React.WheelEvent) => {
if (e.ctrlKey || e.metaKey) {
e.preventDefault(); e.preventDefault();
// Shift + 滚轮 = 平移
if (e.shiftKey) {
setViewport({
x: viewport.x - e.deltaY,
y: viewport.y - e.deltaX,
});
return;
}
// 默认滚轮 = 缩放(以鼠标位置为中心)
const delta = e.deltaY > 0 ? 0.9 : 1.1; const delta = e.deltaY > 0 ? 0.9 : 1.1;
const newZoom = Math.max(0.1, Math.min(4, viewport.zoom * delta)); const newZoom = Math.max(0.1, Math.min(4, viewport.zoom * delta));
// 以鼠标位置为中心缩放
const rect = containerRef.current?.getBoundingClientRect(); const rect = containerRef.current?.getBoundingClientRect();
if (rect) { if (rect) {
const mouseX = e.clientX - rect.left; const mouseX = e.clientX - rect.left;
@ -129,13 +140,6 @@ export function CanvasWorkspace() {
setViewport({ x: newX, y: newY, zoom: newZoom }); setViewport({ x: newX, y: newY, zoom: newZoom });
} }
} else {
// 普通滚动平移
setViewport({
x: viewport.x - e.deltaX,
y: viewport.y - e.deltaY,
});
}
}, [viewport, setViewport]); }, [viewport, setViewport]);
// 渲染节点 // 渲染节点
@ -267,9 +271,41 @@ export function CanvasWorkspace() {
</div> </div>
)} )}
{/* 缩放指示器 */} {/* 缩放控制器 */}
<div className="absolute bottom-4 right-4 bg-background/80 backdrop-blur-sm rounded-md px-3 py-1.5 text-xs text-muted-foreground"> <div className="absolute bottom-4 right-4 bg-background/80 backdrop-blur-sm rounded-lg flex items-center gap-1 px-1 py-1 shadow-sm border border-border/50">
<Button
variant="ghost"
size="icon"
className="h-7 w-7"
onClick={() => {
const newZoom = Math.max(0.1, viewport.zoom - 0.1);
setViewport({ zoom: newZoom });
}}
title="缩小"
>
<Minus className="h-3.5 w-3.5" />
</Button>
<Button
variant="ghost"
size="sm"
className="h-7 min-w-[50px] text-xs font-medium"
onClick={() => setViewport({ zoom: 1, x: 0, y: 0 })}
title="重置缩放"
>
{Math.round(viewport.zoom * 100)}% {Math.round(viewport.zoom * 100)}%
</Button>
<Button
variant="ghost"
size="icon"
className="h-7 w-7"
onClick={() => {
const newZoom = Math.min(4, viewport.zoom + 0.1);
setViewport({ zoom: newZoom });
}}
title="放大"
>
<Plus className="h-3.5 w-3.5" />
</Button>
</div> </div>
</div> </div>
); );