Engine unification: d3-force replaces forceAtlas2 everywhere
One engine owns the equilibrium: the merge settle and (next commit) the live drag both run createGraphSimulation — d3-force link springs, 1/d charge, weak centroid gravity — so a drag's rest state IS the server's rest state. The FA2-era anchor mechanism survives as a post-tick POSITION-SPACE re-blend (retention 0.85): d3's forceLink is a Hooke spring (strength*(d-L)*alpha), which overpowers any force-space anchor at long range — the re-blend is alpha-independent and always wins as the sim anneals (the 675-unit drift bug). Gravity retuned for d3's 1/d many-body falloff (bootstrap 0.2 / incremental 0.12: cluster spacing lands ~400 world units, the FA2-era density). Rim orphans seed (and anchor) at 1.7x the CONNECTED core's mean radius — a max-span-based rim fed back on itself and ran the layout away to 6000 units. Replay: 338 positions in 1.6s, old-node shift within a batch 4.8 (FA2: 23).
This commit is contained in:
@@ -49,6 +49,7 @@ function main() {
|
||||
|
||||
console.log(`[replay] ${nodes.length} unique nodes, ${edges.length} edge lines, ${sources.length} sources`);
|
||||
let maxOldShift = 0;
|
||||
let shiftReport = "";
|
||||
for (const source of sources) {
|
||||
const batch = nodes.filter((n) => batchOf.get(n.id) === source.id);
|
||||
const isLast = source.id === sources[sources.length - 1]!.id;
|
||||
@@ -76,7 +77,10 @@ function main() {
|
||||
for (const [id, prev] of before) {
|
||||
const now = positions.get(id)!;
|
||||
const shift = Math.hypot(prev.x - now.x, prev.y - now.y);
|
||||
if (shift > maxOldShift) maxOldShift = shift;
|
||||
if (shift > maxOldShift) {
|
||||
maxOldShift = shift;
|
||||
shiftReport = `${id} ${prev.x.toFixed(0)},${prev.y.toFixed(0)} -> ${now.x.toFixed(0)},${now.y.toFixed(0)} (batch ${batch.length} new, ${activeEdges.length} edges)`;
|
||||
}
|
||||
}
|
||||
const label = source.filePath.split("/").pop() ?? source.id;
|
||||
console.log(
|
||||
@@ -87,7 +91,7 @@ function main() {
|
||||
graphStore.writePositions(Object.fromEntries(positions));
|
||||
console.log(
|
||||
`[replay] done: ${positions.size} positions written in ${((Date.now() - t0) / 1000).toFixed(1)}s` +
|
||||
` (max old-node shift within a batch: ${maxOldShift.toFixed(1)})`,
|
||||
` (max old-node shift within a batch: ${maxOldShift.toFixed(1)}: ${shiftReport})`,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user