microboard-temp 0.13.20 → 0.13.21
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.
- package/dist/cjs/browser.js +122 -30
- package/dist/cjs/index.js +122 -30
- package/dist/cjs/node.js +122 -30
- package/dist/esm/browser.js +122 -30
- package/dist/esm/index.js +122 -30
- package/dist/esm/node.js +122 -30
- package/dist/types/Board.d.ts +6 -3
- package/dist/types/ForceGraph/ForceGraphEngine.d.ts +31 -3
- package/package.json +1 -1
package/dist/cjs/browser.js
CHANGED
|
@@ -54606,6 +54606,7 @@ class ForceGraphEngine {
|
|
|
54606
54606
|
tickTimer = null;
|
|
54607
54607
|
syncTimer = null;
|
|
54608
54608
|
lastSyncedPositions = new Map;
|
|
54609
|
+
activeComponents = new Map;
|
|
54609
54610
|
TICK_MS = 33;
|
|
54610
54611
|
SYNC_MS = 300;
|
|
54611
54612
|
SOFTENING_SQ = 100 * 100;
|
|
@@ -54613,18 +54614,60 @@ class ForceGraphEngine {
|
|
|
54613
54614
|
constructor(board) {
|
|
54614
54615
|
this.board = board;
|
|
54615
54616
|
}
|
|
54616
|
-
|
|
54617
|
-
if (this.
|
|
54617
|
+
enableForGraph(startNodeId) {
|
|
54618
|
+
if (this.isNodeInActiveGraph(startNodeId))
|
|
54618
54619
|
return;
|
|
54619
|
-
|
|
54620
|
-
|
|
54621
|
-
|
|
54622
|
-
|
|
54620
|
+
const nodeIds = this.bfsComponent(startNodeId);
|
|
54621
|
+
const targetGap = this.calibrateTargetGap(nodeIds);
|
|
54622
|
+
this.activeComponents.set(startNodeId, { nodeIds, targetGap });
|
|
54623
|
+
for (const id of nodeIds) {
|
|
54624
|
+
if (!this.velocities.has(id)) {
|
|
54625
|
+
this.velocities.set(id, { vx: 0, vy: 0 });
|
|
54626
|
+
}
|
|
54627
|
+
const item = this.board.items.getById(id);
|
|
54628
|
+
if (item && !this.lastSyncedPositions.has(id)) {
|
|
54629
|
+
const pos = item.transformation.getTranslation();
|
|
54630
|
+
this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
|
|
54631
|
+
}
|
|
54632
|
+
}
|
|
54633
|
+
this.ensureRunning();
|
|
54634
|
+
}
|
|
54635
|
+
disableForGraph(nodeId) {
|
|
54636
|
+
const compId = this.findComponentId(nodeId);
|
|
54637
|
+
if (!compId)
|
|
54638
|
+
return;
|
|
54639
|
+
this.activeComponents.delete(compId);
|
|
54640
|
+
if (this.activeComponents.size === 0) {
|
|
54641
|
+
this.stopTimers();
|
|
54642
|
+
}
|
|
54643
|
+
}
|
|
54644
|
+
isNodeInActiveGraph(nodeId) {
|
|
54645
|
+
return !!this.findComponentId(nodeId);
|
|
54646
|
+
}
|
|
54647
|
+
hasActiveComponents() {
|
|
54648
|
+
return this.activeComponents.size > 0;
|
|
54649
|
+
}
|
|
54650
|
+
wake() {
|
|
54651
|
+
if (this.activeComponents.size > 0 && this.tickTimer === null) {
|
|
54652
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54623
54653
|
}
|
|
54624
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54625
|
-
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54626
54654
|
}
|
|
54627
54655
|
stop() {
|
|
54656
|
+
this.stopTimers();
|
|
54657
|
+
this.syncPositions();
|
|
54658
|
+
this.velocities.clear();
|
|
54659
|
+
this.lastSyncedPositions.clear();
|
|
54660
|
+
this.activeComponents.clear();
|
|
54661
|
+
}
|
|
54662
|
+
ensureRunning() {
|
|
54663
|
+
if (this.tickTimer === null) {
|
|
54664
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54665
|
+
}
|
|
54666
|
+
if (this.syncTimer === null) {
|
|
54667
|
+
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54668
|
+
}
|
|
54669
|
+
}
|
|
54670
|
+
stopTimers() {
|
|
54628
54671
|
if (this.tickTimer !== null) {
|
|
54629
54672
|
clearInterval(this.tickTimer);
|
|
54630
54673
|
this.tickTimer = null;
|
|
@@ -54633,9 +54676,56 @@ class ForceGraphEngine {
|
|
|
54633
54676
|
clearInterval(this.syncTimer);
|
|
54634
54677
|
this.syncTimer = null;
|
|
54635
54678
|
}
|
|
54636
|
-
|
|
54637
|
-
|
|
54638
|
-
this.
|
|
54679
|
+
}
|
|
54680
|
+
findComponentId(nodeId) {
|
|
54681
|
+
for (const [compId, { nodeIds }] of this.activeComponents) {
|
|
54682
|
+
if (nodeIds.has(nodeId))
|
|
54683
|
+
return compId;
|
|
54684
|
+
}
|
|
54685
|
+
return;
|
|
54686
|
+
}
|
|
54687
|
+
bfsComponent(startNodeId) {
|
|
54688
|
+
const visited = new Set;
|
|
54689
|
+
const queue = [startNodeId];
|
|
54690
|
+
const connectors = this.getConnectors();
|
|
54691
|
+
while (queue.length > 0) {
|
|
54692
|
+
const nodeId = queue.shift();
|
|
54693
|
+
if (visited.has(nodeId))
|
|
54694
|
+
continue;
|
|
54695
|
+
visited.add(nodeId);
|
|
54696
|
+
for (const connector of connectors) {
|
|
54697
|
+
const { startItem, endItem } = connector.getConnectedItems();
|
|
54698
|
+
if (startItem?.getId() === nodeId && endItem && !visited.has(endItem.getId())) {
|
|
54699
|
+
queue.push(endItem.getId());
|
|
54700
|
+
}
|
|
54701
|
+
if (endItem?.getId() === nodeId && startItem && !visited.has(startItem.getId())) {
|
|
54702
|
+
queue.push(startItem.getId());
|
|
54703
|
+
}
|
|
54704
|
+
}
|
|
54705
|
+
}
|
|
54706
|
+
return visited;
|
|
54707
|
+
}
|
|
54708
|
+
calibrateTargetGap(nodeIds) {
|
|
54709
|
+
let totalMaxDim = 0;
|
|
54710
|
+
let count = 0;
|
|
54711
|
+
for (const id of nodeIds) {
|
|
54712
|
+
const item = this.board.items.getById(id);
|
|
54713
|
+
if (!item)
|
|
54714
|
+
continue;
|
|
54715
|
+
const mbr = item.getMbr();
|
|
54716
|
+
totalMaxDim += Math.max(mbr.getWidth(), mbr.getHeight());
|
|
54717
|
+
count++;
|
|
54718
|
+
}
|
|
54719
|
+
const avgMaxDim = count > 0 ? totalMaxDim / count : 100;
|
|
54720
|
+
return avgMaxDim * 0.3 + conf.FG_TARGET_GAP;
|
|
54721
|
+
}
|
|
54722
|
+
getActiveNodeIds() {
|
|
54723
|
+
const all6 = new Set;
|
|
54724
|
+
for (const { nodeIds } of this.activeComponents.values()) {
|
|
54725
|
+
for (const id of nodeIds)
|
|
54726
|
+
all6.add(id);
|
|
54727
|
+
}
|
|
54728
|
+
return all6;
|
|
54639
54729
|
}
|
|
54640
54730
|
getNodes() {
|
|
54641
54731
|
return this.board.items.listAll().filter((item) => !EXCLUDED_TYPES.has(item.itemType) && !item.transformation.isLocked);
|
|
@@ -54645,8 +54735,10 @@ class ForceGraphEngine {
|
|
|
54645
54735
|
}
|
|
54646
54736
|
tick() {
|
|
54647
54737
|
const dt = this.TICK_MS / 1000;
|
|
54648
|
-
const
|
|
54649
|
-
|
|
54738
|
+
const activeIds = this.getActiveNodeIds();
|
|
54739
|
+
const allNodes = this.getNodes();
|
|
54740
|
+
const nodes = allNodes.filter((item) => activeIds.has(item.getId()));
|
|
54741
|
+
if (nodes.length < 1)
|
|
54650
54742
|
return;
|
|
54651
54743
|
const snapMap = new Map;
|
|
54652
54744
|
for (const item of nodes) {
|
|
@@ -54687,7 +54779,9 @@ class ForceGraphEngine {
|
|
|
54687
54779
|
const dx = s2.cx - s1.cx;
|
|
54688
54780
|
const dy = s2.cy - s1.cy;
|
|
54689
54781
|
const dist = Math.sqrt(dx * dx + dy * dy) + 0.001;
|
|
54690
|
-
const
|
|
54782
|
+
const compId = this.findComponentId(s1.id);
|
|
54783
|
+
const targetGap = compId ? this.activeComponents.get(compId)?.targetGap ?? conf.FG_TARGET_GAP : conf.FG_TARGET_GAP;
|
|
54784
|
+
const targetDist = (Math.max(s1.w, s1.h) + Math.max(s2.w, s2.h)) * 0.5 + targetGap;
|
|
54691
54785
|
const stretch = dist - targetDist;
|
|
54692
54786
|
const forceMag = stretch * conf.FG_SPRING_K;
|
|
54693
54787
|
const fx = dx / dist * forceMag;
|
|
@@ -54748,7 +54842,8 @@ class ForceGraphEngine {
|
|
|
54748
54842
|
}
|
|
54749
54843
|
}
|
|
54750
54844
|
syncPositions() {
|
|
54751
|
-
const
|
|
54845
|
+
const activeIds = this.getActiveNodeIds();
|
|
54846
|
+
const nodes = this.getNodes().filter((item) => activeIds.has(item.getId()));
|
|
54752
54847
|
if (nodes.length === 0)
|
|
54753
54848
|
return;
|
|
54754
54849
|
const movedItems = nodes.map((item) => {
|
|
@@ -54772,11 +54867,6 @@ class ForceGraphEngine {
|
|
|
54772
54867
|
};
|
|
54773
54868
|
this.board.events.emit(operation);
|
|
54774
54869
|
}
|
|
54775
|
-
wake() {
|
|
54776
|
-
if (this.tickTimer === null && this.syncTimer !== null) {
|
|
54777
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54778
|
-
}
|
|
54779
|
-
}
|
|
54780
54870
|
}
|
|
54781
54871
|
|
|
54782
54872
|
// src/Board.ts
|
|
@@ -55852,20 +55942,22 @@ class Board {
|
|
|
55852
55942
|
return this.gravity !== null;
|
|
55853
55943
|
}
|
|
55854
55944
|
forceGraph = null;
|
|
55855
|
-
enableForceGraph() {
|
|
55856
|
-
if (this.forceGraph)
|
|
55857
|
-
|
|
55858
|
-
|
|
55859
|
-
this.forceGraph.
|
|
55945
|
+
enableForceGraph(nodeId) {
|
|
55946
|
+
if (!this.forceGraph) {
|
|
55947
|
+
this.forceGraph = new ForceGraphEngine(this);
|
|
55948
|
+
}
|
|
55949
|
+
this.forceGraph.enableForGraph(nodeId);
|
|
55860
55950
|
}
|
|
55861
|
-
disableForceGraph() {
|
|
55951
|
+
disableForceGraph(nodeId) {
|
|
55862
55952
|
if (!this.forceGraph)
|
|
55863
55953
|
return;
|
|
55864
|
-
this.forceGraph.
|
|
55865
|
-
this.forceGraph
|
|
55954
|
+
this.forceGraph.disableForGraph(nodeId);
|
|
55955
|
+
if (!this.forceGraph.hasActiveComponents()) {
|
|
55956
|
+
this.forceGraph = null;
|
|
55957
|
+
}
|
|
55866
55958
|
}
|
|
55867
|
-
|
|
55868
|
-
return this.forceGraph
|
|
55959
|
+
isNodeInForceGraph(nodeId) {
|
|
55960
|
+
return this.forceGraph?.isNodeInActiveGraph(nodeId) ?? false;
|
|
55869
55961
|
}
|
|
55870
55962
|
wakeForceGraph() {
|
|
55871
55963
|
this.forceGraph?.wake();
|
package/dist/cjs/index.js
CHANGED
|
@@ -54606,6 +54606,7 @@ class ForceGraphEngine {
|
|
|
54606
54606
|
tickTimer = null;
|
|
54607
54607
|
syncTimer = null;
|
|
54608
54608
|
lastSyncedPositions = new Map;
|
|
54609
|
+
activeComponents = new Map;
|
|
54609
54610
|
TICK_MS = 33;
|
|
54610
54611
|
SYNC_MS = 300;
|
|
54611
54612
|
SOFTENING_SQ = 100 * 100;
|
|
@@ -54613,18 +54614,60 @@ class ForceGraphEngine {
|
|
|
54613
54614
|
constructor(board) {
|
|
54614
54615
|
this.board = board;
|
|
54615
54616
|
}
|
|
54616
|
-
|
|
54617
|
-
if (this.
|
|
54617
|
+
enableForGraph(startNodeId) {
|
|
54618
|
+
if (this.isNodeInActiveGraph(startNodeId))
|
|
54618
54619
|
return;
|
|
54619
|
-
|
|
54620
|
-
|
|
54621
|
-
|
|
54622
|
-
|
|
54620
|
+
const nodeIds = this.bfsComponent(startNodeId);
|
|
54621
|
+
const targetGap = this.calibrateTargetGap(nodeIds);
|
|
54622
|
+
this.activeComponents.set(startNodeId, { nodeIds, targetGap });
|
|
54623
|
+
for (const id of nodeIds) {
|
|
54624
|
+
if (!this.velocities.has(id)) {
|
|
54625
|
+
this.velocities.set(id, { vx: 0, vy: 0 });
|
|
54626
|
+
}
|
|
54627
|
+
const item = this.board.items.getById(id);
|
|
54628
|
+
if (item && !this.lastSyncedPositions.has(id)) {
|
|
54629
|
+
const pos = item.transformation.getTranslation();
|
|
54630
|
+
this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
|
|
54631
|
+
}
|
|
54632
|
+
}
|
|
54633
|
+
this.ensureRunning();
|
|
54634
|
+
}
|
|
54635
|
+
disableForGraph(nodeId) {
|
|
54636
|
+
const compId = this.findComponentId(nodeId);
|
|
54637
|
+
if (!compId)
|
|
54638
|
+
return;
|
|
54639
|
+
this.activeComponents.delete(compId);
|
|
54640
|
+
if (this.activeComponents.size === 0) {
|
|
54641
|
+
this.stopTimers();
|
|
54642
|
+
}
|
|
54643
|
+
}
|
|
54644
|
+
isNodeInActiveGraph(nodeId) {
|
|
54645
|
+
return !!this.findComponentId(nodeId);
|
|
54646
|
+
}
|
|
54647
|
+
hasActiveComponents() {
|
|
54648
|
+
return this.activeComponents.size > 0;
|
|
54649
|
+
}
|
|
54650
|
+
wake() {
|
|
54651
|
+
if (this.activeComponents.size > 0 && this.tickTimer === null) {
|
|
54652
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54623
54653
|
}
|
|
54624
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54625
|
-
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54626
54654
|
}
|
|
54627
54655
|
stop() {
|
|
54656
|
+
this.stopTimers();
|
|
54657
|
+
this.syncPositions();
|
|
54658
|
+
this.velocities.clear();
|
|
54659
|
+
this.lastSyncedPositions.clear();
|
|
54660
|
+
this.activeComponents.clear();
|
|
54661
|
+
}
|
|
54662
|
+
ensureRunning() {
|
|
54663
|
+
if (this.tickTimer === null) {
|
|
54664
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54665
|
+
}
|
|
54666
|
+
if (this.syncTimer === null) {
|
|
54667
|
+
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54668
|
+
}
|
|
54669
|
+
}
|
|
54670
|
+
stopTimers() {
|
|
54628
54671
|
if (this.tickTimer !== null) {
|
|
54629
54672
|
clearInterval(this.tickTimer);
|
|
54630
54673
|
this.tickTimer = null;
|
|
@@ -54633,9 +54676,56 @@ class ForceGraphEngine {
|
|
|
54633
54676
|
clearInterval(this.syncTimer);
|
|
54634
54677
|
this.syncTimer = null;
|
|
54635
54678
|
}
|
|
54636
|
-
|
|
54637
|
-
|
|
54638
|
-
this.
|
|
54679
|
+
}
|
|
54680
|
+
findComponentId(nodeId) {
|
|
54681
|
+
for (const [compId, { nodeIds }] of this.activeComponents) {
|
|
54682
|
+
if (nodeIds.has(nodeId))
|
|
54683
|
+
return compId;
|
|
54684
|
+
}
|
|
54685
|
+
return;
|
|
54686
|
+
}
|
|
54687
|
+
bfsComponent(startNodeId) {
|
|
54688
|
+
const visited = new Set;
|
|
54689
|
+
const queue = [startNodeId];
|
|
54690
|
+
const connectors = this.getConnectors();
|
|
54691
|
+
while (queue.length > 0) {
|
|
54692
|
+
const nodeId = queue.shift();
|
|
54693
|
+
if (visited.has(nodeId))
|
|
54694
|
+
continue;
|
|
54695
|
+
visited.add(nodeId);
|
|
54696
|
+
for (const connector of connectors) {
|
|
54697
|
+
const { startItem, endItem } = connector.getConnectedItems();
|
|
54698
|
+
if (startItem?.getId() === nodeId && endItem && !visited.has(endItem.getId())) {
|
|
54699
|
+
queue.push(endItem.getId());
|
|
54700
|
+
}
|
|
54701
|
+
if (endItem?.getId() === nodeId && startItem && !visited.has(startItem.getId())) {
|
|
54702
|
+
queue.push(startItem.getId());
|
|
54703
|
+
}
|
|
54704
|
+
}
|
|
54705
|
+
}
|
|
54706
|
+
return visited;
|
|
54707
|
+
}
|
|
54708
|
+
calibrateTargetGap(nodeIds) {
|
|
54709
|
+
let totalMaxDim = 0;
|
|
54710
|
+
let count = 0;
|
|
54711
|
+
for (const id of nodeIds) {
|
|
54712
|
+
const item = this.board.items.getById(id);
|
|
54713
|
+
if (!item)
|
|
54714
|
+
continue;
|
|
54715
|
+
const mbr = item.getMbr();
|
|
54716
|
+
totalMaxDim += Math.max(mbr.getWidth(), mbr.getHeight());
|
|
54717
|
+
count++;
|
|
54718
|
+
}
|
|
54719
|
+
const avgMaxDim = count > 0 ? totalMaxDim / count : 100;
|
|
54720
|
+
return avgMaxDim * 0.3 + conf.FG_TARGET_GAP;
|
|
54721
|
+
}
|
|
54722
|
+
getActiveNodeIds() {
|
|
54723
|
+
const all6 = new Set;
|
|
54724
|
+
for (const { nodeIds } of this.activeComponents.values()) {
|
|
54725
|
+
for (const id of nodeIds)
|
|
54726
|
+
all6.add(id);
|
|
54727
|
+
}
|
|
54728
|
+
return all6;
|
|
54639
54729
|
}
|
|
54640
54730
|
getNodes() {
|
|
54641
54731
|
return this.board.items.listAll().filter((item) => !EXCLUDED_TYPES.has(item.itemType) && !item.transformation.isLocked);
|
|
@@ -54645,8 +54735,10 @@ class ForceGraphEngine {
|
|
|
54645
54735
|
}
|
|
54646
54736
|
tick() {
|
|
54647
54737
|
const dt = this.TICK_MS / 1000;
|
|
54648
|
-
const
|
|
54649
|
-
|
|
54738
|
+
const activeIds = this.getActiveNodeIds();
|
|
54739
|
+
const allNodes = this.getNodes();
|
|
54740
|
+
const nodes = allNodes.filter((item) => activeIds.has(item.getId()));
|
|
54741
|
+
if (nodes.length < 1)
|
|
54650
54742
|
return;
|
|
54651
54743
|
const snapMap = new Map;
|
|
54652
54744
|
for (const item of nodes) {
|
|
@@ -54687,7 +54779,9 @@ class ForceGraphEngine {
|
|
|
54687
54779
|
const dx = s2.cx - s1.cx;
|
|
54688
54780
|
const dy = s2.cy - s1.cy;
|
|
54689
54781
|
const dist = Math.sqrt(dx * dx + dy * dy) + 0.001;
|
|
54690
|
-
const
|
|
54782
|
+
const compId = this.findComponentId(s1.id);
|
|
54783
|
+
const targetGap = compId ? this.activeComponents.get(compId)?.targetGap ?? conf.FG_TARGET_GAP : conf.FG_TARGET_GAP;
|
|
54784
|
+
const targetDist = (Math.max(s1.w, s1.h) + Math.max(s2.w, s2.h)) * 0.5 + targetGap;
|
|
54691
54785
|
const stretch = dist - targetDist;
|
|
54692
54786
|
const forceMag = stretch * conf.FG_SPRING_K;
|
|
54693
54787
|
const fx = dx / dist * forceMag;
|
|
@@ -54748,7 +54842,8 @@ class ForceGraphEngine {
|
|
|
54748
54842
|
}
|
|
54749
54843
|
}
|
|
54750
54844
|
syncPositions() {
|
|
54751
|
-
const
|
|
54845
|
+
const activeIds = this.getActiveNodeIds();
|
|
54846
|
+
const nodes = this.getNodes().filter((item) => activeIds.has(item.getId()));
|
|
54752
54847
|
if (nodes.length === 0)
|
|
54753
54848
|
return;
|
|
54754
54849
|
const movedItems = nodes.map((item) => {
|
|
@@ -54772,11 +54867,6 @@ class ForceGraphEngine {
|
|
|
54772
54867
|
};
|
|
54773
54868
|
this.board.events.emit(operation);
|
|
54774
54869
|
}
|
|
54775
|
-
wake() {
|
|
54776
|
-
if (this.tickTimer === null && this.syncTimer !== null) {
|
|
54777
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54778
|
-
}
|
|
54779
|
-
}
|
|
54780
54870
|
}
|
|
54781
54871
|
|
|
54782
54872
|
// src/Board.ts
|
|
@@ -55852,20 +55942,22 @@ class Board {
|
|
|
55852
55942
|
return this.gravity !== null;
|
|
55853
55943
|
}
|
|
55854
55944
|
forceGraph = null;
|
|
55855
|
-
enableForceGraph() {
|
|
55856
|
-
if (this.forceGraph)
|
|
55857
|
-
|
|
55858
|
-
|
|
55859
|
-
this.forceGraph.
|
|
55945
|
+
enableForceGraph(nodeId) {
|
|
55946
|
+
if (!this.forceGraph) {
|
|
55947
|
+
this.forceGraph = new ForceGraphEngine(this);
|
|
55948
|
+
}
|
|
55949
|
+
this.forceGraph.enableForGraph(nodeId);
|
|
55860
55950
|
}
|
|
55861
|
-
disableForceGraph() {
|
|
55951
|
+
disableForceGraph(nodeId) {
|
|
55862
55952
|
if (!this.forceGraph)
|
|
55863
55953
|
return;
|
|
55864
|
-
this.forceGraph.
|
|
55865
|
-
this.forceGraph
|
|
55954
|
+
this.forceGraph.disableForGraph(nodeId);
|
|
55955
|
+
if (!this.forceGraph.hasActiveComponents()) {
|
|
55956
|
+
this.forceGraph = null;
|
|
55957
|
+
}
|
|
55866
55958
|
}
|
|
55867
|
-
|
|
55868
|
-
return this.forceGraph
|
|
55959
|
+
isNodeInForceGraph(nodeId) {
|
|
55960
|
+
return this.forceGraph?.isNodeInActiveGraph(nodeId) ?? false;
|
|
55869
55961
|
}
|
|
55870
55962
|
wakeForceGraph() {
|
|
55871
55963
|
this.forceGraph?.wake();
|
package/dist/cjs/node.js
CHANGED
|
@@ -57079,6 +57079,7 @@ class ForceGraphEngine {
|
|
|
57079
57079
|
tickTimer = null;
|
|
57080
57080
|
syncTimer = null;
|
|
57081
57081
|
lastSyncedPositions = new Map;
|
|
57082
|
+
activeComponents = new Map;
|
|
57082
57083
|
TICK_MS = 33;
|
|
57083
57084
|
SYNC_MS = 300;
|
|
57084
57085
|
SOFTENING_SQ = 100 * 100;
|
|
@@ -57086,18 +57087,60 @@ class ForceGraphEngine {
|
|
|
57086
57087
|
constructor(board) {
|
|
57087
57088
|
this.board = board;
|
|
57088
57089
|
}
|
|
57089
|
-
|
|
57090
|
-
if (this.
|
|
57090
|
+
enableForGraph(startNodeId) {
|
|
57091
|
+
if (this.isNodeInActiveGraph(startNodeId))
|
|
57091
57092
|
return;
|
|
57092
|
-
|
|
57093
|
-
|
|
57094
|
-
|
|
57095
|
-
|
|
57093
|
+
const nodeIds = this.bfsComponent(startNodeId);
|
|
57094
|
+
const targetGap = this.calibrateTargetGap(nodeIds);
|
|
57095
|
+
this.activeComponents.set(startNodeId, { nodeIds, targetGap });
|
|
57096
|
+
for (const id of nodeIds) {
|
|
57097
|
+
if (!this.velocities.has(id)) {
|
|
57098
|
+
this.velocities.set(id, { vx: 0, vy: 0 });
|
|
57099
|
+
}
|
|
57100
|
+
const item = this.board.items.getById(id);
|
|
57101
|
+
if (item && !this.lastSyncedPositions.has(id)) {
|
|
57102
|
+
const pos = item.transformation.getTranslation();
|
|
57103
|
+
this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
|
|
57104
|
+
}
|
|
57105
|
+
}
|
|
57106
|
+
this.ensureRunning();
|
|
57107
|
+
}
|
|
57108
|
+
disableForGraph(nodeId) {
|
|
57109
|
+
const compId = this.findComponentId(nodeId);
|
|
57110
|
+
if (!compId)
|
|
57111
|
+
return;
|
|
57112
|
+
this.activeComponents.delete(compId);
|
|
57113
|
+
if (this.activeComponents.size === 0) {
|
|
57114
|
+
this.stopTimers();
|
|
57115
|
+
}
|
|
57116
|
+
}
|
|
57117
|
+
isNodeInActiveGraph(nodeId) {
|
|
57118
|
+
return !!this.findComponentId(nodeId);
|
|
57119
|
+
}
|
|
57120
|
+
hasActiveComponents() {
|
|
57121
|
+
return this.activeComponents.size > 0;
|
|
57122
|
+
}
|
|
57123
|
+
wake() {
|
|
57124
|
+
if (this.activeComponents.size > 0 && this.tickTimer === null) {
|
|
57125
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
57096
57126
|
}
|
|
57097
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
57098
|
-
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
57099
57127
|
}
|
|
57100
57128
|
stop() {
|
|
57129
|
+
this.stopTimers();
|
|
57130
|
+
this.syncPositions();
|
|
57131
|
+
this.velocities.clear();
|
|
57132
|
+
this.lastSyncedPositions.clear();
|
|
57133
|
+
this.activeComponents.clear();
|
|
57134
|
+
}
|
|
57135
|
+
ensureRunning() {
|
|
57136
|
+
if (this.tickTimer === null) {
|
|
57137
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
57138
|
+
}
|
|
57139
|
+
if (this.syncTimer === null) {
|
|
57140
|
+
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
57141
|
+
}
|
|
57142
|
+
}
|
|
57143
|
+
stopTimers() {
|
|
57101
57144
|
if (this.tickTimer !== null) {
|
|
57102
57145
|
clearInterval(this.tickTimer);
|
|
57103
57146
|
this.tickTimer = null;
|
|
@@ -57106,9 +57149,56 @@ class ForceGraphEngine {
|
|
|
57106
57149
|
clearInterval(this.syncTimer);
|
|
57107
57150
|
this.syncTimer = null;
|
|
57108
57151
|
}
|
|
57109
|
-
|
|
57110
|
-
|
|
57111
|
-
this.
|
|
57152
|
+
}
|
|
57153
|
+
findComponentId(nodeId) {
|
|
57154
|
+
for (const [compId, { nodeIds }] of this.activeComponents) {
|
|
57155
|
+
if (nodeIds.has(nodeId))
|
|
57156
|
+
return compId;
|
|
57157
|
+
}
|
|
57158
|
+
return;
|
|
57159
|
+
}
|
|
57160
|
+
bfsComponent(startNodeId) {
|
|
57161
|
+
const visited = new Set;
|
|
57162
|
+
const queue = [startNodeId];
|
|
57163
|
+
const connectors = this.getConnectors();
|
|
57164
|
+
while (queue.length > 0) {
|
|
57165
|
+
const nodeId = queue.shift();
|
|
57166
|
+
if (visited.has(nodeId))
|
|
57167
|
+
continue;
|
|
57168
|
+
visited.add(nodeId);
|
|
57169
|
+
for (const connector of connectors) {
|
|
57170
|
+
const { startItem, endItem } = connector.getConnectedItems();
|
|
57171
|
+
if (startItem?.getId() === nodeId && endItem && !visited.has(endItem.getId())) {
|
|
57172
|
+
queue.push(endItem.getId());
|
|
57173
|
+
}
|
|
57174
|
+
if (endItem?.getId() === nodeId && startItem && !visited.has(startItem.getId())) {
|
|
57175
|
+
queue.push(startItem.getId());
|
|
57176
|
+
}
|
|
57177
|
+
}
|
|
57178
|
+
}
|
|
57179
|
+
return visited;
|
|
57180
|
+
}
|
|
57181
|
+
calibrateTargetGap(nodeIds) {
|
|
57182
|
+
let totalMaxDim = 0;
|
|
57183
|
+
let count = 0;
|
|
57184
|
+
for (const id of nodeIds) {
|
|
57185
|
+
const item = this.board.items.getById(id);
|
|
57186
|
+
if (!item)
|
|
57187
|
+
continue;
|
|
57188
|
+
const mbr = item.getMbr();
|
|
57189
|
+
totalMaxDim += Math.max(mbr.getWidth(), mbr.getHeight());
|
|
57190
|
+
count++;
|
|
57191
|
+
}
|
|
57192
|
+
const avgMaxDim = count > 0 ? totalMaxDim / count : 100;
|
|
57193
|
+
return avgMaxDim * 0.3 + conf.FG_TARGET_GAP;
|
|
57194
|
+
}
|
|
57195
|
+
getActiveNodeIds() {
|
|
57196
|
+
const all6 = new Set;
|
|
57197
|
+
for (const { nodeIds } of this.activeComponents.values()) {
|
|
57198
|
+
for (const id of nodeIds)
|
|
57199
|
+
all6.add(id);
|
|
57200
|
+
}
|
|
57201
|
+
return all6;
|
|
57112
57202
|
}
|
|
57113
57203
|
getNodes() {
|
|
57114
57204
|
return this.board.items.listAll().filter((item) => !EXCLUDED_TYPES.has(item.itemType) && !item.transformation.isLocked);
|
|
@@ -57118,8 +57208,10 @@ class ForceGraphEngine {
|
|
|
57118
57208
|
}
|
|
57119
57209
|
tick() {
|
|
57120
57210
|
const dt = this.TICK_MS / 1000;
|
|
57121
|
-
const
|
|
57122
|
-
|
|
57211
|
+
const activeIds = this.getActiveNodeIds();
|
|
57212
|
+
const allNodes = this.getNodes();
|
|
57213
|
+
const nodes = allNodes.filter((item) => activeIds.has(item.getId()));
|
|
57214
|
+
if (nodes.length < 1)
|
|
57123
57215
|
return;
|
|
57124
57216
|
const snapMap = new Map;
|
|
57125
57217
|
for (const item of nodes) {
|
|
@@ -57160,7 +57252,9 @@ class ForceGraphEngine {
|
|
|
57160
57252
|
const dx = s2.cx - s1.cx;
|
|
57161
57253
|
const dy = s2.cy - s1.cy;
|
|
57162
57254
|
const dist = Math.sqrt(dx * dx + dy * dy) + 0.001;
|
|
57163
|
-
const
|
|
57255
|
+
const compId = this.findComponentId(s1.id);
|
|
57256
|
+
const targetGap = compId ? this.activeComponents.get(compId)?.targetGap ?? conf.FG_TARGET_GAP : conf.FG_TARGET_GAP;
|
|
57257
|
+
const targetDist = (Math.max(s1.w, s1.h) + Math.max(s2.w, s2.h)) * 0.5 + targetGap;
|
|
57164
57258
|
const stretch = dist - targetDist;
|
|
57165
57259
|
const forceMag = stretch * conf.FG_SPRING_K;
|
|
57166
57260
|
const fx = dx / dist * forceMag;
|
|
@@ -57221,7 +57315,8 @@ class ForceGraphEngine {
|
|
|
57221
57315
|
}
|
|
57222
57316
|
}
|
|
57223
57317
|
syncPositions() {
|
|
57224
|
-
const
|
|
57318
|
+
const activeIds = this.getActiveNodeIds();
|
|
57319
|
+
const nodes = this.getNodes().filter((item) => activeIds.has(item.getId()));
|
|
57225
57320
|
if (nodes.length === 0)
|
|
57226
57321
|
return;
|
|
57227
57322
|
const movedItems = nodes.map((item) => {
|
|
@@ -57245,11 +57340,6 @@ class ForceGraphEngine {
|
|
|
57245
57340
|
};
|
|
57246
57341
|
this.board.events.emit(operation);
|
|
57247
57342
|
}
|
|
57248
|
-
wake() {
|
|
57249
|
-
if (this.tickTimer === null && this.syncTimer !== null) {
|
|
57250
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
57251
|
-
}
|
|
57252
|
-
}
|
|
57253
57343
|
}
|
|
57254
57344
|
|
|
57255
57345
|
// src/Board.ts
|
|
@@ -58325,20 +58415,22 @@ class Board {
|
|
|
58325
58415
|
return this.gravity !== null;
|
|
58326
58416
|
}
|
|
58327
58417
|
forceGraph = null;
|
|
58328
|
-
enableForceGraph() {
|
|
58329
|
-
if (this.forceGraph)
|
|
58330
|
-
|
|
58331
|
-
|
|
58332
|
-
this.forceGraph.
|
|
58418
|
+
enableForceGraph(nodeId) {
|
|
58419
|
+
if (!this.forceGraph) {
|
|
58420
|
+
this.forceGraph = new ForceGraphEngine(this);
|
|
58421
|
+
}
|
|
58422
|
+
this.forceGraph.enableForGraph(nodeId);
|
|
58333
58423
|
}
|
|
58334
|
-
disableForceGraph() {
|
|
58424
|
+
disableForceGraph(nodeId) {
|
|
58335
58425
|
if (!this.forceGraph)
|
|
58336
58426
|
return;
|
|
58337
|
-
this.forceGraph.
|
|
58338
|
-
this.forceGraph
|
|
58427
|
+
this.forceGraph.disableForGraph(nodeId);
|
|
58428
|
+
if (!this.forceGraph.hasActiveComponents()) {
|
|
58429
|
+
this.forceGraph = null;
|
|
58430
|
+
}
|
|
58339
58431
|
}
|
|
58340
|
-
|
|
58341
|
-
return this.forceGraph
|
|
58432
|
+
isNodeInForceGraph(nodeId) {
|
|
58433
|
+
return this.forceGraph?.isNodeInActiveGraph(nodeId) ?? false;
|
|
58342
58434
|
}
|
|
58343
58435
|
wakeForceGraph() {
|
|
58344
58436
|
this.forceGraph?.wake();
|
package/dist/esm/browser.js
CHANGED
|
@@ -54435,6 +54435,7 @@ class ForceGraphEngine {
|
|
|
54435
54435
|
tickTimer = null;
|
|
54436
54436
|
syncTimer = null;
|
|
54437
54437
|
lastSyncedPositions = new Map;
|
|
54438
|
+
activeComponents = new Map;
|
|
54438
54439
|
TICK_MS = 33;
|
|
54439
54440
|
SYNC_MS = 300;
|
|
54440
54441
|
SOFTENING_SQ = 100 * 100;
|
|
@@ -54442,18 +54443,60 @@ class ForceGraphEngine {
|
|
|
54442
54443
|
constructor(board) {
|
|
54443
54444
|
this.board = board;
|
|
54444
54445
|
}
|
|
54445
|
-
|
|
54446
|
-
if (this.
|
|
54446
|
+
enableForGraph(startNodeId) {
|
|
54447
|
+
if (this.isNodeInActiveGraph(startNodeId))
|
|
54447
54448
|
return;
|
|
54448
|
-
|
|
54449
|
-
|
|
54450
|
-
|
|
54451
|
-
|
|
54449
|
+
const nodeIds = this.bfsComponent(startNodeId);
|
|
54450
|
+
const targetGap = this.calibrateTargetGap(nodeIds);
|
|
54451
|
+
this.activeComponents.set(startNodeId, { nodeIds, targetGap });
|
|
54452
|
+
for (const id of nodeIds) {
|
|
54453
|
+
if (!this.velocities.has(id)) {
|
|
54454
|
+
this.velocities.set(id, { vx: 0, vy: 0 });
|
|
54455
|
+
}
|
|
54456
|
+
const item = this.board.items.getById(id);
|
|
54457
|
+
if (item && !this.lastSyncedPositions.has(id)) {
|
|
54458
|
+
const pos = item.transformation.getTranslation();
|
|
54459
|
+
this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
|
|
54460
|
+
}
|
|
54461
|
+
}
|
|
54462
|
+
this.ensureRunning();
|
|
54463
|
+
}
|
|
54464
|
+
disableForGraph(nodeId) {
|
|
54465
|
+
const compId = this.findComponentId(nodeId);
|
|
54466
|
+
if (!compId)
|
|
54467
|
+
return;
|
|
54468
|
+
this.activeComponents.delete(compId);
|
|
54469
|
+
if (this.activeComponents.size === 0) {
|
|
54470
|
+
this.stopTimers();
|
|
54471
|
+
}
|
|
54472
|
+
}
|
|
54473
|
+
isNodeInActiveGraph(nodeId) {
|
|
54474
|
+
return !!this.findComponentId(nodeId);
|
|
54475
|
+
}
|
|
54476
|
+
hasActiveComponents() {
|
|
54477
|
+
return this.activeComponents.size > 0;
|
|
54478
|
+
}
|
|
54479
|
+
wake() {
|
|
54480
|
+
if (this.activeComponents.size > 0 && this.tickTimer === null) {
|
|
54481
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54452
54482
|
}
|
|
54453
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54454
|
-
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54455
54483
|
}
|
|
54456
54484
|
stop() {
|
|
54485
|
+
this.stopTimers();
|
|
54486
|
+
this.syncPositions();
|
|
54487
|
+
this.velocities.clear();
|
|
54488
|
+
this.lastSyncedPositions.clear();
|
|
54489
|
+
this.activeComponents.clear();
|
|
54490
|
+
}
|
|
54491
|
+
ensureRunning() {
|
|
54492
|
+
if (this.tickTimer === null) {
|
|
54493
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54494
|
+
}
|
|
54495
|
+
if (this.syncTimer === null) {
|
|
54496
|
+
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54497
|
+
}
|
|
54498
|
+
}
|
|
54499
|
+
stopTimers() {
|
|
54457
54500
|
if (this.tickTimer !== null) {
|
|
54458
54501
|
clearInterval(this.tickTimer);
|
|
54459
54502
|
this.tickTimer = null;
|
|
@@ -54462,9 +54505,56 @@ class ForceGraphEngine {
|
|
|
54462
54505
|
clearInterval(this.syncTimer);
|
|
54463
54506
|
this.syncTimer = null;
|
|
54464
54507
|
}
|
|
54465
|
-
|
|
54466
|
-
|
|
54467
|
-
this.
|
|
54508
|
+
}
|
|
54509
|
+
findComponentId(nodeId) {
|
|
54510
|
+
for (const [compId, { nodeIds }] of this.activeComponents) {
|
|
54511
|
+
if (nodeIds.has(nodeId))
|
|
54512
|
+
return compId;
|
|
54513
|
+
}
|
|
54514
|
+
return;
|
|
54515
|
+
}
|
|
54516
|
+
bfsComponent(startNodeId) {
|
|
54517
|
+
const visited = new Set;
|
|
54518
|
+
const queue = [startNodeId];
|
|
54519
|
+
const connectors = this.getConnectors();
|
|
54520
|
+
while (queue.length > 0) {
|
|
54521
|
+
const nodeId = queue.shift();
|
|
54522
|
+
if (visited.has(nodeId))
|
|
54523
|
+
continue;
|
|
54524
|
+
visited.add(nodeId);
|
|
54525
|
+
for (const connector of connectors) {
|
|
54526
|
+
const { startItem, endItem } = connector.getConnectedItems();
|
|
54527
|
+
if (startItem?.getId() === nodeId && endItem && !visited.has(endItem.getId())) {
|
|
54528
|
+
queue.push(endItem.getId());
|
|
54529
|
+
}
|
|
54530
|
+
if (endItem?.getId() === nodeId && startItem && !visited.has(startItem.getId())) {
|
|
54531
|
+
queue.push(startItem.getId());
|
|
54532
|
+
}
|
|
54533
|
+
}
|
|
54534
|
+
}
|
|
54535
|
+
return visited;
|
|
54536
|
+
}
|
|
54537
|
+
calibrateTargetGap(nodeIds) {
|
|
54538
|
+
let totalMaxDim = 0;
|
|
54539
|
+
let count = 0;
|
|
54540
|
+
for (const id of nodeIds) {
|
|
54541
|
+
const item = this.board.items.getById(id);
|
|
54542
|
+
if (!item)
|
|
54543
|
+
continue;
|
|
54544
|
+
const mbr = item.getMbr();
|
|
54545
|
+
totalMaxDim += Math.max(mbr.getWidth(), mbr.getHeight());
|
|
54546
|
+
count++;
|
|
54547
|
+
}
|
|
54548
|
+
const avgMaxDim = count > 0 ? totalMaxDim / count : 100;
|
|
54549
|
+
return avgMaxDim * 0.3 + conf.FG_TARGET_GAP;
|
|
54550
|
+
}
|
|
54551
|
+
getActiveNodeIds() {
|
|
54552
|
+
const all6 = new Set;
|
|
54553
|
+
for (const { nodeIds } of this.activeComponents.values()) {
|
|
54554
|
+
for (const id of nodeIds)
|
|
54555
|
+
all6.add(id);
|
|
54556
|
+
}
|
|
54557
|
+
return all6;
|
|
54468
54558
|
}
|
|
54469
54559
|
getNodes() {
|
|
54470
54560
|
return this.board.items.listAll().filter((item) => !EXCLUDED_TYPES.has(item.itemType) && !item.transformation.isLocked);
|
|
@@ -54474,8 +54564,10 @@ class ForceGraphEngine {
|
|
|
54474
54564
|
}
|
|
54475
54565
|
tick() {
|
|
54476
54566
|
const dt = this.TICK_MS / 1000;
|
|
54477
|
-
const
|
|
54478
|
-
|
|
54567
|
+
const activeIds = this.getActiveNodeIds();
|
|
54568
|
+
const allNodes = this.getNodes();
|
|
54569
|
+
const nodes = allNodes.filter((item) => activeIds.has(item.getId()));
|
|
54570
|
+
if (nodes.length < 1)
|
|
54479
54571
|
return;
|
|
54480
54572
|
const snapMap = new Map;
|
|
54481
54573
|
for (const item of nodes) {
|
|
@@ -54516,7 +54608,9 @@ class ForceGraphEngine {
|
|
|
54516
54608
|
const dx = s2.cx - s1.cx;
|
|
54517
54609
|
const dy = s2.cy - s1.cy;
|
|
54518
54610
|
const dist = Math.sqrt(dx * dx + dy * dy) + 0.001;
|
|
54519
|
-
const
|
|
54611
|
+
const compId = this.findComponentId(s1.id);
|
|
54612
|
+
const targetGap = compId ? this.activeComponents.get(compId)?.targetGap ?? conf.FG_TARGET_GAP : conf.FG_TARGET_GAP;
|
|
54613
|
+
const targetDist = (Math.max(s1.w, s1.h) + Math.max(s2.w, s2.h)) * 0.5 + targetGap;
|
|
54520
54614
|
const stretch = dist - targetDist;
|
|
54521
54615
|
const forceMag = stretch * conf.FG_SPRING_K;
|
|
54522
54616
|
const fx = dx / dist * forceMag;
|
|
@@ -54577,7 +54671,8 @@ class ForceGraphEngine {
|
|
|
54577
54671
|
}
|
|
54578
54672
|
}
|
|
54579
54673
|
syncPositions() {
|
|
54580
|
-
const
|
|
54674
|
+
const activeIds = this.getActiveNodeIds();
|
|
54675
|
+
const nodes = this.getNodes().filter((item) => activeIds.has(item.getId()));
|
|
54581
54676
|
if (nodes.length === 0)
|
|
54582
54677
|
return;
|
|
54583
54678
|
const movedItems = nodes.map((item) => {
|
|
@@ -54601,11 +54696,6 @@ class ForceGraphEngine {
|
|
|
54601
54696
|
};
|
|
54602
54697
|
this.board.events.emit(operation);
|
|
54603
54698
|
}
|
|
54604
|
-
wake() {
|
|
54605
|
-
if (this.tickTimer === null && this.syncTimer !== null) {
|
|
54606
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54607
|
-
}
|
|
54608
|
-
}
|
|
54609
54699
|
}
|
|
54610
54700
|
|
|
54611
54701
|
// src/Board.ts
|
|
@@ -55681,20 +55771,22 @@ class Board {
|
|
|
55681
55771
|
return this.gravity !== null;
|
|
55682
55772
|
}
|
|
55683
55773
|
forceGraph = null;
|
|
55684
|
-
enableForceGraph() {
|
|
55685
|
-
if (this.forceGraph)
|
|
55686
|
-
|
|
55687
|
-
|
|
55688
|
-
this.forceGraph.
|
|
55774
|
+
enableForceGraph(nodeId) {
|
|
55775
|
+
if (!this.forceGraph) {
|
|
55776
|
+
this.forceGraph = new ForceGraphEngine(this);
|
|
55777
|
+
}
|
|
55778
|
+
this.forceGraph.enableForGraph(nodeId);
|
|
55689
55779
|
}
|
|
55690
|
-
disableForceGraph() {
|
|
55780
|
+
disableForceGraph(nodeId) {
|
|
55691
55781
|
if (!this.forceGraph)
|
|
55692
55782
|
return;
|
|
55693
|
-
this.forceGraph.
|
|
55694
|
-
this.forceGraph
|
|
55783
|
+
this.forceGraph.disableForGraph(nodeId);
|
|
55784
|
+
if (!this.forceGraph.hasActiveComponents()) {
|
|
55785
|
+
this.forceGraph = null;
|
|
55786
|
+
}
|
|
55695
55787
|
}
|
|
55696
|
-
|
|
55697
|
-
return this.forceGraph
|
|
55788
|
+
isNodeInForceGraph(nodeId) {
|
|
55789
|
+
return this.forceGraph?.isNodeInActiveGraph(nodeId) ?? false;
|
|
55698
55790
|
}
|
|
55699
55791
|
wakeForceGraph() {
|
|
55700
55792
|
this.forceGraph?.wake();
|
package/dist/esm/index.js
CHANGED
|
@@ -54428,6 +54428,7 @@ class ForceGraphEngine {
|
|
|
54428
54428
|
tickTimer = null;
|
|
54429
54429
|
syncTimer = null;
|
|
54430
54430
|
lastSyncedPositions = new Map;
|
|
54431
|
+
activeComponents = new Map;
|
|
54431
54432
|
TICK_MS = 33;
|
|
54432
54433
|
SYNC_MS = 300;
|
|
54433
54434
|
SOFTENING_SQ = 100 * 100;
|
|
@@ -54435,18 +54436,60 @@ class ForceGraphEngine {
|
|
|
54435
54436
|
constructor(board) {
|
|
54436
54437
|
this.board = board;
|
|
54437
54438
|
}
|
|
54438
|
-
|
|
54439
|
-
if (this.
|
|
54439
|
+
enableForGraph(startNodeId) {
|
|
54440
|
+
if (this.isNodeInActiveGraph(startNodeId))
|
|
54440
54441
|
return;
|
|
54441
|
-
|
|
54442
|
-
|
|
54443
|
-
|
|
54444
|
-
|
|
54442
|
+
const nodeIds = this.bfsComponent(startNodeId);
|
|
54443
|
+
const targetGap = this.calibrateTargetGap(nodeIds);
|
|
54444
|
+
this.activeComponents.set(startNodeId, { nodeIds, targetGap });
|
|
54445
|
+
for (const id of nodeIds) {
|
|
54446
|
+
if (!this.velocities.has(id)) {
|
|
54447
|
+
this.velocities.set(id, { vx: 0, vy: 0 });
|
|
54448
|
+
}
|
|
54449
|
+
const item = this.board.items.getById(id);
|
|
54450
|
+
if (item && !this.lastSyncedPositions.has(id)) {
|
|
54451
|
+
const pos = item.transformation.getTranslation();
|
|
54452
|
+
this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
|
|
54453
|
+
}
|
|
54454
|
+
}
|
|
54455
|
+
this.ensureRunning();
|
|
54456
|
+
}
|
|
54457
|
+
disableForGraph(nodeId) {
|
|
54458
|
+
const compId = this.findComponentId(nodeId);
|
|
54459
|
+
if (!compId)
|
|
54460
|
+
return;
|
|
54461
|
+
this.activeComponents.delete(compId);
|
|
54462
|
+
if (this.activeComponents.size === 0) {
|
|
54463
|
+
this.stopTimers();
|
|
54464
|
+
}
|
|
54465
|
+
}
|
|
54466
|
+
isNodeInActiveGraph(nodeId) {
|
|
54467
|
+
return !!this.findComponentId(nodeId);
|
|
54468
|
+
}
|
|
54469
|
+
hasActiveComponents() {
|
|
54470
|
+
return this.activeComponents.size > 0;
|
|
54471
|
+
}
|
|
54472
|
+
wake() {
|
|
54473
|
+
if (this.activeComponents.size > 0 && this.tickTimer === null) {
|
|
54474
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54445
54475
|
}
|
|
54446
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54447
|
-
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54448
54476
|
}
|
|
54449
54477
|
stop() {
|
|
54478
|
+
this.stopTimers();
|
|
54479
|
+
this.syncPositions();
|
|
54480
|
+
this.velocities.clear();
|
|
54481
|
+
this.lastSyncedPositions.clear();
|
|
54482
|
+
this.activeComponents.clear();
|
|
54483
|
+
}
|
|
54484
|
+
ensureRunning() {
|
|
54485
|
+
if (this.tickTimer === null) {
|
|
54486
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54487
|
+
}
|
|
54488
|
+
if (this.syncTimer === null) {
|
|
54489
|
+
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
54490
|
+
}
|
|
54491
|
+
}
|
|
54492
|
+
stopTimers() {
|
|
54450
54493
|
if (this.tickTimer !== null) {
|
|
54451
54494
|
clearInterval(this.tickTimer);
|
|
54452
54495
|
this.tickTimer = null;
|
|
@@ -54455,9 +54498,56 @@ class ForceGraphEngine {
|
|
|
54455
54498
|
clearInterval(this.syncTimer);
|
|
54456
54499
|
this.syncTimer = null;
|
|
54457
54500
|
}
|
|
54458
|
-
|
|
54459
|
-
|
|
54460
|
-
this.
|
|
54501
|
+
}
|
|
54502
|
+
findComponentId(nodeId) {
|
|
54503
|
+
for (const [compId, { nodeIds }] of this.activeComponents) {
|
|
54504
|
+
if (nodeIds.has(nodeId))
|
|
54505
|
+
return compId;
|
|
54506
|
+
}
|
|
54507
|
+
return;
|
|
54508
|
+
}
|
|
54509
|
+
bfsComponent(startNodeId) {
|
|
54510
|
+
const visited = new Set;
|
|
54511
|
+
const queue = [startNodeId];
|
|
54512
|
+
const connectors = this.getConnectors();
|
|
54513
|
+
while (queue.length > 0) {
|
|
54514
|
+
const nodeId = queue.shift();
|
|
54515
|
+
if (visited.has(nodeId))
|
|
54516
|
+
continue;
|
|
54517
|
+
visited.add(nodeId);
|
|
54518
|
+
for (const connector of connectors) {
|
|
54519
|
+
const { startItem, endItem } = connector.getConnectedItems();
|
|
54520
|
+
if (startItem?.getId() === nodeId && endItem && !visited.has(endItem.getId())) {
|
|
54521
|
+
queue.push(endItem.getId());
|
|
54522
|
+
}
|
|
54523
|
+
if (endItem?.getId() === nodeId && startItem && !visited.has(startItem.getId())) {
|
|
54524
|
+
queue.push(startItem.getId());
|
|
54525
|
+
}
|
|
54526
|
+
}
|
|
54527
|
+
}
|
|
54528
|
+
return visited;
|
|
54529
|
+
}
|
|
54530
|
+
calibrateTargetGap(nodeIds) {
|
|
54531
|
+
let totalMaxDim = 0;
|
|
54532
|
+
let count = 0;
|
|
54533
|
+
for (const id of nodeIds) {
|
|
54534
|
+
const item = this.board.items.getById(id);
|
|
54535
|
+
if (!item)
|
|
54536
|
+
continue;
|
|
54537
|
+
const mbr = item.getMbr();
|
|
54538
|
+
totalMaxDim += Math.max(mbr.getWidth(), mbr.getHeight());
|
|
54539
|
+
count++;
|
|
54540
|
+
}
|
|
54541
|
+
const avgMaxDim = count > 0 ? totalMaxDim / count : 100;
|
|
54542
|
+
return avgMaxDim * 0.3 + conf.FG_TARGET_GAP;
|
|
54543
|
+
}
|
|
54544
|
+
getActiveNodeIds() {
|
|
54545
|
+
const all6 = new Set;
|
|
54546
|
+
for (const { nodeIds } of this.activeComponents.values()) {
|
|
54547
|
+
for (const id of nodeIds)
|
|
54548
|
+
all6.add(id);
|
|
54549
|
+
}
|
|
54550
|
+
return all6;
|
|
54461
54551
|
}
|
|
54462
54552
|
getNodes() {
|
|
54463
54553
|
return this.board.items.listAll().filter((item) => !EXCLUDED_TYPES.has(item.itemType) && !item.transformation.isLocked);
|
|
@@ -54467,8 +54557,10 @@ class ForceGraphEngine {
|
|
|
54467
54557
|
}
|
|
54468
54558
|
tick() {
|
|
54469
54559
|
const dt = this.TICK_MS / 1000;
|
|
54470
|
-
const
|
|
54471
|
-
|
|
54560
|
+
const activeIds = this.getActiveNodeIds();
|
|
54561
|
+
const allNodes = this.getNodes();
|
|
54562
|
+
const nodes = allNodes.filter((item) => activeIds.has(item.getId()));
|
|
54563
|
+
if (nodes.length < 1)
|
|
54472
54564
|
return;
|
|
54473
54565
|
const snapMap = new Map;
|
|
54474
54566
|
for (const item of nodes) {
|
|
@@ -54509,7 +54601,9 @@ class ForceGraphEngine {
|
|
|
54509
54601
|
const dx = s2.cx - s1.cx;
|
|
54510
54602
|
const dy = s2.cy - s1.cy;
|
|
54511
54603
|
const dist = Math.sqrt(dx * dx + dy * dy) + 0.001;
|
|
54512
|
-
const
|
|
54604
|
+
const compId = this.findComponentId(s1.id);
|
|
54605
|
+
const targetGap = compId ? this.activeComponents.get(compId)?.targetGap ?? conf.FG_TARGET_GAP : conf.FG_TARGET_GAP;
|
|
54606
|
+
const targetDist = (Math.max(s1.w, s1.h) + Math.max(s2.w, s2.h)) * 0.5 + targetGap;
|
|
54513
54607
|
const stretch = dist - targetDist;
|
|
54514
54608
|
const forceMag = stretch * conf.FG_SPRING_K;
|
|
54515
54609
|
const fx = dx / dist * forceMag;
|
|
@@ -54570,7 +54664,8 @@ class ForceGraphEngine {
|
|
|
54570
54664
|
}
|
|
54571
54665
|
}
|
|
54572
54666
|
syncPositions() {
|
|
54573
|
-
const
|
|
54667
|
+
const activeIds = this.getActiveNodeIds();
|
|
54668
|
+
const nodes = this.getNodes().filter((item) => activeIds.has(item.getId()));
|
|
54574
54669
|
if (nodes.length === 0)
|
|
54575
54670
|
return;
|
|
54576
54671
|
const movedItems = nodes.map((item) => {
|
|
@@ -54594,11 +54689,6 @@ class ForceGraphEngine {
|
|
|
54594
54689
|
};
|
|
54595
54690
|
this.board.events.emit(operation);
|
|
54596
54691
|
}
|
|
54597
|
-
wake() {
|
|
54598
|
-
if (this.tickTimer === null && this.syncTimer !== null) {
|
|
54599
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
54600
|
-
}
|
|
54601
|
-
}
|
|
54602
54692
|
}
|
|
54603
54693
|
|
|
54604
54694
|
// src/Board.ts
|
|
@@ -55674,20 +55764,22 @@ class Board {
|
|
|
55674
55764
|
return this.gravity !== null;
|
|
55675
55765
|
}
|
|
55676
55766
|
forceGraph = null;
|
|
55677
|
-
enableForceGraph() {
|
|
55678
|
-
if (this.forceGraph)
|
|
55679
|
-
|
|
55680
|
-
|
|
55681
|
-
this.forceGraph.
|
|
55767
|
+
enableForceGraph(nodeId) {
|
|
55768
|
+
if (!this.forceGraph) {
|
|
55769
|
+
this.forceGraph = new ForceGraphEngine(this);
|
|
55770
|
+
}
|
|
55771
|
+
this.forceGraph.enableForGraph(nodeId);
|
|
55682
55772
|
}
|
|
55683
|
-
disableForceGraph() {
|
|
55773
|
+
disableForceGraph(nodeId) {
|
|
55684
55774
|
if (!this.forceGraph)
|
|
55685
55775
|
return;
|
|
55686
|
-
this.forceGraph.
|
|
55687
|
-
this.forceGraph
|
|
55776
|
+
this.forceGraph.disableForGraph(nodeId);
|
|
55777
|
+
if (!this.forceGraph.hasActiveComponents()) {
|
|
55778
|
+
this.forceGraph = null;
|
|
55779
|
+
}
|
|
55688
55780
|
}
|
|
55689
|
-
|
|
55690
|
-
return this.forceGraph
|
|
55781
|
+
isNodeInForceGraph(nodeId) {
|
|
55782
|
+
return this.forceGraph?.isNodeInActiveGraph(nodeId) ?? false;
|
|
55691
55783
|
}
|
|
55692
55784
|
wakeForceGraph() {
|
|
55693
55785
|
this.forceGraph?.wake();
|
package/dist/esm/node.js
CHANGED
|
@@ -56896,6 +56896,7 @@ class ForceGraphEngine {
|
|
|
56896
56896
|
tickTimer = null;
|
|
56897
56897
|
syncTimer = null;
|
|
56898
56898
|
lastSyncedPositions = new Map;
|
|
56899
|
+
activeComponents = new Map;
|
|
56899
56900
|
TICK_MS = 33;
|
|
56900
56901
|
SYNC_MS = 300;
|
|
56901
56902
|
SOFTENING_SQ = 100 * 100;
|
|
@@ -56903,18 +56904,60 @@ class ForceGraphEngine {
|
|
|
56903
56904
|
constructor(board) {
|
|
56904
56905
|
this.board = board;
|
|
56905
56906
|
}
|
|
56906
|
-
|
|
56907
|
-
if (this.
|
|
56907
|
+
enableForGraph(startNodeId) {
|
|
56908
|
+
if (this.isNodeInActiveGraph(startNodeId))
|
|
56908
56909
|
return;
|
|
56909
|
-
|
|
56910
|
-
|
|
56911
|
-
|
|
56912
|
-
|
|
56910
|
+
const nodeIds = this.bfsComponent(startNodeId);
|
|
56911
|
+
const targetGap = this.calibrateTargetGap(nodeIds);
|
|
56912
|
+
this.activeComponents.set(startNodeId, { nodeIds, targetGap });
|
|
56913
|
+
for (const id of nodeIds) {
|
|
56914
|
+
if (!this.velocities.has(id)) {
|
|
56915
|
+
this.velocities.set(id, { vx: 0, vy: 0 });
|
|
56916
|
+
}
|
|
56917
|
+
const item = this.board.items.getById(id);
|
|
56918
|
+
if (item && !this.lastSyncedPositions.has(id)) {
|
|
56919
|
+
const pos = item.transformation.getTranslation();
|
|
56920
|
+
this.lastSyncedPositions.set(id, { x: pos.x, y: pos.y });
|
|
56921
|
+
}
|
|
56922
|
+
}
|
|
56923
|
+
this.ensureRunning();
|
|
56924
|
+
}
|
|
56925
|
+
disableForGraph(nodeId) {
|
|
56926
|
+
const compId = this.findComponentId(nodeId);
|
|
56927
|
+
if (!compId)
|
|
56928
|
+
return;
|
|
56929
|
+
this.activeComponents.delete(compId);
|
|
56930
|
+
if (this.activeComponents.size === 0) {
|
|
56931
|
+
this.stopTimers();
|
|
56932
|
+
}
|
|
56933
|
+
}
|
|
56934
|
+
isNodeInActiveGraph(nodeId) {
|
|
56935
|
+
return !!this.findComponentId(nodeId);
|
|
56936
|
+
}
|
|
56937
|
+
hasActiveComponents() {
|
|
56938
|
+
return this.activeComponents.size > 0;
|
|
56939
|
+
}
|
|
56940
|
+
wake() {
|
|
56941
|
+
if (this.activeComponents.size > 0 && this.tickTimer === null) {
|
|
56942
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
56913
56943
|
}
|
|
56914
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
56915
|
-
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
56916
56944
|
}
|
|
56917
56945
|
stop() {
|
|
56946
|
+
this.stopTimers();
|
|
56947
|
+
this.syncPositions();
|
|
56948
|
+
this.velocities.clear();
|
|
56949
|
+
this.lastSyncedPositions.clear();
|
|
56950
|
+
this.activeComponents.clear();
|
|
56951
|
+
}
|
|
56952
|
+
ensureRunning() {
|
|
56953
|
+
if (this.tickTimer === null) {
|
|
56954
|
+
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
56955
|
+
}
|
|
56956
|
+
if (this.syncTimer === null) {
|
|
56957
|
+
this.syncTimer = setInterval(() => this.syncPositions(), this.SYNC_MS);
|
|
56958
|
+
}
|
|
56959
|
+
}
|
|
56960
|
+
stopTimers() {
|
|
56918
56961
|
if (this.tickTimer !== null) {
|
|
56919
56962
|
clearInterval(this.tickTimer);
|
|
56920
56963
|
this.tickTimer = null;
|
|
@@ -56923,9 +56966,56 @@ class ForceGraphEngine {
|
|
|
56923
56966
|
clearInterval(this.syncTimer);
|
|
56924
56967
|
this.syncTimer = null;
|
|
56925
56968
|
}
|
|
56926
|
-
|
|
56927
|
-
|
|
56928
|
-
this.
|
|
56969
|
+
}
|
|
56970
|
+
findComponentId(nodeId) {
|
|
56971
|
+
for (const [compId, { nodeIds }] of this.activeComponents) {
|
|
56972
|
+
if (nodeIds.has(nodeId))
|
|
56973
|
+
return compId;
|
|
56974
|
+
}
|
|
56975
|
+
return;
|
|
56976
|
+
}
|
|
56977
|
+
bfsComponent(startNodeId) {
|
|
56978
|
+
const visited = new Set;
|
|
56979
|
+
const queue = [startNodeId];
|
|
56980
|
+
const connectors = this.getConnectors();
|
|
56981
|
+
while (queue.length > 0) {
|
|
56982
|
+
const nodeId = queue.shift();
|
|
56983
|
+
if (visited.has(nodeId))
|
|
56984
|
+
continue;
|
|
56985
|
+
visited.add(nodeId);
|
|
56986
|
+
for (const connector of connectors) {
|
|
56987
|
+
const { startItem, endItem } = connector.getConnectedItems();
|
|
56988
|
+
if (startItem?.getId() === nodeId && endItem && !visited.has(endItem.getId())) {
|
|
56989
|
+
queue.push(endItem.getId());
|
|
56990
|
+
}
|
|
56991
|
+
if (endItem?.getId() === nodeId && startItem && !visited.has(startItem.getId())) {
|
|
56992
|
+
queue.push(startItem.getId());
|
|
56993
|
+
}
|
|
56994
|
+
}
|
|
56995
|
+
}
|
|
56996
|
+
return visited;
|
|
56997
|
+
}
|
|
56998
|
+
calibrateTargetGap(nodeIds) {
|
|
56999
|
+
let totalMaxDim = 0;
|
|
57000
|
+
let count = 0;
|
|
57001
|
+
for (const id of nodeIds) {
|
|
57002
|
+
const item = this.board.items.getById(id);
|
|
57003
|
+
if (!item)
|
|
57004
|
+
continue;
|
|
57005
|
+
const mbr = item.getMbr();
|
|
57006
|
+
totalMaxDim += Math.max(mbr.getWidth(), mbr.getHeight());
|
|
57007
|
+
count++;
|
|
57008
|
+
}
|
|
57009
|
+
const avgMaxDim = count > 0 ? totalMaxDim / count : 100;
|
|
57010
|
+
return avgMaxDim * 0.3 + conf.FG_TARGET_GAP;
|
|
57011
|
+
}
|
|
57012
|
+
getActiveNodeIds() {
|
|
57013
|
+
const all6 = new Set;
|
|
57014
|
+
for (const { nodeIds } of this.activeComponents.values()) {
|
|
57015
|
+
for (const id of nodeIds)
|
|
57016
|
+
all6.add(id);
|
|
57017
|
+
}
|
|
57018
|
+
return all6;
|
|
56929
57019
|
}
|
|
56930
57020
|
getNodes() {
|
|
56931
57021
|
return this.board.items.listAll().filter((item) => !EXCLUDED_TYPES.has(item.itemType) && !item.transformation.isLocked);
|
|
@@ -56935,8 +57025,10 @@ class ForceGraphEngine {
|
|
|
56935
57025
|
}
|
|
56936
57026
|
tick() {
|
|
56937
57027
|
const dt = this.TICK_MS / 1000;
|
|
56938
|
-
const
|
|
56939
|
-
|
|
57028
|
+
const activeIds = this.getActiveNodeIds();
|
|
57029
|
+
const allNodes = this.getNodes();
|
|
57030
|
+
const nodes = allNodes.filter((item) => activeIds.has(item.getId()));
|
|
57031
|
+
if (nodes.length < 1)
|
|
56940
57032
|
return;
|
|
56941
57033
|
const snapMap = new Map;
|
|
56942
57034
|
for (const item of nodes) {
|
|
@@ -56977,7 +57069,9 @@ class ForceGraphEngine {
|
|
|
56977
57069
|
const dx = s2.cx - s1.cx;
|
|
56978
57070
|
const dy = s2.cy - s1.cy;
|
|
56979
57071
|
const dist = Math.sqrt(dx * dx + dy * dy) + 0.001;
|
|
56980
|
-
const
|
|
57072
|
+
const compId = this.findComponentId(s1.id);
|
|
57073
|
+
const targetGap = compId ? this.activeComponents.get(compId)?.targetGap ?? conf.FG_TARGET_GAP : conf.FG_TARGET_GAP;
|
|
57074
|
+
const targetDist = (Math.max(s1.w, s1.h) + Math.max(s2.w, s2.h)) * 0.5 + targetGap;
|
|
56981
57075
|
const stretch = dist - targetDist;
|
|
56982
57076
|
const forceMag = stretch * conf.FG_SPRING_K;
|
|
56983
57077
|
const fx = dx / dist * forceMag;
|
|
@@ -57038,7 +57132,8 @@ class ForceGraphEngine {
|
|
|
57038
57132
|
}
|
|
57039
57133
|
}
|
|
57040
57134
|
syncPositions() {
|
|
57041
|
-
const
|
|
57135
|
+
const activeIds = this.getActiveNodeIds();
|
|
57136
|
+
const nodes = this.getNodes().filter((item) => activeIds.has(item.getId()));
|
|
57042
57137
|
if (nodes.length === 0)
|
|
57043
57138
|
return;
|
|
57044
57139
|
const movedItems = nodes.map((item) => {
|
|
@@ -57062,11 +57157,6 @@ class ForceGraphEngine {
|
|
|
57062
57157
|
};
|
|
57063
57158
|
this.board.events.emit(operation);
|
|
57064
57159
|
}
|
|
57065
|
-
wake() {
|
|
57066
|
-
if (this.tickTimer === null && this.syncTimer !== null) {
|
|
57067
|
-
this.tickTimer = setInterval(() => this.tick(), this.TICK_MS);
|
|
57068
|
-
}
|
|
57069
|
-
}
|
|
57070
57160
|
}
|
|
57071
57161
|
|
|
57072
57162
|
// src/Board.ts
|
|
@@ -58142,20 +58232,22 @@ class Board {
|
|
|
58142
58232
|
return this.gravity !== null;
|
|
58143
58233
|
}
|
|
58144
58234
|
forceGraph = null;
|
|
58145
|
-
enableForceGraph() {
|
|
58146
|
-
if (this.forceGraph)
|
|
58147
|
-
|
|
58148
|
-
|
|
58149
|
-
this.forceGraph.
|
|
58235
|
+
enableForceGraph(nodeId) {
|
|
58236
|
+
if (!this.forceGraph) {
|
|
58237
|
+
this.forceGraph = new ForceGraphEngine(this);
|
|
58238
|
+
}
|
|
58239
|
+
this.forceGraph.enableForGraph(nodeId);
|
|
58150
58240
|
}
|
|
58151
|
-
disableForceGraph() {
|
|
58241
|
+
disableForceGraph(nodeId) {
|
|
58152
58242
|
if (!this.forceGraph)
|
|
58153
58243
|
return;
|
|
58154
|
-
this.forceGraph.
|
|
58155
|
-
this.forceGraph
|
|
58244
|
+
this.forceGraph.disableForGraph(nodeId);
|
|
58245
|
+
if (!this.forceGraph.hasActiveComponents()) {
|
|
58246
|
+
this.forceGraph = null;
|
|
58247
|
+
}
|
|
58156
58248
|
}
|
|
58157
|
-
|
|
58158
|
-
return this.forceGraph
|
|
58249
|
+
isNodeInForceGraph(nodeId) {
|
|
58250
|
+
return this.forceGraph?.isNodeInActiveGraph(nodeId) ?? false;
|
|
58159
58251
|
}
|
|
58160
58252
|
wakeForceGraph() {
|
|
58161
58253
|
this.forceGraph?.wake();
|
package/dist/types/Board.d.ts
CHANGED
|
@@ -140,9 +140,12 @@ export declare class Board {
|
|
|
140
140
|
disableGravity(): void;
|
|
141
141
|
isGravityEnabled(): boolean;
|
|
142
142
|
private forceGraph;
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
143
|
+
/** Enable force-directed layout for the connected component containing `nodeId`. */
|
|
144
|
+
enableForceGraph(nodeId: string): void;
|
|
145
|
+
/** Disable graph mode for the component containing `nodeId`. */
|
|
146
|
+
disableForceGraph(nodeId: string): void;
|
|
147
|
+
/** Returns true if `nodeId` is currently in an active force-directed component. */
|
|
148
|
+
isNodeInForceGraph(nodeId: string): boolean;
|
|
146
149
|
/** Call after dragging a node to re-wake the physics engine if it was sleeping. */
|
|
147
150
|
wakeForceGraph(): void;
|
|
148
151
|
}
|
|
@@ -5,17 +5,45 @@ export declare class ForceGraphEngine {
|
|
|
5
5
|
private tickTimer;
|
|
6
6
|
private syncTimer;
|
|
7
7
|
private lastSyncedPositions;
|
|
8
|
+
/** Active components: componentId → { nodeIds, targetGap }
|
|
9
|
+
* componentId is the nodeId that was passed to enableForGraph(). */
|
|
10
|
+
private activeComponents;
|
|
8
11
|
private readonly TICK_MS;
|
|
9
12
|
private readonly SYNC_MS;
|
|
10
13
|
private readonly SOFTENING_SQ;
|
|
11
14
|
private readonly MIN_MOVE_PX;
|
|
12
15
|
constructor(board: Board);
|
|
13
|
-
|
|
16
|
+
/**
|
|
17
|
+
* Enable force-directed layout for the connected component containing `startNodeId`.
|
|
18
|
+
* BFS walks the connector graph to find all nodes in the component.
|
|
19
|
+
* `targetGap` is auto-calibrated from the average node size; callers may override via conf.
|
|
20
|
+
*/
|
|
21
|
+
enableForGraph(startNodeId: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Disable graph mode for the component containing `nodeId`.
|
|
24
|
+
* Stops the engine entirely if no components remain active.
|
|
25
|
+
*/
|
|
26
|
+
disableForGraph(nodeId: string): void;
|
|
27
|
+
isNodeInActiveGraph(nodeId: string): boolean;
|
|
28
|
+
hasActiveComponents(): boolean;
|
|
29
|
+
/** Re-wake physics after a node is manually dragged. */
|
|
30
|
+
wake(): void;
|
|
31
|
+
/** Full stop — called when Board destroys the engine. */
|
|
14
32
|
stop(): void;
|
|
33
|
+
private ensureRunning;
|
|
34
|
+
private stopTimers;
|
|
35
|
+
/** Find the componentId (Map key) for the component containing `nodeId`. */
|
|
36
|
+
private findComponentId;
|
|
37
|
+
/** BFS through connector graph starting from `startNodeId`. */
|
|
38
|
+
private bfsComponent;
|
|
39
|
+
/**
|
|
40
|
+
* Auto-calibrate spring target gap from the average max(w, h) of nodes in the component.
|
|
41
|
+
* Larger nodes → longer springs so items visually breathe.
|
|
42
|
+
*/
|
|
43
|
+
private calibrateTargetGap;
|
|
44
|
+
private getActiveNodeIds;
|
|
15
45
|
private getNodes;
|
|
16
46
|
private getConnectors;
|
|
17
47
|
private tick;
|
|
18
48
|
private syncPositions;
|
|
19
|
-
/** Re-wake the engine after user moves a node (dragging disturbs equilibrium). */
|
|
20
|
-
wake(): void;
|
|
21
49
|
}
|