feat: Querverbindungen folgen der Faltung + Schalter; Falt-Knopf mit vier Voreinstellungen (D75)

- Abhängigkeits-Kanten enden am nächsten sichtbaren Vorfahren, für Quelle
  wie Ziel; zusammengefallene Kanten entfallen bzw. werden dedupliziert
  (data-sub-ids/data-sub-deps am eingeklappten Vertreter, SPEC §9)
- Umschalter für die Querverbindungen neben dem Günstigster-Pfad-Knopf,
  Voreinstellung an, persistiert; Export und Druck folgen ihm
- Der Falt-Knopf schaltet durch: M und kleiner zu → alles abseits des
  Pfads zu → alles zu → alles offen; Icon/Tooltip zeigen den nächsten
  Schritt, Handfaltung setzt die Position zurück (presetFoldSet, model.js)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
mhoennig
2026-08-25 17:19:32 +02:00
co-authored by Claude Fable 5
parent 69c9be7a6d
commit 33443016ce
10 changed files with 452 additions and 80 deletions
+25
View File
@@ -503,6 +503,31 @@ export function initialCollapsed(roots, rescueFocus){
return set;
}
/* ---------- Falt-Voreinstellungen des Durchschalters (SPEC §9, D75) ----------
Je Modus ein VOLLSTÄNDIGER Faltzustand als Menge der zuzuklappenden Knoten —
was nicht in der Menge steht, ist offen (dieselbe Eigenschaft wie beim alten
Umschalter, D44). `cheapSet` braucht nur der Modus 'path'; er klappt jeden
Knoten zu, durch dessen Teilbaum der günstigste Pfad nicht läuft — weder er
selbst noch ein Unterknoten liegt darauf. Sichtbar bleibt so genau der Pfad,
alles Übrige steht als je ein eingeklappter Knoten da. */
export function presetFoldSet(roots, mode, cheapSet){
const set = new Set();
const walk = ns => {
for(const n of ns){
if(n.children.length){
const zu = mode === 'closed' ? true
: mode === 'small' ? atMostM(n)
: mode === 'path' ? !(cheapSet.has(n) || hidesCheap(n, cheapSet))
: false; /* 'open' */
if(zu) set.add(n);
walk(n.children);
}
}
};
walk(roots);
return set;
}
/* key -> Status-Schlüssel ('' für neutrale Knoten) über den ganzen Baum. */
export function statusByKey(roots){
const map = new Map();