|
@@ -406,8 +406,10 @@ function showLockButton(nodeEl, immediate = false) {
|
|
|
|
|
|
|
|
// 创建按钮的函数
|
|
// 创建按钮的函数
|
|
|
const createBtn = () => {
|
|
const createBtn = () => {
|
|
|
- // 先清除其他节点的按钮
|
|
|
|
|
- d3.selectAll('.lock-btn').remove()
|
|
|
|
|
|
|
+ // 先清除当前 SVG 内其他节点的按钮(不影响另一边)
|
|
|
|
|
+ if (svgRef.value) {
|
|
|
|
|
+ d3.select(svgRef.value).selectAll('.lock-btn').remove()
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
const isLocked = !!store.lockedHoverNodeId
|
|
const isLocked = !!store.lockedHoverNodeId
|
|
|
|
|
|
|
@@ -470,7 +472,10 @@ function hideLockButton() {
|
|
|
clearTimeout(showButtonTimer)
|
|
clearTimeout(showButtonTimer)
|
|
|
showButtonTimer = null
|
|
showButtonTimer = null
|
|
|
}
|
|
}
|
|
|
- d3.selectAll('.lock-btn').interrupt().remove()
|
|
|
|
|
|
|
+ // 只清除当前 SVG 内的按钮
|
|
|
|
|
+ if (svgRef.value) {
|
|
|
|
|
+ d3.select(svgRef.value).selectAll('.lock-btn').interrupt().remove()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 处理锁定按钮点击
|
|
// 处理锁定按钮点击
|
|
@@ -478,15 +483,15 @@ function handleLockClick() {
|
|
|
const startNodeId = store.selectedNodeId
|
|
const startNodeId = store.selectedNodeId
|
|
|
if (store.lockedHoverNodeId) {
|
|
if (store.lockedHoverNodeId) {
|
|
|
store.clearLockedHover()
|
|
store.clearLockedHover()
|
|
|
- hideLockButton()
|
|
|
|
|
|
|
+ // 清除所有锁定按钮(两边都清除)
|
|
|
|
|
+ d3.selectAll('.lock-btn').interrupt().remove()
|
|
|
} else if (startNodeId) {
|
|
} else if (startNodeId) {
|
|
|
store.lockCurrentHover(startNodeId)
|
|
store.lockCurrentHover(startNodeId)
|
|
|
- const btn = d3.select('.lock-btn')
|
|
|
|
|
- if (!btn.empty()) {
|
|
|
|
|
- btn.interrupt()
|
|
|
|
|
- .text(' 🔓解锁')
|
|
|
|
|
- .attr('fill', '#f6ad55')
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 更新所有锁定按钮状态(两边同步)
|
|
|
|
|
+ d3.selectAll('.lock-btn')
|
|
|
|
|
+ .interrupt()
|
|
|
|
|
+ .text(' 🔓解锁')
|
|
|
|
|
+ .attr('fill', '#f6ad55')
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -503,6 +508,23 @@ function updateHighlight() {
|
|
|
applyHighlight(svgRef.value, store.highlightedNodeIds, edgeSet, store.selectedNodeId)
|
|
applyHighlight(svgRef.value, store.highlightedNodeIds, edgeSet, store.selectedNodeId)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 恢复锁定的 hover 状态(重新渲染后调用)
|
|
|
|
|
+function restoreLockedHover() {
|
|
|
|
|
+ if (!store.lockedHoverNodeId || !graphNodeSelection) return
|
|
|
|
|
+
|
|
|
|
|
+ // 恢复高亮效果
|
|
|
|
|
+ if (store.hoverPathNodes.size > 0) {
|
|
|
|
|
+ applyHoverHighlight(graphNodeSelection, graphLinkSelection, graphLinkLabelSelection, store.hoverPathNodes)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 恢复锁定按钮:找到锁定节点的 DOM 元素
|
|
|
|
|
+ graphNodeSelection.each(function(d) {
|
|
|
|
|
+ if (d.id === store.lockedHoverNodeId) {
|
|
|
|
|
+ showLockButton(this, true)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// 监听高亮变化(walkedEdges 或 postWalkedEdges 变化时重新渲染)
|
|
// 监听高亮变化(walkedEdges 或 postWalkedEdges 变化时重新渲染)
|
|
|
watch([() => store.walkedEdges.length, () => store.postWalkedEdges.length], () => {
|
|
watch([() => store.walkedEdges.length, () => store.postWalkedEdges.length], () => {
|
|
|
nextTick(renderGraph)
|
|
nextTick(renderGraph)
|
|
@@ -518,20 +540,33 @@ watch(() => store.selectedEdgeId, () => {
|
|
|
watch(() => store.highlightedNodeIds.size, updateHighlight)
|
|
watch(() => store.highlightedNodeIds.size, updateHighlight)
|
|
|
|
|
|
|
|
// 监听 hover 状态变化(用于左右联动)
|
|
// 监听 hover 状态变化(用于左右联动)
|
|
|
-watch(() => store.hoverPathNodes.size, () => {
|
|
|
|
|
|
|
+watch([() => store.hoverPathNodes.size, () => store.hoverNodeId], () => {
|
|
|
if (!graphNodeSelection || !graphLinkSelection) return
|
|
if (!graphNodeSelection || !graphLinkSelection) return
|
|
|
|
|
|
|
|
if (store.hoverPathNodes.size > 0) {
|
|
if (store.hoverPathNodes.size > 0) {
|
|
|
// 应用 hover 高亮
|
|
// 应用 hover 高亮
|
|
|
applyHoverHighlight(graphNodeSelection, graphLinkSelection, graphLinkLabelSelection, store.hoverPathNodes)
|
|
applyHoverHighlight(graphNodeSelection, graphLinkSelection, graphLinkLabelSelection, store.hoverPathNodes)
|
|
|
|
|
|
|
|
- // 如果是从 PostTreeView 触发的,缩放到显示完整路径
|
|
|
|
|
|
|
+ // 如果是从 PostTreeView 触发的,缩放到显示完整路径,并显示锁定按钮
|
|
|
if (store.hoverSource === 'post-tree') {
|
|
if (store.hoverSource === 'post-tree') {
|
|
|
zoomToPathNodes(store.hoverPathNodes)
|
|
zoomToPathNodes(store.hoverPathNodes)
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // 在对应节点上显示锁定按钮(无论来源)
|
|
|
|
|
+ if (store.hoverNodeId) {
|
|
|
|
|
+ graphNodeSelection.each(function(d) {
|
|
|
|
|
+ if (d.id === store.hoverNodeId) {
|
|
|
|
|
+ showLockButton(this)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
} else {
|
|
} else {
|
|
|
// 清除 hover,恢复原有高亮
|
|
// 清除 hover,恢复原有高亮
|
|
|
clearHoverHighlight(graphNodeSelection, graphLinkSelection, graphLinkLabelSelection)
|
|
clearHoverHighlight(graphNodeSelection, graphLinkSelection, graphLinkLabelSelection)
|
|
|
|
|
+ // 如果没有锁定,隐藏按钮
|
|
|
|
|
+ if (!store.lockedHoverNodeId) {
|
|
|
|
|
+ hideLockButton()
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -595,6 +630,10 @@ function handleTransitionEnd(e) {
|
|
|
if ((store.selectedNodeId || store.selectedEdgeId) && svgRef.value) {
|
|
if ((store.selectedNodeId || store.selectedEdgeId) && svgRef.value) {
|
|
|
renderGraph()
|
|
renderGraph()
|
|
|
svgRef.value.style.opacity = '1'
|
|
svgRef.value.style.opacity = '1'
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ updateHighlight()
|
|
|
|
|
+ restoreLockedHover() // 恢复锁定的 hover 状态
|
|
|
|
|
+ })
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|