aifastdb-devplan 1.5.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/dist/autopilot.d.ts +58 -0
  2. package/dist/autopilot.d.ts.map +1 -0
  3. package/dist/autopilot.js +250 -0
  4. package/dist/autopilot.js.map +1 -0
  5. package/dist/dev-plan-document-store.d.ts +15 -1
  6. package/dist/dev-plan-document-store.d.ts.map +1 -1
  7. package/dist/dev-plan-document-store.js +122 -0
  8. package/dist/dev-plan-document-store.js.map +1 -1
  9. package/dist/dev-plan-factory.d.ts +69 -3
  10. package/dist/dev-plan-factory.d.ts.map +1 -1
  11. package/dist/dev-plan-factory.js +113 -19
  12. package/dist/dev-plan-factory.js.map +1 -1
  13. package/dist/dev-plan-graph-store.d.ts +79 -1
  14. package/dist/dev-plan-graph-store.d.ts.map +1 -1
  15. package/dist/dev-plan-graph-store.js +420 -3
  16. package/dist/dev-plan-graph-store.js.map +1 -1
  17. package/dist/dev-plan-interface.d.ts +24 -1
  18. package/dist/dev-plan-interface.d.ts.map +1 -1
  19. package/dist/dev-plan-migrate.d.ts +1 -0
  20. package/dist/dev-plan-migrate.d.ts.map +1 -1
  21. package/dist/dev-plan-migrate.js +28 -2
  22. package/dist/dev-plan-migrate.js.map +1 -1
  23. package/dist/index.d.ts +3 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +14 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/mcp-server/index.d.ts +3 -0
  28. package/dist/mcp-server/index.d.ts.map +1 -1
  29. package/dist/mcp-server/index.js +397 -4
  30. package/dist/mcp-server/index.js.map +1 -1
  31. package/dist/types.d.ts +160 -1
  32. package/dist/types.d.ts.map +1 -1
  33. package/dist/types.js +9 -1
  34. package/dist/types.js.map +1 -1
  35. package/dist/visualize/graph-canvas/api-compat.d.ts +20 -0
  36. package/dist/visualize/graph-canvas/api-compat.d.ts.map +1 -0
  37. package/dist/visualize/graph-canvas/api-compat.js +344 -0
  38. package/dist/visualize/graph-canvas/api-compat.js.map +1 -0
  39. package/dist/visualize/graph-canvas/clusterer.d.ts +16 -0
  40. package/dist/visualize/graph-canvas/clusterer.d.ts.map +1 -0
  41. package/dist/visualize/graph-canvas/clusterer.js +460 -0
  42. package/dist/visualize/graph-canvas/clusterer.js.map +1 -0
  43. package/dist/visualize/graph-canvas/core.d.ts +11 -0
  44. package/dist/visualize/graph-canvas/core.d.ts.map +1 -0
  45. package/dist/visualize/graph-canvas/core.js +1136 -0
  46. package/dist/visualize/graph-canvas/core.js.map +1 -0
  47. package/dist/visualize/graph-canvas/index.d.ts +22 -0
  48. package/dist/visualize/graph-canvas/index.d.ts.map +1 -0
  49. package/dist/visualize/graph-canvas/index.js +69 -0
  50. package/dist/visualize/graph-canvas/index.js.map +1 -0
  51. package/dist/visualize/graph-canvas/interaction.d.ts +13 -0
  52. package/dist/visualize/graph-canvas/interaction.d.ts.map +1 -0
  53. package/dist/visualize/graph-canvas/interaction.js +457 -0
  54. package/dist/visualize/graph-canvas/interaction.js.map +1 -0
  55. package/dist/visualize/graph-canvas/layout-worker.d.ts +17 -0
  56. package/dist/visualize/graph-canvas/layout-worker.d.ts.map +1 -0
  57. package/dist/visualize/graph-canvas/layout-worker.js +577 -0
  58. package/dist/visualize/graph-canvas/layout-worker.js.map +1 -0
  59. package/dist/visualize/graph-canvas/lod.d.ts +10 -0
  60. package/dist/visualize/graph-canvas/lod.d.ts.map +1 -0
  61. package/dist/visualize/graph-canvas/lod.js +111 -0
  62. package/dist/visualize/graph-canvas/lod.js.map +1 -0
  63. package/dist/visualize/graph-canvas/renderer.d.ts +12 -0
  64. package/dist/visualize/graph-canvas/renderer.d.ts.map +1 -0
  65. package/dist/visualize/graph-canvas/renderer.js +813 -0
  66. package/dist/visualize/graph-canvas/renderer.js.map +1 -0
  67. package/dist/visualize/graph-canvas/spatial-index.d.ts +13 -0
  68. package/dist/visualize/graph-canvas/spatial-index.d.ts.map +1 -0
  69. package/dist/visualize/graph-canvas/spatial-index.js +482 -0
  70. package/dist/visualize/graph-canvas/spatial-index.js.map +1 -0
  71. package/dist/visualize/graph-canvas/styles.d.ts +11 -0
  72. package/dist/visualize/graph-canvas/styles.d.ts.map +1 -0
  73. package/dist/visualize/graph-canvas/styles.js +152 -0
  74. package/dist/visualize/graph-canvas/styles.js.map +1 -0
  75. package/dist/visualize/graph-canvas/viewport.d.ts +17 -0
  76. package/dist/visualize/graph-canvas/viewport.d.ts.map +1 -0
  77. package/dist/visualize/graph-canvas/viewport.js +385 -0
  78. package/dist/visualize/graph-canvas/viewport.js.map +1 -0
  79. package/dist/visualize/server.js +737 -7
  80. package/dist/visualize/server.js.map +1 -1
  81. package/dist/visualize/template-core.d.ts +9 -0
  82. package/dist/visualize/template-core.d.ts.map +1 -0
  83. package/dist/visualize/template-core.js +714 -0
  84. package/dist/visualize/template-core.js.map +1 -0
  85. package/dist/visualize/template-data-loading.d.ts +7 -0
  86. package/dist/visualize/template-data-loading.d.ts.map +1 -0
  87. package/dist/visualize/template-data-loading.js +677 -0
  88. package/dist/visualize/template-data-loading.js.map +1 -0
  89. package/dist/visualize/template-detail-panel.d.ts +14 -0
  90. package/dist/visualize/template-detail-panel.d.ts.map +1 -0
  91. package/dist/visualize/template-detail-panel.js +553 -0
  92. package/dist/visualize/template-detail-panel.js.map +1 -0
  93. package/dist/visualize/template-graph-3d.d.ts +7 -0
  94. package/dist/visualize/template-graph-3d.d.ts.map +1 -0
  95. package/dist/visualize/template-graph-3d.js +1112 -0
  96. package/dist/visualize/template-graph-3d.js.map +1 -0
  97. package/dist/visualize/template-graph-vis.d.ts +8 -0
  98. package/dist/visualize/template-graph-vis.d.ts.map +1 -0
  99. package/dist/visualize/template-graph-vis.js +1204 -0
  100. package/dist/visualize/template-graph-vis.js.map +1 -0
  101. package/dist/visualize/template-html.d.ts +9 -0
  102. package/dist/visualize/template-html.d.ts.map +1 -0
  103. package/dist/visualize/template-html.js +484 -0
  104. package/dist/visualize/template-html.js.map +1 -0
  105. package/dist/visualize/template-pages.d.ts +7 -0
  106. package/dist/visualize/template-pages.d.ts.map +1 -0
  107. package/dist/visualize/template-pages.js +806 -0
  108. package/dist/visualize/template-pages.js.map +1 -0
  109. package/dist/visualize/template-stats-modal.d.ts +7 -0
  110. package/dist/visualize/template-stats-modal.d.ts.map +1 -0
  111. package/dist/visualize/template-stats-modal.js +406 -0
  112. package/dist/visualize/template-stats-modal.js.map +1 -0
  113. package/dist/visualize/template-styles.d.ts +9 -0
  114. package/dist/visualize/template-styles.d.ts.map +1 -0
  115. package/dist/visualize/template-styles.js +487 -0
  116. package/dist/visualize/template-styles.js.map +1 -0
  117. package/dist/visualize/template.d.ts +14 -3
  118. package/dist/visualize/template.d.ts.map +1 -1
  119. package/dist/visualize/template.js +38 -2889
  120. package/dist/visualize/template.js.map +1 -1
  121. package/package.json +1 -1
@@ -0,0 +1,460 @@
1
+ "use strict";
2
+ /**
3
+ * Clusterer — 节点聚合器 (完整实现)
4
+ *
5
+ * 在极低缩放级别时,将空间邻近的节点聚合为 cluster 节点。
6
+ * 使用网格聚合 (grid-based clustering) 算法:
7
+ * 1. 将世界空间划分为网格
8
+ * 2. 每个网格内的多个节点聚合为一个 cluster
9
+ * 3. cluster 显示计数标签、主类型颜色、状态饼图
10
+ * 4. 缩放到阈值以上时自动展开
11
+ * 5. Spring 展开/收起过渡动画
12
+ * 6. 多级递归聚合
13
+ *
14
+ * Phase 8B 完整实现
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.getClustererScript = getClustererScript;
18
+ function getClustererScript() {
19
+ return `
20
+ // ============================================================================
21
+ // Clusterer — Grid-based Node Aggregation (Full Implementation)
22
+ // ============================================================================
23
+
24
+ function Clusterer(engine) {
25
+ this._engine = engine;
26
+ this._enabled = false;
27
+ this._clusters = []; // [{id, nodes, x, y, count, radius, ...}, ...]
28
+ this._clusterMap = {}; // clusterId → cluster
29
+ this._nodeToCluster = {}; // nodeId → clusterId
30
+ this._gridSize = 200; // world-space grid cell size (base)
31
+ this._clusterThreshold = 0.08; // scale below which clustering activates
32
+ this._minClusterSize = 2; // minimum nodes to form a cluster
33
+ this._lastRebuildScale = -1; // last scale at which clusters were rebuilt
34
+ this._rebuildThresholdRatio = 1.5; // rebuild when scale changes by this factor
35
+
36
+ // Animation state
37
+ this._animating = false;
38
+ this._animations = []; // [{node, startX, startY, targetX, targetY, t, duration}, ...]
39
+ this._animRafId = null;
40
+
41
+ // Multi-level: clusters of clusters
42
+ this._level = 0; // current aggregation level
43
+ this._parentClusters = []; // level-2 super-clusters
44
+ }
45
+
46
+ /**
47
+ * Enable/disable clustering.
48
+ */
49
+ Clusterer.prototype.setEnabled = function(enabled) {
50
+ this._enabled = enabled;
51
+ if (enabled) {
52
+ this.rebuild();
53
+ } else {
54
+ this._clearAllClusters();
55
+ }
56
+ };
57
+
58
+ Clusterer.prototype._clearAllClusters = function() {
59
+ // Restore visibility to all nodes
60
+ var nodes = this._engine._nodes;
61
+ for (var i = 0; i < nodes.length; i++) {
62
+ nodes[i]._visible = true;
63
+ nodes[i]._clustered = false;
64
+ }
65
+ this._clusters = [];
66
+ this._clusterMap = {};
67
+ this._nodeToCluster = {};
68
+ this._parentClusters = [];
69
+ this._level = 0;
70
+ this._lastRebuildScale = -1;
71
+ };
72
+
73
+ /**
74
+ * Check if clustering should be active at the current zoom level.
75
+ */
76
+ Clusterer.prototype.isActive = function() {
77
+ if (!this._enabled) return false;
78
+ return this._engine._viewport.getScale() < this._clusterThreshold;
79
+ };
80
+
81
+ /**
82
+ * Check if clusters need rebuilding based on scale change.
83
+ */
84
+ Clusterer.prototype.needsRebuild = function() {
85
+ if (!this._enabled) return false;
86
+ var scale = this._engine._viewport.getScale();
87
+ if (this._lastRebuildScale <= 0) return true;
88
+ var ratio = Math.max(scale / this._lastRebuildScale, this._lastRebuildScale / scale);
89
+ return ratio > this._rebuildThresholdRatio;
90
+ };
91
+
92
+ /**
93
+ * Rebuild clusters based on current node positions and zoom level.
94
+ * Uses adaptive grid-based clustering for O(n) performance.
95
+ * Grid size adapts to zoom: zoomed further out → larger grids → more aggregation.
96
+ */
97
+ Clusterer.prototype.rebuild = function() {
98
+ if (!this._enabled) return;
99
+
100
+ var engine = this._engine;
101
+ var nodes = engine._nodes;
102
+ var scale = engine._viewport.getScale();
103
+ this._lastRebuildScale = scale;
104
+
105
+ // Adaptive grid size: smaller scale → larger grid → more aggregation
106
+ var baseGrid = this._gridSize;
107
+ var adaptiveGrid = baseGrid / Math.max(scale * 5, 0.01);
108
+ adaptiveGrid = Math.max(adaptiveGrid, 100); // minimum grid size
109
+ adaptiveGrid = Math.min(adaptiveGrid, 5000); // maximum grid size
110
+
111
+ var grid = {}; // "gx:gy" → [node, ...]
112
+
113
+ // Assign nodes to grid cells
114
+ for (var i = 0; i < nodes.length; i++) {
115
+ var n = nodes[i];
116
+ var gx = Math.floor(n.x / adaptiveGrid);
117
+ var gy = Math.floor(n.y / adaptiveGrid);
118
+ var key = gx + ':' + gy;
119
+ if (!grid[key]) grid[key] = [];
120
+ grid[key].push(n);
121
+ }
122
+
123
+ // Reset old state
124
+ for (var i = 0; i < nodes.length; i++) {
125
+ nodes[i]._visible = true;
126
+ nodes[i]._clustered = false;
127
+ }
128
+ this._clusters = [];
129
+ this._clusterMap = {};
130
+ this._nodeToCluster = {};
131
+ var clusterId = 0;
132
+
133
+ var keys = Object.keys(grid);
134
+ for (var i = 0; i < keys.length; i++) {
135
+ var cellNodes = grid[keys[i]];
136
+ if (cellNodes.length < this._minClusterSize) continue; // too few, show individually
137
+
138
+ // Compute centroid
139
+ var cx = 0, cy = 0;
140
+ for (var j = 0; j < cellNodes.length; j++) {
141
+ cx += cellNodes[j].x;
142
+ cy += cellNodes[j].y;
143
+ }
144
+ cx /= cellNodes.length;
145
+ cy /= cellNodes.length;
146
+
147
+ // Determine dominant type and status
148
+ var typeCount = {};
149
+ var statusCount = {};
150
+ for (var j = 0; j < cellNodes.length; j++) {
151
+ var t = cellNodes[j].type || 'default';
152
+ var s = (cellNodes[j].properties || {}).status || 'pending';
153
+ typeCount[t] = (typeCount[t] || 0) + 1;
154
+ statusCount[s] = (statusCount[s] || 0) + 1;
155
+ }
156
+ var dominantType = this._getDominant(typeCount);
157
+ var dominantStatus = this._getDominant(statusCount);
158
+
159
+ // Get style for the cluster based on dominant type
160
+ var styles = engine._styles;
161
+ var mockNode = { type: dominantType, properties: { status: dominantStatus }, degree: cellNodes.length };
162
+ var clusterStyle = styles.getNodeStyle(mockNode);
163
+
164
+ var cluster = {
165
+ id: 'cluster_' + (clusterId++),
166
+ nodes: cellNodes,
167
+ nodeIds: [],
168
+ x: cx,
169
+ y: cy,
170
+ count: cellNodes.length,
171
+ radius: Math.max(18, Math.min(Math.sqrt(cellNodes.length) * 6, 60)),
172
+ dominantType: dominantType,
173
+ dominantStatus: dominantStatus,
174
+ bgColor: clusterStyle.bgColor,
175
+ borderColor: clusterStyle.borderColor,
176
+ fontColor: clusterStyle.fontColor || '#fff',
177
+ statusBreakdown: statusCount,
178
+ _aabb: null, // will be set below
179
+ };
180
+
181
+ for (var j = 0; j < cellNodes.length; j++) {
182
+ cluster.nodeIds.push(cellNodes[j].id);
183
+ this._nodeToCluster[cellNodes[j].id] = cluster.id;
184
+ cellNodes[j]._visible = false; // hide individual nodes
185
+ cellNodes[j]._clustered = true;
186
+ }
187
+
188
+ // Set AABB for cluster hit-test
189
+ cluster._aabb = {
190
+ minX: cx - cluster.radius,
191
+ minY: cy - cluster.radius,
192
+ maxX: cx + cluster.radius,
193
+ maxY: cy + cluster.radius,
194
+ };
195
+
196
+ this._clusters.push(cluster);
197
+ this._clusterMap[cluster.id] = cluster;
198
+ }
199
+
200
+ // Multi-level: if there are still too many clusters, create super-clusters
201
+ this._parentClusters = [];
202
+ if (this._clusters.length > 200 && scale < this._clusterThreshold * 0.3) {
203
+ this._buildSuperClusters(adaptiveGrid * 3);
204
+ }
205
+ };
206
+
207
+ /**
208
+ * Build level-2 super-clusters (clusters of clusters).
209
+ */
210
+ Clusterer.prototype._buildSuperClusters = function(superGridSize) {
211
+ var grid = {};
212
+ for (var i = 0; i < this._clusters.length; i++) {
213
+ var c = this._clusters[i];
214
+ var gx = Math.floor(c.x / superGridSize);
215
+ var gy = Math.floor(c.y / superGridSize);
216
+ var key = gx + ':' + gy;
217
+ if (!grid[key]) grid[key] = [];
218
+ grid[key].push(c);
219
+ }
220
+
221
+ this._parentClusters = [];
222
+ var keys = Object.keys(grid);
223
+ for (var i = 0; i < keys.length; i++) {
224
+ var subClusters = grid[keys[i]];
225
+ if (subClusters.length < 2) continue;
226
+
227
+ var cx = 0, cy = 0, totalCount = 0;
228
+ for (var j = 0; j < subClusters.length; j++) {
229
+ cx += subClusters[j].x * subClusters[j].count;
230
+ cy += subClusters[j].y * subClusters[j].count;
231
+ totalCount += subClusters[j].count;
232
+ }
233
+ cx /= totalCount;
234
+ cy /= totalCount;
235
+
236
+ this._parentClusters.push({
237
+ id: 'super_' + i,
238
+ subClusters: subClusters,
239
+ x: cx,
240
+ y: cy,
241
+ count: totalCount,
242
+ radius: Math.max(25, Math.min(Math.sqrt(totalCount) * 4, 80)),
243
+ bgColor: '#6366f1',
244
+ borderColor: '#4f46e5',
245
+ fontColor: '#fff',
246
+ });
247
+
248
+ // Mark sub-clusters as hidden
249
+ for (var j = 0; j < subClusters.length; j++) {
250
+ subClusters[j]._superClustered = true;
251
+ }
252
+ }
253
+ };
254
+
255
+ Clusterer.prototype._getDominant = function(countMap) {
256
+ var maxKey = null, maxCount = 0;
257
+ var keys = Object.keys(countMap);
258
+ for (var i = 0; i < keys.length; i++) {
259
+ if (countMap[keys[i]] > maxCount) {
260
+ maxCount = countMap[keys[i]];
261
+ maxKey = keys[i];
262
+ }
263
+ }
264
+ return maxKey;
265
+ };
266
+
267
+ /**
268
+ * Get clusters for rendering (filters out super-clustered ones).
269
+ */
270
+ Clusterer.prototype.getClusters = function() {
271
+ if (this._parentClusters.length > 0) {
272
+ // Return only non-super-clustered clusters + super-clusters
273
+ var visible = [];
274
+ for (var i = 0; i < this._clusters.length; i++) {
275
+ if (!this._clusters[i]._superClustered) visible.push(this._clusters[i]);
276
+ }
277
+ return visible.concat(this._parentClusters);
278
+ }
279
+ return this._clusters;
280
+ };
281
+
282
+ /**
283
+ * Check if a node is currently inside a cluster.
284
+ */
285
+ Clusterer.prototype.isNodeClustered = function(nodeId) {
286
+ return !!this._nodeToCluster[nodeId];
287
+ };
288
+
289
+ /**
290
+ * Hit-test: find cluster at world coordinates.
291
+ */
292
+ Clusterer.prototype.hitTest = function(worldX, worldY) {
293
+ var clusters = this.getClusters();
294
+ for (var i = clusters.length - 1; i >= 0; i--) {
295
+ var c = clusters[i];
296
+ var dx = worldX - c.x;
297
+ var dy = worldY - c.y;
298
+ if (dx * dx + dy * dy <= c.radius * c.radius) {
299
+ return c;
300
+ }
301
+ }
302
+ return null;
303
+ };
304
+
305
+ /**
306
+ * Expand a cluster with Spring animation.
307
+ * @param {string} clusterId
308
+ * @param {Object} [options] — { animation: boolean, fitAfter: boolean }
309
+ */
310
+ Clusterer.prototype.expandCluster = function(clusterId, options) {
311
+ var cluster = this._clusterMap[clusterId];
312
+ if (!cluster) return;
313
+
314
+ var opts = options || {};
315
+ var animate = opts.animation !== false;
316
+ var fitAfter = opts.fitAfter !== false;
317
+ var engine = this._engine;
318
+
319
+ // Remove cluster
320
+ var idx = this._clusters.indexOf(cluster);
321
+ if (idx >= 0) this._clusters.splice(idx, 1);
322
+ delete this._clusterMap[clusterId];
323
+
324
+ // Restore nodes
325
+ for (var i = 0; i < cluster.nodes.length; i++) {
326
+ var node = cluster.nodes[i];
327
+ delete this._nodeToCluster[node.id];
328
+ node._visible = true;
329
+ node._clustered = false;
330
+
331
+ if (animate) {
332
+ // Start all nodes at cluster center, animate to their real positions
333
+ var realX = node.x;
334
+ var realY = node.y;
335
+ node.x = cluster.x;
336
+ node.y = cluster.y;
337
+ this._animations.push({
338
+ node: node,
339
+ startX: cluster.x,
340
+ startY: cluster.y,
341
+ targetX: realX,
342
+ targetY: realY,
343
+ t: 0,
344
+ duration: 400 + Math.random() * 200, // stagger slightly
345
+ });
346
+ }
347
+ }
348
+
349
+ if (animate && this._animations.length > 0) {
350
+ this._startAnimation();
351
+ }
352
+
353
+ // Rebuild spatial index with restored nodes
354
+ engine._spatialIndex.buildFromNodes(engine._nodes);
355
+ engine._spatialIndex.buildEdgeIndex(engine._edges, engine._nodeMap);
356
+ engine.markDirty();
357
+
358
+ // Emit event
359
+ engine._emit('clusterExpanded', { clusterId: clusterId, nodeCount: cluster.nodes.length });
360
+
361
+ // Fit to expanded nodes after animation
362
+ if (fitAfter && !animate) {
363
+ engine._viewport.fitToNodes(cluster.nodes, { padding: 80, animation: { duration: 600 } });
364
+ }
365
+ };
366
+
367
+ /**
368
+ * Collapse nodes back into cluster (reverse of expand).
369
+ * @param {Array} nodeIds — nodes to re-cluster
370
+ */
371
+ Clusterer.prototype.collapseNodes = function(nodeIds) {
372
+ // Simply rebuild clusters — the auto-clustering will re-aggregate
373
+ this.rebuild();
374
+ this._engine.markDirty();
375
+ };
376
+
377
+ // ── Spring Animation ──────────────────────────────────────────────────────
378
+
379
+ /**
380
+ * Start the expand/collapse animation loop.
381
+ */
382
+ Clusterer.prototype._startAnimation = function() {
383
+ if (this._animating) return;
384
+ this._animating = true;
385
+
386
+ var self = this;
387
+ var engine = this._engine;
388
+ var startTime = performance.now();
389
+
390
+ function animate(now) {
391
+ var allDone = true;
392
+ var elapsed = now - startTime;
393
+
394
+ for (var i = self._animations.length - 1; i >= 0; i--) {
395
+ var a = self._animations[i];
396
+ a.t = Math.min(elapsed / a.duration, 1);
397
+
398
+ // Spring easing function
399
+ var progress = self._springEase(a.t);
400
+
401
+ a.node.x = a.startX + (a.targetX - a.startX) * progress;
402
+ a.node.y = a.startY + (a.targetY - a.startY) * progress;
403
+
404
+ if (a.t >= 1) {
405
+ // Ensure final position
406
+ a.node.x = a.targetX;
407
+ a.node.y = a.targetY;
408
+ self._animations.splice(i, 1);
409
+ } else {
410
+ allDone = false;
411
+ }
412
+ }
413
+
414
+ // Rebuild spatial index during animation
415
+ engine._spatialIndex.buildFromNodes(engine._nodes);
416
+ engine._spatialIndex.buildEdgeIndex(engine._edges, engine._nodeMap);
417
+ engine.markDirty();
418
+
419
+ if (allDone) {
420
+ self._animating = false;
421
+ self._animRafId = null;
422
+ // Fit to expanded nodes
423
+ var expandedNodes = engine._nodes.filter(function(n) { return n._visible; });
424
+ // Don't auto-fit — let user control viewport
425
+ } else {
426
+ self._animRafId = requestAnimationFrame(animate);
427
+ }
428
+ }
429
+
430
+ this._animRafId = requestAnimationFrame(animate);
431
+ };
432
+
433
+ /**
434
+ * Spring easing: overshoot + settle.
435
+ * Based on a critically damped spring model.
436
+ */
437
+ Clusterer.prototype._springEase = function(t) {
438
+ // Spring parameters
439
+ var frequency = 4.5; // oscillation frequency
440
+ var damping = 0.7; // damping ratio
441
+ if (t >= 1) return 1;
442
+ return 1 - Math.exp(-damping * t * 10) * Math.cos(frequency * t * Math.PI);
443
+ };
444
+
445
+ /**
446
+ * Set clustering threshold.
447
+ */
448
+ Clusterer.prototype.setThreshold = function(threshold) {
449
+ this._clusterThreshold = threshold;
450
+ };
451
+
452
+ /**
453
+ * Set grid size.
454
+ */
455
+ Clusterer.prototype.setGridSize = function(size) {
456
+ this._gridSize = size;
457
+ };
458
+ `;
459
+ }
460
+ //# sourceMappingURL=clusterer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clusterer.js","sourceRoot":"","sources":["../../../src/visualize/graph-canvas/clusterer.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAEH,gDAybC;AAzbD,SAAgB,kBAAkB;IAChC,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAubR,CAAC;AACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * GraphCanvas Core — Canvas2D 渲染器骨架
3
+ *
4
+ * 职责:
5
+ * - 创建/管理 Canvas 元素
6
+ * - 维护节点/边数据
7
+ * - requestAnimationFrame 渲染循环
8
+ * - 协调各子模块 (Viewport, SpatialIndex, Renderer, etc.)
9
+ */
10
+ export declare function getCoreScript(): string;
11
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/visualize/graph-canvas/core.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wBAAgB,aAAa,IAAI,MAAM,CAkmCtC"}