Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions packages/dag/src/Canvas.vue
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ onMounted(() => {
onUnmounted(() => {
cleanupKeyboardShortcuts()
dataflowStore.unregisterVueFlowUpdateCallback()
if (locatedNodeHighlightTimer) {
clearTimeout(locatedNodeHighlightTimer)
locatedNodeHighlightTimer = null
}
leftPanelResizeObserver?.disconnect()
leftPanelMutationObserver?.disconnect()
rightPanelResizeObserver?.disconnect()
Expand Down Expand Up @@ -315,6 +319,8 @@ const ZOOM_STEP = 0.1
const MIN_ZOOM = 0.1
const MAX_ZOOM = 10
const ZOOM_PRESETS = [0.25, 0.5, 0.75, 1, 2]
const LOCATED_NODE_HIGHLIGHT_DURATION = 1800
let locatedNodeHighlightTimer: ReturnType<typeof setTimeout> | null = null

const zoomPercentage = computed(() => Math.round(viewport.value.zoom * 100))
const previousZoom = ref(1)
Expand Down Expand Up @@ -806,13 +812,25 @@ provide('clearDragHelperLines', () => {
helperLineVertical.value = undefined
})

function locateNode(nodeId: string) {
async function locateNode(nodeId: string) {
const node = vueFlow.findNode(nodeId)
if (!node) return
dataflowStore.locatedNodeId = ''
await nextTick()
dataflowStore.locatedNodeId = nodeId

if (locatedNodeHighlightTimer) clearTimeout(locatedNodeHighlightTimer)
locatedNodeHighlightTimer = setTimeout(() => {
if (dataflowStore.locatedNodeId === nodeId) {
dataflowStore.locatedNodeId = ''
}
locatedNodeHighlightTimer = null
}, LOCATED_NODE_HIGHLIGHT_DURATION)

fitViewWithOffset({
nodes: [nodeId],
duration: 300,
maxZoom: viewport.value.zoom,
maxZoom: 1,
})
}

Expand Down
2 changes: 1 addition & 1 deletion packages/dag/src/MonitorView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const taskRecord = ref({ total: 0, items: [] as any[] })
const timeFormat = ref('HH:mm:ss')
const nodeDetailDialog = ref(false)
const nodeDetailDialogId = ref('')
const canvasRef = ref<any>(null)
const { t } = useI18n()

const {
Expand All @@ -56,6 +55,7 @@ const {
formScope,
isSaving,
syncTypeLabel,
canvasRef,
taskOperationsRef,
consoleRef,
skipErrorRef,
Expand Down
86 changes: 86 additions & 0 deletions packages/dag/src/components/BaseNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,92 @@ $iconSize: 24px;
pointer-events: none;
}*/
}

.df-node-wrap.is-locating {
--canvas-node-locate-stroke: rgba(44, 101, 255, 0.64);
--canvas-node-locate-ring: rgba(44, 101, 255, 0.2);
--canvas-node-locate-glow: rgba(44, 101, 255, 0.16);

position: relative;
z-index: 9;

&::before,
&::after {
content: '';
position: absolute;
inset: -4px;
border-radius: 18px;
pointer-events: none;
}

&::before {
border: 1px solid var(--canvas-node-locate-stroke);
animation: canvas-node-locate-trace 1.8s cubic-bezier(0.16, 1, 0.3, 1);
}

&::after {
box-shadow:
0 0 0 0 var(--canvas-node-locate-ring),
0 10px 24px var(--canvas-node-locate-glow);
animation: canvas-node-locate-halo 1.8s cubic-bezier(0.16, 1, 0.3, 1);
}
}

html.dark .df-node-wrap.is-locating {
--canvas-node-locate-stroke: rgba(92, 140, 255, 0.72);
--canvas-node-locate-ring: rgba(92, 140, 255, 0.28);
--canvas-node-locate-glow: rgba(92, 140, 255, 0.24);
}

@keyframes canvas-node-locate-trace {
0% {
opacity: 0;
transform: scale(0.985);
}
14% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(1.035);
}
}

@keyframes canvas-node-locate-halo {
0% {
opacity: 0;
transform: scale(0.98);
}
16% {
opacity: 1;
}
68% {
opacity: 0.42;
}
100% {
opacity: 0;
transform: scale(1.055);
box-shadow:
0 0 0 14px rgba(44, 101, 255, 0),
0 10px 24px rgba(44, 101, 255, 0);
}
}

@media (prefers-reduced-motion: reduce) {
.df-node-wrap.is-locating {
&::before {
animation: none;
opacity: 1;
}

&::after {
animation: none;
box-shadow: 0 0 0 4px var(--canvas-node-locate-ring);
}
}
}

.df-menu-list {
margin: -6px;
.df-menu-item {
Expand Down
16 changes: 13 additions & 3 deletions packages/dag/src/components/elements/CanvasNode.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@ const hasNodeError = computed(() => store.getters['dataflow/hasNodeError'])
const ins = computed(() => props.data?.__Ctor || {})

const wrapClass = computed(() => {
if (dataflowStore.selectedNode?.id === props.data.id || props.selected)
return 'border-primary'
return ''
const list: string[] = []
if (dataflowStore.selectedNode?.id === props.data.id || props.selected) {
list.push('border-primary')
}
if (dataflowStore.locatedNodeId === props.data.id) {
list.push('is-locating')
}
return list
})

const nodeClass = computed(() => {
Expand Down Expand Up @@ -216,6 +221,11 @@ const canBeTarget = computed(() => {
.df-node-wrap {
z-index: 5;
outline: none;

&.is-locating {
z-index: 9;
}

&.can-be-connected {
.node-anchor.input {
display: flex;
Expand Down
10 changes: 8 additions & 2 deletions packages/dag/src/components/monitor/Node.vue
Original file line number Diff line number Diff line change
Expand Up @@ -420,8 +420,14 @@ const alarmCls = computed(() =>
)

const wrapClass = computed(() => {
if (dataflowStore.selectedNode?.id === props.data.id) return 'border-primary'
return ''
const list: string[] = []
if (dataflowStore.selectedNode?.id === props.data.id) {
list.push('border-primary')
}
if (dataflowStore.locatedNodeId === props.data.id) {
list.push('is-locating')
}
return list
})

const nodeClass = computed(() => {
Expand Down
3 changes: 3 additions & 0 deletions packages/dag/src/stores/dataflow.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ export const useDataflowStore = defineStore('dataflow', () => {
const pageVersion = ref(Date.now().toString())
const selectedNode = ref(null)
const selectedNodeId = ref(null)
const locatedNodeId = ref('')
const lastClickPosition = ref<[number, number]>([0, 0])
const stateIsReadonly = ref(false)
const showSettings = ref(false)
Expand Down Expand Up @@ -886,6 +887,7 @@ export const useDataflowStore = defineStore('dataflow', () => {
// UI / 交互状态归零
selectedNode.value = null
selectedNodeId.value = null
locatedNodeId.value = ''
stateIsReadonly.value = false
showSettings.value = false
showConsole.value = false
Expand Down Expand Up @@ -928,6 +930,7 @@ export const useDataflowStore = defineStore('dataflow', () => {
patchDataflowDebounce,
processorNodeTypes,
selectedNode,
locatedNodeId,
lastClickPosition,
stateIsReadonly,
taskSaving,
Expand Down
Loading