feat: 优化画布缩放交互 - 滚轮直接缩放,添加缩放控制按钮
This commit is contained in:
parent
ff5e78c5a9
commit
be6f22b3d6
@ -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,29 +114,31 @@ export function CanvasWorkspace() {
|
|||||||
|
|
||||||
// 处理滚轮缩放
|
// 处理滚轮缩放
|
||||||
const handleWheel = useCallback((e: React.WheelEvent) => {
|
const handleWheel = useCallback((e: React.WheelEvent) => {
|
||||||
if (e.ctrlKey || e.metaKey) {
|
e.preventDefault();
|
||||||
e.preventDefault();
|
|
||||||
const delta = e.deltaY > 0 ? 0.9 : 1.1;
|
|
||||||
const newZoom = Math.max(0.1, Math.min(4, viewport.zoom * delta));
|
|
||||||
|
|
||||||
// 以鼠标位置为中心缩放
|
// Shift + 滚轮 = 平移
|
||||||
const rect = containerRef.current?.getBoundingClientRect();
|
if (e.shiftKey) {
|
||||||
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 {
|
|
||||||
// 普通滚动平移
|
|
||||||
setViewport({
|
setViewport({
|
||||||
x: viewport.x - e.deltaX,
|
x: viewport.x - e.deltaY,
|
||||||
y: viewport.y - 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]);
|
}, [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">
|
||||||
{Math.round(viewport.zoom * 100)}%
|
<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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user