Physics controls + FA2 fallback retirement

User-facing live-sim controls (settings panel, Physics section):
node repulsion, edge attraction, edge length, central pull, cluster
pull, friction — session-only number inputs feeding createGraphSimulation
(the SAME engine the server settle runs, so the feel IS the physics).
Changing a value rebuilds the sim from current positions; drag pins
(fx/fy live on the node objects) survive; a mid-settle change re-anneals.

The graph-view FA2 bootstrap fallback is rewritten on incrementalLayout
(d3-force): the last graphology import in the shell is gone.
This commit is contained in:
amosblomqvist
2026-09-13 09:52:14 +03:00
parent 975a78a304
commit 7ebdf065c8
3 changed files with 179 additions and 45 deletions
+28
View File
@@ -17,8 +17,10 @@ import {
fitTransform,
labelAlpha,
pickNearest,
sanitizePhysicsTuning,
sanitizeRegionTuning,
zoomRatioOf,
DEFAULT_PHYSICS_TUNING,
DEFAULT_REGION_TUNING,
LABELS_FADE_SPAN,
} from "../components/graph-canvas.ts";
@@ -194,3 +196,29 @@ describe("boxBlurRound (premultiplied region blur)", () => {
assert.deepEqual([...b], [1, 2, 3, 4, 5, 6, 7, 8]);
});
});
describe("sanitizePhysicsTuning (physics controls)", () => {
test("defaults survive untouched; partial input keeps the rest", () => {
assert.deepEqual(sanitizePhysicsTuning(undefined), DEFAULT_PHYSICS_TUNING);
const half = sanitizePhysicsTuning({ clusterPull: 0.6 });
assert.equal(half.clusterPull, 0.6);
assert.equal(half.chargeStrength, DEFAULT_PHYSICS_TUNING.chargeStrength);
});
test("garbage clamps: NaN falls back, out-of-range clamps", () => {
const t = sanitizePhysicsTuning({
chargeStrength: Number.NaN,
linkStrength: 99,
linkDistance: -5,
gravity: 7,
clusterPull: -1,
velocityDecay: 3,
});
assert.equal(t.chargeStrength, DEFAULT_PHYSICS_TUNING.chargeStrength);
assert.equal(t.linkStrength, 5);
assert.equal(t.linkDistance, 1);
assert.equal(t.gravity, 1);
assert.equal(t.clusterPull, 0);
assert.equal(t.velocityDecay, 0.99);
});
});