Browse Source

层级问题处理

feature/071
yun 1 week ago
parent
commit
60e8686a6f
  1. 99
      src/components/WorkflowCanvas.tsx

99
src/components/WorkflowCanvas.tsx

@ -98,7 +98,8 @@ const BOX_SELECTION_EXPAND_MIN_DISTANCE = 4;
const MULTI_SELECTION_BOUNDS_PADDING = 40; const MULTI_SELECTION_BOUNDS_PADDING = 40;
const GROUP_NODE_Z_INDEX = 0; const GROUP_NODE_Z_INDEX = 0;
const DEFAULT_NODE_Z_INDEX = 1; const DEFAULT_NODE_Z_INDEX = 1;
const INITIAL_ACTIVE_NODE_Z_INDEX = 100; const INITIAL_TOP_STACK_Z_INDEX = 100;
const INITIAL_TOP_MEMBER_Z_INDEX = 1;
type ScreenPoint = { type ScreenPoint = {
x: number; x: number;
@ -572,10 +573,10 @@ export function WorkflowCanvas() {
const [isMiniMapOpen, setIsMiniMapOpen] = useState(false); const [isMiniMapOpen, setIsMiniMapOpen] = useState(false);
const [zoomPercent, setZoomPercent] = useState(100); const [zoomPercent, setZoomPercent] = useState(100);
const [draggingGroupId, setDraggingGroupId] = useState<string | null>(null); const [draggingGroupId, setDraggingGroupId] = useState<string | null>(null);
const [activeNodeLayer, setActiveNodeLayer] = useState<{ nodeId: string | null; zIndex: number }>({ const [stackLayerMap, setStackLayerMap] = useState<Record<string, number>>({});
nodeId: null, const [memberLayerMap, setMemberLayerMap] = useState<Record<string, number>>({});
zIndex: INITIAL_ACTIVE_NODE_Z_INDEX, const [topStackLayer, setTopStackLayer] = useState(INITIAL_TOP_STACK_Z_INDEX);
}); const topMemberLayerRef = useRef(INITIAL_TOP_MEMBER_Z_INDEX);
const canvasGridColor = "var(--canvas-grid)"; const canvasGridColor = "var(--canvas-grid)";
const miniMapMaskColor = "var(--surface-overlay)"; const miniMapMaskColor = "var(--surface-overlay)";
const miniMapNodeColor = "var(--text-disabled)"; const miniMapNodeColor = "var(--text-disabled)";
@ -588,18 +589,39 @@ export function WorkflowCanvas() {
const gestureZoomStartRef = useRef<{ zoom: number } | null>(null); const gestureZoomStartRef = useRef<{ zoom: number } | null>(null);
const [boxSelectionRect, setBoxSelectionRect] = useState<FlowRect | null>(null); const [boxSelectionRect, setBoxSelectionRect] = useState<FlowRect | null>(null);
const bringNodeToFront = useCallback((nodeId: string) => { const bringNodeToFront = useCallback((node: Node) => {
setActiveNodeLayer((current) => ({ const nodeGroupId = node.type === "group"
nodeId, ? (node.data as { groupId?: string }).groupId
zIndex: current.zIndex + 1, : (node as Node & { groupId?: string }).groupId;
})); const groupNodeId = nodeGroupId ? `group-node-${nodeGroupId}` : null;
}, []);
if (node.type !== "group" && nodeGroupId && groupNodeId) {
topMemberLayerRef.current += 1;
const nextMemberLayer = topMemberLayerRef.current;
setMemberLayerMap((layers) => ({
...layers,
[node.id]: nextMemberLayer,
}));
setTopStackLayer((current) => {
const nextStackLayer = current + 1;
setStackLayerMap((layers) => ({
...layers,
[groupNodeId]: nextStackLayer,
}));
return nextStackLayer;
});
return;
}
const resetActiveNodeLayer = useCallback(() => { setTopStackLayer((current) => {
setActiveNodeLayer((current) => ({ const nextStackLayer = current + 1;
...current, setStackLayerMap((layers) => ({
nodeId: null, ...layers,
})); [node.id]: nextStackLayer,
}));
return nextStackLayer;
});
}, []); }, []);
const onNodesChange = useCallback((changes: NodeChange<WorkflowNode>[]) => { const onNodesChange = useCallback((changes: NodeChange<WorkflowNode>[]) => {
@ -893,13 +915,15 @@ export function WorkflowCanvas() {
// Apply visual state that React Flow can turn into DOM classes and z-index. // Apply visual state that React Flow can turn into DOM classes and z-index.
const allNodes = useMemo(() => { const allNodes = useMemo(() => {
const draggingGroupNodeId = draggingGroupId ? `group-node-${draggingGroupId}` : null; const draggingGroupNodeId = draggingGroupId ? `group-node-${draggingGroupId}` : null;
const activeNode = activeNodeLayer.nodeId const groupStackLayerById = new Map<string, number>();
? nodes.find((node) => node.id === activeNodeLayer.nodeId) for (const node of nodes) {
: undefined; if (node.type !== "group") continue;
const activeGroupId = activeNode?.type === "group" const groupId = (node.data as { groupId?: string }).groupId;
? (activeNode.data as { groupId?: string }).groupId const stackLayer = stackLayerMap[node.id];
: undefined; if (groupId && stackLayer !== undefined) {
const activeGroupNodeId = activeGroupId ? `group-node-${activeGroupId}` : null; groupStackLayerById.set(groupId, stackLayer);
}
}
return nodes.map((node) => { return nodes.map((node) => {
// Never dim Switch or ConditionalSwitch nodes themselves // Never dim Switch or ConditionalSwitch nodes themselves
@ -919,29 +943,27 @@ export function WorkflowCanvas() {
// Preserve existing className if any, add/remove dimmed/skipped classes // Preserve existing className if any, add/remove dimmed/skipped classes
const baseClass = (node.className || "").replace(/\bswitch-dimmed\b/g, "").replace(/\bnode-skipped\b/g, "").trim(); const baseClass = (node.className || "").replace(/\bswitch-dimmed\b/g, "").replace(/\bnode-skipped\b/g, "").trim();
const newClass = extraClasses ? `${baseClass} ${extraClasses}`.trim() : baseClass; const newClass = extraClasses ? `${baseClass} ${extraClasses}`.trim() : baseClass;
let zIndex = node.type === "group" ? GROUP_NODE_Z_INDEX : DEFAULT_NODE_Z_INDEX; const nodeGroupId = (node as Node & { groupId?: string }).groupId;
const groupStackLayer = nodeGroupId ? groupStackLayerById.get(nodeGroupId) : undefined;
if (activeGroupId && node.id === activeGroupNodeId) { let zIndex = node.type === "group"
zIndex = activeNodeLayer.zIndex; ? stackLayerMap[node.id] ?? GROUP_NODE_Z_INDEX
} else if (activeGroupId && node.type !== "group" && (node.groupId === activeGroupId || node.parentId === activeGroupNodeId)) { : nodeGroupId && groupStackLayer !== undefined
zIndex = activeNodeLayer.zIndex + 1; ? groupStackLayer + (memberLayerMap[node.id] ?? DEFAULT_NODE_Z_INDEX)
} else if (!activeGroupId && node.id === activeNodeLayer.nodeId) { : stackLayerMap[node.id] ?? DEFAULT_NODE_Z_INDEX;
zIndex = activeNodeLayer.zIndex;
}
if (isDraggingGroupShell) { if (isDraggingGroupShell) {
zIndex = Math.max(zIndex, activeNodeLayer.zIndex); zIndex = Math.max(zIndex, topStackLayer);
} else if (isDraggingGroupMember) { } else if (isDraggingGroupMember) {
zIndex = Math.max(zIndex, activeNodeLayer.zIndex + 1); zIndex = Math.max(zIndex, topStackLayer + (memberLayerMap[node.id] ?? DEFAULT_NODE_Z_INDEX));
} else if (node.dragging) { } else if (node.dragging) {
zIndex = Math.max(zIndex, activeNodeLayer.zIndex + 1); zIndex = Math.max(zIndex, topStackLayer + 1);
} }
// Only create new node object if className changed // Only create new node object if className changed
if (node.className === newClass && node.zIndex === zIndex) return node; if (node.className === newClass && node.zIndex === zIndex) return node;
return { ...node, className: newClass, zIndex }; return { ...node, className: newClass, zIndex };
}); });
}, [nodes, activeNodeLayer, dimmedNodeIds, draggingGroupId, skippedNodeIds]); }, [nodes, dimmedNodeIds, draggingGroupId, memberLayerMap, skippedNodeIds, stackLayerMap, topStackLayer]);
const absoluteNodePositions = useMemo(() => { const absoluteNodePositions = useMemo(() => {
const byId = new Map(allNodes.map((node) => [node.id, node])); const byId = new Map(allNodes.map((node) => [node.id, node]));
@ -3078,12 +3100,12 @@ export function WorkflowCanvas() {
onMoveStart={() => { isPanningRef.current = true; setHoveredNodeId(null); document.documentElement.classList.add("canvas-interacting"); }} onMoveStart={() => { isPanningRef.current = true; setHoveredNodeId(null); document.documentElement.classList.add("canvas-interacting"); }}
onMoveEnd={() => { isPanningRef.current = false; document.documentElement.classList.remove("canvas-interacting"); syncZoomPercent(); }} onMoveEnd={() => { isPanningRef.current = false; document.documentElement.classList.remove("canvas-interacting"); syncZoomPercent(); }}
onNodeClick={(_event, node) => { onNodeClick={(_event, node) => {
bringNodeToFront(node.id); bringNodeToFront(node);
}} }}
onNodeDragStart={(_event, node) => { onNodeDragStart={(_event, node) => {
isDraggingNodeRef.current = true; isDraggingNodeRef.current = true;
document.documentElement.classList.add("canvas-interacting"); document.documentElement.classList.add("canvas-interacting");
bringNodeToFront(node.id); bringNodeToFront(node);
setDraggingGroupId(node.type === "group" ? (node.data as { groupId?: string }).groupId ?? null : null); setDraggingGroupId(node.type === "group" ? (node.data as { groupId?: string }).groupId ?? null : null);
}} }}
onNodeDragStop={(event, node) => { onNodeDragStop={(event, node) => {
@ -3092,7 +3114,6 @@ export function WorkflowCanvas() {
setDraggingGroupId(null); setDraggingGroupId(null);
handleNodeDragStop(event, node); handleNodeDragStop(event, node);
}} }}
onPaneClick={resetActiveNodeLayer}
onPaneContextMenu={openCanvasContextMenu} onPaneContextMenu={openCanvasContextMenu}
onNodeContextMenu={openNodeContextMenu} onNodeContextMenu={openNodeContextMenu}
onSelectionStart={handleSelectionStart} onSelectionStart={handleSelectionStart}

Loading…
Cancel
Save