From 085aa6bbe6f312bb1bb9395350f1d5fb54206e44 Mon Sep 17 00:00:00 2001 From: 666ghj <670939375@qq.com> Date: Sun, 18 Jan 2026 22:34:40 +0800 Subject: [PATCH] fix(GraphPanel): optimize force graph drag behavior to prevent simulation restart on click Background: - With many nodes, D3 force simulation tick callback updates all nodes/edges/labels every frame - Original implementation called simulation.restart() in drag start event on mousedown - Even after simulation converged, clicking a node to view details would restart simulation, causing lag Solution: - Distinguish between "click" and "drag" using 3px movement threshold - On drag start: only record initial position, do not restart simulation - On drag event: detect movement exceeding threshold before marking as actual drag and restarting simulation - Pure click operations no longer trigger simulation restart, keeping graph static Bug fix: - Fixed issue where nodes became undraggable after initial optimization - Cause: incorrectly used if(!event.active) check in drag event - event.active equals 1 during drag event, causing restart() to never execute - Removed that condition, using custom _isDragging flag to control logic instead --- frontend/src/components/GraphPanel.vue | 28 ++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/frontend/src/components/GraphPanel.vue b/frontend/src/components/GraphPanel.vue index 704282c..314c966 100644 --- a/frontend/src/components/GraphPanel.vue +++ b/frontend/src/components/GraphPanel.vue @@ -661,18 +661,38 @@ const renderGraph = () => { .style('cursor', 'pointer') .call(d3.drag() .on('start', (event, d) => { - if (!event.active) simulation.alphaTarget(0.3).restart() + // 只记录位置,不重启仿真(区分点击和拖拽) d.fx = d.x d.fy = d.y + d._dragStartX = event.x + d._dragStartY = event.y + d._isDragging = false }) .on('drag', (event, d) => { - d.fx = event.x - d.fy = event.y + // 检测是否真正开始拖拽(移动超过阈值) + const dx = event.x - d._dragStartX + const dy = event.y - d._dragStartY + const distance = Math.sqrt(dx * dx + dy * dy) + + if (!d._isDragging && distance > 3) { + // 首次检测到真正拖拽,才重启仿真 + d._isDragging = true + simulation.alphaTarget(0.3).restart() + } + + if (d._isDragging) { + d.fx = event.x + d.fy = event.y + } }) .on('end', (event, d) => { - if (!event.active) simulation.alphaTarget(0) + // 只有真正拖拽过才让仿真逐渐停止 + if (d._isDragging) { + simulation.alphaTarget(0) + } d.fx = null d.fy = null + d._isDragging = false }) ) .on('click', (event, d) => {