Skip to content

Commit a23235b

Browse files
authored
Merge pull request #539 from tapdata/feat/TAP-10595-dag
feat: implement node focus functionality to ensure selected nodes are…
2 parents 156dd4e + 8bc9dc7 commit a23235b

File tree

4 files changed

+82
-1
lines changed

4 files changed

+82
-1
lines changed

packages/dag/src/EditorView.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ function onClipboardPaste(plainTextData: string) {
139139
140140
watch([() => dag.value.nodes.length, () => dag.value.edges.length], () => {
141141
if (isInitialized.value) {
142-
dataflowStore.patchDataflowDebounce()
142+
dataflowStore.patchDataflow()
143143
}
144144
})
145145

packages/dag/src/components/NodesPanel.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { debounce, escapeRegExp } from 'lodash-es'
99
import { computed, inject, nextTick, reactive, ref, shallowRef } from 'vue'
1010
import { useCreateTable } from '../composables/useCreateTable'
1111
import { makeNode, makeProcessorNode, useDnD } from '../composables/useDnD'
12+
import { useNodeFocus } from '../composables/useNodeFocus'
1213
import { useDataflowStore } from '../stores/dataflow.store'
1314
import { useHistoryStore } from '../stores/history.store'
1415
import BaseNode from './BaseNode.vue'
@@ -251,6 +252,8 @@ useI18n()
251252
const { findNode, getOutgoers, screenToFlowCoordinate, viewportRef } =
252253
useVueFlow()
253254
255+
const { focusNode } = useNodeFocus()
256+
254257
const historyStore = useHistoryStore()
255258
256259
const X_OFFSET = 100
@@ -434,6 +437,9 @@ const handleDblClickAddNode = (node: any) => {
434437
}
435438
436439
historyStore.stopRecordingUndo()
440+
441+
// 选中新添加的节点并确保可见
442+
focusNode(node.id)
437443
}
438444
439445
const handleDblClickConnection = (item: any) => {

packages/dag/src/components/elements/NodesPopover.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { computed, inject, onBeforeUnmount, ref, watch, type Ref } from 'vue'
77
import { useCreateTable } from '../../composables/useCreateTable'
88
import { makeNode, makeProcessorNode } from '../../composables/useDnD'
99
import { useFetchConnections } from '../../composables/useFetchConnections'
10+
import { useNodeFocus } from '../../composables/useNodeFocus'
1011
import { useDataflowStore } from '../../stores/dataflow.store'
1112
import { useHistoryStore } from '../../stores/history.store'
1213
import ConnectionType from '../ConnectionType.vue'
@@ -24,6 +25,7 @@ const Y_OFFSET = 40
2425
const props = defineProps<Props>()
2526
2627
const { findNode, getOutgoers, getIncomers } = useVueFlow()
28+
const { focusNode } = useNodeFocus()
2729
2830
const { t } = useI18n()
2931
@@ -237,6 +239,7 @@ const handleAddNode = (node: any) => {
237239
})
238240
239241
historyStore.stopRecordingUndo()
242+
focusNode(node.id)
240243
return
241244
} else if (prevNodeId && !nextNodeId) {
242245
// 在节点后面添加
@@ -308,6 +311,7 @@ const handleAddNode = (node: any) => {
308311
}
309312
310313
historyStore.stopRecordingUndo()
314+
focusNode(node.id)
311315
}
312316
313317
const onClickConnection = (item: any) => {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { useVueFlow } from '@vue-flow/core'
2+
import { watch } from 'vue'
3+
import { useDataflowStore } from '../stores/dataflow.store'
4+
5+
/**
6+
* 提供 focusNode 方法:选中指定节点并确保其在视口中可见。
7+
*
8+
* 内部会等待 VueFlow 完成节点 DOM 渲染和尺寸测量后,
9+
* 再执行选中 + fitView,避免 nextTick / setTimeout 的时序问题。
10+
*/
11+
export function useNodeFocus() {
12+
const {
13+
findNode,
14+
addSelectedNodes,
15+
removeSelectedNodes,
16+
getNodes,
17+
fitView,
18+
viewport,
19+
} = useVueFlow()
20+
21+
const dataflowStore = useDataflowStore()
22+
23+
/**
24+
* 选中节点并平移视口使其可见
25+
* @param nodeId 要聚焦的节点 ID
26+
*/
27+
function focusNode(nodeId: string) {
28+
// store 级别选中(打开右侧设置面板),不依赖尺寸,立即执行
29+
dataflowStore.selectNodeById(nodeId)
30+
31+
const graphNode = findNode(nodeId)
32+
33+
// 如果节点已经在 VueFlow 中且尺寸已测量完毕,直接执行
34+
if (graphNode && graphNode.dimensions?.width > 0) {
35+
removeSelectedNodes(getNodes.value)
36+
addSelectedNodes([graphNode])
37+
fitView({
38+
nodes: [nodeId],
39+
duration: 200,
40+
maxZoom: viewport.value.zoom,
41+
padding: 0.2,
42+
})
43+
return
44+
}
45+
46+
// 否则等待 VueFlow 测量完节点尺寸后再执行
47+
const stop = watch(
48+
() => findNode(nodeId)?.dimensions?.width,
49+
(width) => {
50+
if (width && width > 0) {
51+
stop()
52+
const node = findNode(nodeId)
53+
if (node) {
54+
removeSelectedNodes(getNodes.value)
55+
addSelectedNodes([node])
56+
}
57+
fitView({
58+
nodes: [nodeId],
59+
duration: 200,
60+
maxZoom: viewport.value.zoom,
61+
padding: 0.2,
62+
})
63+
}
64+
},
65+
{ flush: 'post' },
66+
)
67+
}
68+
69+
return { focusNode }
70+
}
71+

0 commit comments

Comments
 (0)