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
This commit is contained in:
666ghj 2026-01-18 22:34:40 +08:00
parent 49847c5b26
commit 085aa6bbe6

View file

@ -661,18 +661,38 @@ const renderGraph = () => {
.style('cursor', 'pointer') .style('cursor', 'pointer')
.call(d3.drag() .call(d3.drag()
.on('start', (event, d) => { .on('start', (event, d) => {
if (!event.active) simulation.alphaTarget(0.3).restart() // 仿
d.fx = d.x d.fx = d.x
d.fy = d.y d.fy = d.y
d._dragStartX = event.x
d._dragStartY = event.y
d._isDragging = false
}) })
.on('drag', (event, d) => { .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) => { .on('end', (event, d) => {
if (!event.active) simulation.alphaTarget(0) // 仿
if (d._isDragging) {
simulation.alphaTarget(0)
}
d.fx = null d.fx = null
d.fy = null d.fy = null
d._isDragging = false
}) })
) )
.on('click', (event, d) => { .on('click', (event, d) => {