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 { VideoNode } from "./nodes/VideoNode";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Minus, Plus } from "lucide-react";
// 性能优化:判断节点是否在视口内
function isNodeInViewport(
@ -112,29 +114,31 @@ export function CanvasWorkspace() {
// 处理滚轮缩放
const handleWheel = useCallback((e: React.WheelEvent) => {
if (e.ctrlKey || e.metaKey) {
e.preventDefault();
const delta = e.deltaY > 0 ? 0.9 : 1.1;
const newZoom = Math.max(0.1, Math.min(4, viewport.zoom * delta));
// 以鼠标位置为中心缩放
const rect = containerRef.current?.getBoundingClientRect();
if (rect) {
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const scaleChange = newZoom / viewport.zoom;
const newX = mouseX - (mouseX - viewport.x) * scaleChange;
const newY = mouseY - (mouseY - viewport.y) * scaleChange;
setViewport({ x: newX, y: newY, zoom: newZoom });
}
} else {
// 普通滚动平移
e.preventDefault();
// Shift + 滚轮 = 平移
if (e.shiftKey) {
setViewport({
x: viewport.x - e.deltaX,
y: viewport.y - e.deltaY,
x: viewport.x - e.deltaY,
y: viewport.y - e.deltaX,
});
return;
}
// 默认滚轮 = 缩放(以鼠标位置为中心)
const delta = e.deltaY > 0 ? 0.9 : 1.1;
const newZoom = Math.max(0.1, Math.min(4, viewport.zoom * delta));
const rect = containerRef.current?.getBoundingClientRect();
if (rect) {
const mouseX = e.clientX - rect.left;
const mouseY = e.clientY - rect.top;
const scaleChange = newZoom / viewport.zoom;
const newX = mouseX - (mouseX - viewport.x) * scaleChange;
const newY = mouseY - (mouseY - viewport.y) * scaleChange;
setViewport({ x: newX, y: newY, zoom: newZoom });
}
}, [viewport, setViewport]);
@ -267,9 +271,41 @@ export function CanvasWorkspace() {
</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">
{Math.round(viewport.zoom * 100)}%
{/* 缩放控制器 */}
<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)}%
</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>
);