修复角度调整弹窗拖拽误触底层画布
This commit is contained in:
parent
2793582fd1
commit
67c18dd820
@ -39,6 +39,22 @@ export function AngleEditDialog({
|
|||||||
});
|
});
|
||||||
// 预览 Tab 状态:如果生成了结果,默认显示结果;否则显示原图
|
// 预览 Tab 状态:如果生成了结果,默认显示结果;否则显示原图
|
||||||
const [activeTab, setActiveTab] = useState<"original" | "result">("original");
|
const [activeTab, setActiveTab] = useState<"original" | "result">("original");
|
||||||
|
const stopDialogEventPropagation = useCallback((event: React.SyntheticEvent) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const stopDialogEventCapture = useCallback((event: React.SyntheticEvent) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const stopDialogWheelPropagation = useCallback((event: React.WheelEvent) => {
|
||||||
|
event.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const stopDialogWheelCapture = useCallback((event: React.WheelEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 当对话框关闭时重置状态
|
// 当对话框关闭时重置状态
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -173,6 +189,17 @@ export function AngleEditDialog({
|
|||||||
<Dialog open={open} onOpenChange={handleOpenChange}>
|
<Dialog open={open} onOpenChange={handleOpenChange}>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="max-w-4xl p-0 gap-0 overflow-hidden border-none shadow-2xl bg-background/95 backdrop-blur-xl"
|
className="max-w-4xl p-0 gap-0 overflow-hidden border-none shadow-2xl bg-background/95 backdrop-blur-xl"
|
||||||
|
onPointerDownCapture={stopDialogEventCapture}
|
||||||
|
onPointerMoveCapture={stopDialogEventCapture}
|
||||||
|
onPointerUpCapture={stopDialogEventCapture}
|
||||||
|
onMouseDown={stopDialogEventPropagation}
|
||||||
|
onMouseMove={stopDialogEventPropagation}
|
||||||
|
onMouseUp={stopDialogEventPropagation}
|
||||||
|
onTouchStart={stopDialogEventPropagation}
|
||||||
|
onTouchMove={stopDialogEventPropagation}
|
||||||
|
onTouchEnd={stopDialogEventPropagation}
|
||||||
|
onWheelCapture={stopDialogWheelCapture}
|
||||||
|
onWheel={stopDialogWheelPropagation}
|
||||||
onInteractOutside={(e) => {
|
onInteractOutside={(e) => {
|
||||||
// 阻止点击遮罩层关闭对话框(防止意外触发导航)
|
// 阻止点击遮罩层关闭对话框(防止意外触发导航)
|
||||||
if (isProcessing) {
|
if (isProcessing) {
|
||||||
@ -347,4 +374,3 @@ export function AngleEditDialog({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default AngleEditDialog;
|
export default AngleEditDialog;
|
||||||
|
|
||||||
|
|||||||
@ -171,15 +171,22 @@ export function CanvasWorkspace() {
|
|||||||
return !!target.closest("[data-canvas-node-id]");
|
return !!target.closest("[data-canvas-node-id]");
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const isEventFromCanvasContainer = useCallback((target: EventTarget | null) => {
|
||||||
|
if (!(target instanceof Node) || !containerRef.current) return false;
|
||||||
|
return containerRef.current.contains(target);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 处理画布点击(取消选择)
|
// 处理画布点击(取消选择)
|
||||||
const handleCanvasClick = useCallback((e: React.MouseEvent) => {
|
const handleCanvasClick = useCallback((e: React.MouseEvent) => {
|
||||||
|
if (!isEventFromCanvasContainer(e.target)) return;
|
||||||
if (!isPointOnNodeElement(e.target) && !isMarqueeSelecting) {
|
if (!isPointOnNodeElement(e.target) && !isMarqueeSelecting) {
|
||||||
clearSelection();
|
clearSelection();
|
||||||
}
|
}
|
||||||
}, [clearSelection, isMarqueeSelecting, isPointOnNodeElement]);
|
}, [clearSelection, isEventFromCanvasContainer, isMarqueeSelecting, isPointOnNodeElement]);
|
||||||
|
|
||||||
// 处理画布平移开始
|
// 处理画布平移开始
|
||||||
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
const handleMouseDown = useCallback((e: React.MouseEvent) => {
|
||||||
|
if (!isEventFromCanvasContainer(e.target)) return;
|
||||||
if (tool === 'pan' || e.button === 1 || (e.button === 0 && e.altKey)) {
|
if (tool === 'pan' || e.button === 1 || (e.button === 0 && e.altKey)) {
|
||||||
setIsPanning(true);
|
setIsPanning(true);
|
||||||
setPanStart({ x: e.clientX - viewport.x, y: e.clientY - viewport.y });
|
setPanStart({ x: e.clientX - viewport.x, y: e.clientY - viewport.y });
|
||||||
@ -193,10 +200,11 @@ export function CanvasWorkspace() {
|
|||||||
setMarqueeStart(start);
|
setMarqueeStart(start);
|
||||||
setMarqueeEnd(start);
|
setMarqueeEnd(start);
|
||||||
}
|
}
|
||||||
}, [isPointOnNodeElement, toCanvasPosition, tool, viewport]);
|
}, [isEventFromCanvasContainer, isPointOnNodeElement, toCanvasPosition, tool, viewport]);
|
||||||
|
|
||||||
// 处理画布平移
|
// 处理画布平移
|
||||||
const handleMouseMove = useCallback((e: React.MouseEvent) => {
|
const handleMouseMove = useCallback((e: React.MouseEvent) => {
|
||||||
|
if (!isEventFromCanvasContainer(e.target)) return;
|
||||||
dragPointerRef.current = toCanvasPosition(e.clientX, e.clientY);
|
dragPointerRef.current = toCanvasPosition(e.clientX, e.clientY);
|
||||||
if (isPanning) {
|
if (isPanning) {
|
||||||
setViewport({
|
setViewport({
|
||||||
@ -209,10 +217,11 @@ export function CanvasWorkspace() {
|
|||||||
if (isMarqueeSelecting) {
|
if (isMarqueeSelecting) {
|
||||||
setMarqueeEnd(toCanvasPosition(e.clientX, e.clientY));
|
setMarqueeEnd(toCanvasPosition(e.clientX, e.clientY));
|
||||||
}
|
}
|
||||||
}, [isMarqueeSelecting, isPanning, panStart, setViewport, toCanvasPosition]);
|
}, [isEventFromCanvasContainer, isMarqueeSelecting, isPanning, panStart, setViewport, toCanvasPosition]);
|
||||||
|
|
||||||
// 处理画布平移结束
|
// 处理画布平移结束
|
||||||
const handleMouseUp = useCallback(() => {
|
const handleMouseUp = useCallback((e?: React.MouseEvent) => {
|
||||||
|
if (e && !isEventFromCanvasContainer(e.target)) return;
|
||||||
setIsPanning(false);
|
setIsPanning(false);
|
||||||
|
|
||||||
if (isMarqueeSelecting && marqueeStart && marqueeEnd) {
|
if (isMarqueeSelecting && marqueeStart && marqueeEnd) {
|
||||||
@ -247,7 +256,7 @@ export function CanvasWorkspace() {
|
|||||||
setIsMarqueeSelecting(false);
|
setIsMarqueeSelecting(false);
|
||||||
setMarqueeStart(null);
|
setMarqueeStart(null);
|
||||||
setMarqueeEnd(null);
|
setMarqueeEnd(null);
|
||||||
}, [clearSelection, isMarqueeSelecting, marqueeEnd, marqueeStart, nodes, selectNodes, viewport.x, viewport.y, viewport.zoom]);
|
}, [clearSelection, isEventFromCanvasContainer, isMarqueeSelecting, marqueeEnd, marqueeStart, nodes, selectNodes, viewport.x, viewport.y, viewport.zoom]);
|
||||||
|
|
||||||
// 新增图片后自动居中展示
|
// 新增图片后自动居中展示
|
||||||
const centerNodeInView = useCallback((nodeId: string) => {
|
const centerNodeInView = useCallback((nodeId: string) => {
|
||||||
@ -284,6 +293,7 @@ export function CanvasWorkspace() {
|
|||||||
|
|
||||||
// 处理滚轮缩放
|
// 处理滚轮缩放
|
||||||
const handleWheel = useCallback((e: React.WheelEvent) => {
|
const handleWheel = useCallback((e: React.WheelEvent) => {
|
||||||
|
if (!isEventFromCanvasContainer(e.target)) return;
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
@ -308,7 +318,7 @@ export function CanvasWorkspace() {
|
|||||||
const newX = mouseX - (mouseX - viewport.x) * scaleChange;
|
const newX = mouseX - (mouseX - viewport.x) * scaleChange;
|
||||||
const newY = mouseY - (mouseY - viewport.y) * scaleChange;
|
const newY = mouseY - (mouseY - viewport.y) * scaleChange;
|
||||||
setViewport({ x: newX, y: newY, zoom: newZoom });
|
setViewport({ x: newX, y: newY, zoom: newZoom });
|
||||||
}, [isMacPlatform, setViewport, viewport.x, viewport.y, viewport.zoom]);
|
}, [isEventFromCanvasContainer, isMacPlatform, setViewport, viewport.x, viewport.y, viewport.zoom]);
|
||||||
|
|
||||||
const getImageDimensionsFromFile = useCallback((file: File): Promise<{
|
const getImageDimensionsFromFile = useCallback((file: File): Promise<{
|
||||||
width: number;
|
width: number;
|
||||||
|
|||||||
@ -421,6 +421,8 @@ export function QwenCameraWidget({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handlePointerDown = useCallback((event: React.MouseEvent | React.TouchEvent) => {
|
const handlePointerDown = useCallback((event: React.MouseEvent | React.TouchEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
if (!canvasRef.current || !cameraRef.current) return;
|
if (!canvasRef.current || !cameraRef.current) return;
|
||||||
|
|
||||||
const clientX = "touches" in event ? event.touches[0].clientX : event.clientX;
|
const clientX = "touches" in event ? event.touches[0].clientX : event.clientX;
|
||||||
@ -446,7 +448,9 @@ export function QwenCameraWidget({
|
|||||||
}, [getMousePos]);
|
}, [getMousePos]);
|
||||||
|
|
||||||
const handlePointerMove = useCallback((event: React.MouseEvent | React.TouchEvent) => {
|
const handlePointerMove = useCallback((event: React.MouseEvent | React.TouchEvent) => {
|
||||||
|
event.stopPropagation();
|
||||||
if (!canvasRef.current || !cameraRef.current || !isDraggingRef.current) return;
|
if (!canvasRef.current || !cameraRef.current || !isDraggingRef.current) return;
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
const clientX = "touches" in event ? event.touches[0].clientX : event.clientX;
|
const clientX = "touches" in event ? event.touches[0].clientX : event.clientX;
|
||||||
const clientY = "touches" in event ? event.touches[0].clientY : event.clientY;
|
const clientY = "touches" in event ? event.touches[0].clientY : event.clientY;
|
||||||
@ -496,7 +500,11 @@ export function QwenCameraWidget({
|
|||||||
}
|
}
|
||||||
}, [getMousePos, onStateChange]);
|
}, [getMousePos, onStateChange]);
|
||||||
|
|
||||||
const handlePointerUp = useCallback(() => {
|
const handlePointerUp = useCallback((event?: React.MouseEvent | React.TouchEvent) => {
|
||||||
|
if (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
isDraggingRef.current = false;
|
isDraggingRef.current = false;
|
||||||
dragTargetRef.current = null;
|
dragTargetRef.current = null;
|
||||||
if (canvasRef.current) {
|
if (canvasRef.current) {
|
||||||
@ -504,6 +512,11 @@ export function QwenCameraWidget({
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleWheel = useCallback((event: React.WheelEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
}, []);
|
||||||
|
|
||||||
// 下拉选择器变化处理
|
// 下拉选择器变化处理
|
||||||
const handleAzimuthChange = useCallback((value: string) => {
|
const handleAzimuthChange = useCallback((value: string) => {
|
||||||
const val = Number(value);
|
const val = Number(value);
|
||||||
@ -582,7 +595,7 @@ export function QwenCameraWidget({
|
|||||||
<div className="relative flex-1 min-h-0 bg-muted/20 rounded-lg overflow-hidden border">
|
<div className="relative flex-1 min-h-0 bg-muted/20 rounded-lg overflow-hidden border">
|
||||||
<canvas
|
<canvas
|
||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
className="w-full h-full block cursor-grab active:cursor-grabbing"
|
className="w-full h-full block cursor-grab active:cursor-grabbing touch-none select-none"
|
||||||
onMouseDown={handlePointerDown}
|
onMouseDown={handlePointerDown}
|
||||||
onMouseMove={handlePointerMove}
|
onMouseMove={handlePointerMove}
|
||||||
onMouseUp={handlePointerUp}
|
onMouseUp={handlePointerUp}
|
||||||
@ -590,6 +603,8 @@ export function QwenCameraWidget({
|
|||||||
onTouchStart={handlePointerDown}
|
onTouchStart={handlePointerDown}
|
||||||
onTouchMove={handlePointerMove}
|
onTouchMove={handlePointerMove}
|
||||||
onTouchEnd={handlePointerUp}
|
onTouchEnd={handlePointerUp}
|
||||||
|
onTouchCancel={handlePointerUp}
|
||||||
|
onWheel={handleWheel}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 提示词浮层 - 放在底部 */}
|
{/* 提示词浮层 - 放在底部 */}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user