Spaces:
Sleeping
fix(GraphPanel): optimize force graph drag behavior to prevent simulation restart on click
Browse filesBackground:
- 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
|
@@ -661,18 +661,38 @@ const renderGraph = () => {
|
|
| 661 |
.style('cursor', 'pointer')
|
| 662 |
.call(d3.drag()
|
| 663 |
.on('start', (event, d) => {
|
| 664 |
-
|
| 665 |
d.fx = d.x
|
| 666 |
d.fy = d.y
|
|
|
|
|
|
|
|
|
|
| 667 |
})
|
| 668 |
.on('drag', (event, d) => {
|
| 669 |
-
|
| 670 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 671 |
})
|
| 672 |
.on('end', (event, d) => {
|
| 673 |
-
|
|
|
|
|
|
|
|
|
|
| 674 |
d.fx = null
|
| 675 |
d.fy = null
|
|
|
|
| 676 |
})
|
| 677 |
)
|
| 678 |
.on('click', (event, d) => {
|
|
|
|
| 661 |
.style('cursor', 'pointer')
|
| 662 |
.call(d3.drag()
|
| 663 |
.on('start', (event, d) => {
|
| 664 |
+
// 只记录位置,不重启仿真(区分点击和拖拽)
|
| 665 |
d.fx = d.x
|
| 666 |
d.fy = d.y
|
| 667 |
+
d._dragStartX = event.x
|
| 668 |
+
d._dragStartY = event.y
|
| 669 |
+
d._isDragging = false
|
| 670 |
})
|
| 671 |
.on('drag', (event, d) => {
|
| 672 |
+
// 检测是否真正开始拖拽(移动超过阈值)
|
| 673 |
+
const dx = event.x - d._dragStartX
|
| 674 |
+
const dy = event.y - d._dragStartY
|
| 675 |
+
const distance = Math.sqrt(dx * dx + dy * dy)
|
| 676 |
+
|
| 677 |
+
if (!d._isDragging && distance > 3) {
|
| 678 |
+
// 首次检测到真正拖拽,才重启仿真
|
| 679 |
+
d._isDragging = true
|
| 680 |
+
simulation.alphaTarget(0.3).restart()
|
| 681 |
+
}
|
| 682 |
+
|
| 683 |
+
if (d._isDragging) {
|
| 684 |
+
d.fx = event.x
|
| 685 |
+
d.fy = event.y
|
| 686 |
+
}
|
| 687 |
})
|
| 688 |
.on('end', (event, d) => {
|
| 689 |
+
// 只有真正拖拽过才让仿真逐渐停止
|
| 690 |
+
if (d._isDragging) {
|
| 691 |
+
simulation.alphaTarget(0)
|
| 692 |
+
}
|
| 693 |
d.fx = null
|
| 694 |
d.fy = null
|
| 695 |
+
d._isDragging = false
|
| 696 |
})
|
| 697 |
)
|
| 698 |
.on('click', (event, d) => {
|