Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536/** One-shot ForceAtlas2 over an index-keyed packed graph. Shared by the * layout worker (normal path) and the synchronous fallback. */import Graph from "graphology";import forceAtlas2 from "graphology-layout-forceatlas2";
export interface Fa2Input { xy: Float64Array; // packed x0,y0,x1,y1,… seed positions sizes: Float64Array; edges: Uint32Array; // packed source,target index pairs}
export function fa2Positions({ xy, sizes, edges }: Fa2Input): Float64Array { const graph = new Graph(); const n = sizes.length; for (let i = 0; i < n; i++) graph.addNode(i, { x: xy[2 * i], y: xy[2 * i + 1], size: sizes[i] }); for (let j = 0; j < edges.length; j += 2) graph.addEdge(edges[j], edges[j + 1]); const settings = forceAtlas2.inferSettings(graph); // Fewer iterations on huge graphs: barnes-hut converges well before 300, // and halving the wall-clock beats marginal layout polish there. const big = n > 4000; forceAtlas2.assign(graph, { iterations: big ? 180 : 300, settings }); // Second phase with size-aware repulsion untangles huge same-parent fans // (hundreds of quotes of the root) that otherwise clump into a blob. forceAtlas2.assign(graph, { iterations: big ? 50 : 80, settings: { ...settings, adjustSizes: true }, }); const out = new Float64Array(2 * n); graph.forEachNode((node, attrs) => { const i = Number(node); out[2 * i] = attrs.x; out[2 * i + 1] = attrs.y; }); return out;}