MCPcopy Create free account
hub / github.com/ScriptedAlchemy/tracedecay / createSimulation

Function createSimulation

dashboard/graph/src/simulation.ts:60–226  ·  view source on GitHub ↗
(
  nodes: GraphNode[],
  edges: GraphEdge[],
  previous?: Simulation | null,
  anchorId?: string | null,
)

Source from the content-addressed store, hash-verified

58 * already exist in `previous` so progressive expansion feels stable.
59 */
60export function createSimulation(
61 nodes: GraphNode[],
62 edges: GraphEdge[],
63 previous?: Simulation | null,
64 anchorId?: string | null,
65): Simulation {
66 const prevById = new Map<string, SimNode>();
67 if (previous) {
68 for (const node of previous.nodes) prevById.set(node.id, node);
69 }
70 const anchor = anchorId ? prevById.get(anchorId) : undefined;
71 const cx = anchor ? anchor.x : 0;
72 const cy = anchor ? anchor.y : 0;
73
74 const visibleDegree = new Map<string, number>();
75 for (const edge of edges) {
76 visibleDegree.set(edge.source, (visibleDegree.get(edge.source) || 0) + 1);
77 visibleDegree.set(edge.target, (visibleDegree.get(edge.target) || 0) + 1);
78 }
79
80 const simNodes: SimNode[] = nodes.map((node, index) => {
81 const prev = prevById.get(node.id);
82 const angle = (index / Math.max(1, nodes.length)) * Math.PI * 2;
83 const jitter = 60 + (index % 7) * 26;
84 return {
85 ...node,
86 x: prev ? prev.x : cx + Math.cos(angle) * jitter,
87 y: prev ? prev.y : cy + Math.sin(angle) * jitter,
88 vx: prev ? prev.vx : 0,
89 vy: prev ? prev.vy : 0,
90 fx: prev ? prev.fx : null,
91 fy: prev ? prev.fy : null,
92 radius: nodeRadius(node.degree || 0),
93 visibleDegree: visibleDegree.get(node.id) || 0,
94 };
95 });
96
97 const byId = new Map(simNodes.map((node) => [node.id, node]));
98 const simEdges: SimEdge[] = [];
99 for (const edge of edges) {
100 const sourceNode = byId.get(edge.source);
101 const targetNode = byId.get(edge.target);
102 if (sourceNode && targetNode) simEdges.push({ ...edge, sourceNode, targetNode });
103 }
104
105 let alpha = 1;
106
107 function applyRepulsion() {
108 // Spatial grid keeps repulsion ~O(n * neighbors) instead of O(n²).
109 const grid = new Map<string, SimNode[]>();
110 for (const node of simNodes) {
111 const key = `${Math.floor(node.x / GRID_CELL)}:${Math.floor(node.y / GRID_CELL)}`;
112 const cell = grid.get(key);
113 if (cell) cell.push(node);
114 else grid.set(key, [node]);
115 }
116 for (const node of simNodes) {
117 const gx = Math.floor(node.x / GRID_CELL);

Callers 1

GraphCanvasFunction · 0.90

Calls 3

nodeRadiusFunction · 0.85
pushMethod · 0.80
setMethod · 0.45

Tested by

no test coverage detected