Преглед на файлове

fix: FamilyRelationGraph 力导向模拟增加动能收敛检测, 布局稳定后自动停止避免永续占用主线程

liaoxg преди 1 месец
родител
ревизия
0f61b14444
променени са 1 файла, в които са добавени 25 реда и са изтрити 1 реда
  1. 25 1
      cfc-frontend/components/FamilyRelationGraph.vue

+ 25 - 1
cfc-frontend/components/FamilyRelationGraph.vue

@@ -105,6 +105,11 @@ export default {
       animFrameId: null,
       isSimulating: false,
 
+      // 动能收敛检测(布局收敛后自动停止,避免永续占用主线程)
+      stillFrames: 0,          // 连续低动能帧计数
+      energyThreshold: 2,      // 总动能阈值(各节点速度平方和)
+      stillFrameLimit: 30,     // 连续 30 帧低动能(约 0.5s)→ 停止
+
       // 主题色
       themeColors: {
         body: '#8D6E63',
@@ -281,6 +286,7 @@ export default {
     startSimulation: function() {
       if (this.isSimulating) return
       this.isSimulating = true
+      this.stillFrames = 0
       this.simulationTick()
     },
 
@@ -370,6 +376,7 @@ simulationTick: function() {
       }
 
       // 5. 更新速度 + 位置
+      var totalEnergy = 0
       for (var i = 0; i < nodes.length; i++) {
         var node = nodes[i]
         if (node.fixed) continue
@@ -410,6 +417,9 @@ simulationTick: function() {
         node.x += node.vx
         node.y += node.vy
 
+        // 累计动能(用于收敛检测)
+        totalEnergy += node.vx * node.vx + node.vy * node.vy
+
         // 边界约束
         var r = node.radius + 4
         if (node.x < r) { node.x = r; node.vx *= -0.5 }
@@ -418,6 +428,17 @@ simulationTick: function() {
         if (node.y > this.canvasHeight - r) { node.y = this.canvasHeight - r; node.vy *= -0.5 }
       }
 
+      // 5.5 动能收敛检测:布局基本稳定后自动停止,避免永续占用主线程(模拟器会判定长时间无响应)
+      if (totalEnergy < this.energyThreshold) {
+        this.stillFrames++
+        if (this.stillFrames >= this.stillFrameLimit) {
+          this.stopSimulation()
+          return
+        }
+      } else {
+        this.stillFrames = 0
+      }
+
       // 6. 渲染
       this.render()
 
@@ -766,7 +787,10 @@ simulationTick: function() {
               // 自身节点 → 显示 + 号
               self.touchingSelf = true
             } else {
-              // 其他节点 → 拖拽
+              // 其他节点 → 拖拽(若模拟已因收敛停止,则唤醒)
+              if (!self.isSimulating) {
+                self.startSimulation()
+              }
               self.dragging = {
                 node: node,
                 offsetX: x - node.x,