diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8b1dad7..477616a 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -19,6 +19,7 @@ reverse. ## 2026-08-24 +- Dependency links now run behind every node, highlighted ones included — no more lines struck through node titles - Fix: the line to an only child was torn where the child does not sit centred in its cell - An optional node (`+`) joins the cheapest path while it is being worked on — started work is the open front - Fix: a started alternative lost its `|`/`=` group to an untouched cheaper one, although the choice was already made diff --git a/docs/DECISIONS.md b/docs/DECISIONS.md index dbdf5da..9b9aa96 100644 --- a/docs/DECISIONS.md +++ b/docs/DECISIONS.md @@ -2805,6 +2805,61 @@ Zweiter Schritt derselben Rückmeldung: Auch die **Pfeilspitze** ist jetzt Dreiecks — das Dreieck stach als einziger satter Fleck aus der gepunkteten Linie heraus. Die Hervorhebung bekommt denselben Winkel in Tinte. +**Nachtrag 2 — auch die hervorgehobenen Kanten laufen hinter den Knoten +durch.** Gemeldet: „die Abhängigkeits-Pfeile sollen im Hintergrund durch andere +Knoten durchlaufen, derzeit werden die Pfeile drüber gemalt." + +**Nachgemessen war es genau eine Hälfte.** Die **Basis**-Kanten lagen schon +richtig: In einem eigens gebauten Fall — eine Kante quer über drei breite +Knoten hinweg, zur Sichtbarkeit magenta und 6 px dick gefärbt — erschien sie +**nur in den Lücken** zwischen den Knoten, nie über deren Fläche. Sichtbar +„drüber" war allein die **Hervorhebung**: Steht der Cursor auf einer Zeile mit +`:#…`, wandern deren Kanten auf `svg.dep-front` (`z-index:4`) und laufen als +durchgezogene Tinte-Linie mitten durch die Beschriftung der Knoten dazwischen. + +**Damit fällt die Begründung des Haupttextes** — „vorn dürfen sie den Baum +überlagern, denn die Hervorhebung ist flüchtig und gerade angefragt". Der +Einwand des Nutzers wiegt schwerer, und er ist derselbe, aus dem die +Basis-Kanten von Anfang an hinten liegen: Eine Linie quer über einen fremden +Knoten **durchstreicht dessen Titel**. Das trifft ausgerechnet die Knoten, die +mit der Sache nichts zu tun haben — die Kante sagt etwas über ihre beiden +Enden, nicht über das, was zufällig dazwischen steht. „Flüchtig" ist dabei kein +Freibrief, sondern eher das Gegenteil: Beim Tippen wechselt die Hervorhebung +mit jeder Zeile, der Schaden ist also nicht selten, sondern dauernd. + +**Eine Ebene statt zweier.** `svg.dep-front` entfällt; hervorgehobene Kanten +werden **zuletzt** in dieselbe hintere Ebene gehängt und liegen dadurch über +den übrigen Kanten, aber unter jedem Knoten. Die Unterscheidung trägt weiterhin +das Aussehen (durchgezogen in Tinte gegen gepunktet in Blassgrau), und das ist +genug: Sie war nie an der Ebene festgemacht, sondern nur zusätzlich betont. + +**Der Preis, benannt:** In einer dichten Reihe breiter Knoten bleibt von der +hervorgehobenen Kante wenig mehr als ein Stück in jeder Lücke. Zu **finden** +ist ihr Ziel trotzdem, denn die **Pfeilspitze sitzt auf der Knotenkante** und +liegt damit außerhalb jedes Kastens. Für den Fall, dass das eines Tages nicht +reicht, steht das Hausmittel bereit: eine **abgetönte Kopie davor**, wie sie +der günstigste Pfad seit D18 für genau dieses Problem hat („deutet den Verlauf +beim Durchschreiten eines Knotens nur schwach an"). Bewusst nicht vorab +gebaut — gefragt war, dass die Kanten hinten laufen, und eine zweite Ebene +zurückzuholen, um die erste zu erklären, ist der falsche Anfang. + +**Was dadurch obsolet wird:** D25-Nachtrag 3 gab `.dep-front` seinen +`z-index:4`, weil die hervorgehobenen Kanten sonst unter dem hervorgehobenen +Knoten endeten („vorn heißt vorn"). Das war für eine vordere Ebene richtig und +ist mit ihr weggefallen; für `.cheap-front` (`z-index:5`) gilt es unverändert +weiter — der Stationspunkt gehört über den Knoten. + +**Export und Druck waren nie betroffen:** `diagramToSvg()` zeichnet die +Basis-Kanten in Schritt 1a, also vor den Knoten, und die Hervorhebung gar nicht +(Interaktion, siehe oben). Das Bild auf dem Schirm zieht damit nach, statt dass +etwas Neues entsteht — derselbe Befund wie bei D46-Nachtrag. + +**Nachgemessen** nach der Änderung, an demselben Fall: `svg.dep-front` gibt es +nicht mehr, alle Kanten hängen in `svg.dep-back` als erstem Kind von `#out`, +die hervorgehobene als letztes Element darin. Die Tinte-Linie ist in den Lücken +zu sehen und über den Knoten nicht mehr; die Pfeilspitze steht unverändert an +der Kante des gebrauchten Knotens. + ## D42 — Closure-Pfad: erschöpfend über die gekoppelten Gruppen, gierig nur benannt Die letzte Baustelle aus D34: Mit Abhängigkeiten zählt der günstigste Pfad nicht mehr den gewählten Teilbaum, sondern die **Hülle** — jeder nötige Knoten diff --git a/docs/SPEC.md b/docs/SPEC.md index 2e142ce..2ffafc6 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -961,9 +961,13 @@ eigenen Zeichenebene **hinter** den Knoten, mit einer kleinen **offenen Pfeilspitze auf das Gebrauchte** („braucht“-Richtung; ein Winkel aus zwei Strichen, kein gefülltes Dreieck). Der Baum trägt weiterhin die Hauptaussage. +- **Alle** Kanten laufen **hinter** den Knoten durch, auch die hervorgehobenen: + sichtbar in den Lücken, verdeckt vom Knoten selbst. Der Baum bleibt damit + lesbar — eine Kante, die quer über fremde Knoten hinwegläuft, durchstreicht + deren Beschriftung. - Die Kanten des **ausgewählten** Knotens — Tastaturfokus im Diagramm, sonst - der Knoten der Cursor-Zeile — liegen hervorgehoben in Tinte auf einer - vorderen Ebene, ein- wie ausgehende. + der Knoten der Cursor-Zeile — sind in Tinte hervorgehoben, ein- wie + ausgehende; sie liegen über den übrigen Kanten, aber unter jedem Knoten. - Kanten zu gerade nicht sichtbaren Knoten (eingeklappt §9, verworfen ausgeblendet §4) entfallen; bei doppelter ID zielt die Kante auf die erste Vergabe (D36/D39). diff --git a/frontend/src/app.js b/frontend/src/app.js index 2a36cbf..8f193e8 100644 --- a/frontend/src/app.js +++ b/frontend/src/app.js @@ -426,18 +426,23 @@ function drawDepLinks(){ cx:(r.left - outRect.left + r.width/2)/z, cy:(r.top - outRect.top + r.height/2)/z}; }; const w = outRect.width/z, h = outRect.height/z; + /* EINE Ebene, und die liegt hinter den Knoten (D41-Nachtrag 2): Die Kanten + laufen durch fremde Knoten hindurch, statt über sie hinweg. Die + hervorgehobenen werden zuletzt eingehängt — damit liegen sie über den + übrigen Kanten, aber weiterhin unter jedem Knoten. */ const back = overlaySvg('dep-overlay dep-back', w, h); - const front = overlaySvg('dep-overlay dep-front', w, h); const hi = activeDepNode(); + const hoch = []; for(const [from, to] of edges){ const hl = hi && (from === hi || to === hi); const c = depCurve(rect(from), rect(to)); - const layer = hl ? front : back; - layer.appendChild(svgEl('path', {class:'dep-edge' + (hl ? ' hl' : ''), d:c.d})); - layer.appendChild(svgEl('path', {class:'dep-arrow' + (hl ? ' hl' : ''), d:depArrow(c.end, c.ctrl)})); + const kante = svgEl('path', {class:'dep-edge' + (hl ? ' hl' : ''), d:c.d}); + const spitze = svgEl('path', {class:'dep-arrow' + (hl ? ' hl' : ''), d:depArrow(c.end, c.ctrl)}); + if(hl) hoch.push(kante, spitze); + else { back.appendChild(kante); back.appendChild(spitze); } } + for(const p of hoch) back.appendChild(p); out.insertBefore(back, out.firstChild); - if(front.childNodes.length) out.appendChild(front); } /* Hervorhebung folgt dem Fokus; die Basis-Kanten selbst ändern sich nicht. */ out.addEventListener('focusin', drawDepLinks); diff --git a/frontend/src/style.css b/frontend/src/style.css index b30f2e3..0579077 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -918,12 +918,12 @@ Blättern zeigen, welche Knoten wirklich auf dem Pfad enden — durchquerte Fremdknoten tragen keinen Punkt. Reihenfolge im DOM steuert vorn/hinten. */ .cheap-overlay{position:absolute;left:0;top:0;overflow:visible;pointer-events:none} - /* Die VORDEREN Ebenen müssen über JEDEN Knoten — auch über die, die sich - selbst eine Stapelposition nehmen: Cursor-Zeile (`z-index:3`, D25), + /* Die VORDERE Ebene muss über JEDEN Knoten — auch über die, die sich selbst + eine Stapelposition nehmen: Cursor-Zeile (`z-index:3`, D25), Strahlenkränze (`z-index:2`, D28/D32). Ohne das deckt ausgerechnet der - hervorgehobene Knoten seinen eigenen Stationspunkt zu, und die - hervorgehobenen Abhängigkeits-Kanten enden unter ihm. „Vorn" heißt vorn. */ - .dep-overlay.dep-front{z-index:4} + hervorgehobene Knoten seinen eigenen Stationspunkt zu. „Vorn" heißt vorn. + (Die Abhängigkeits-Kanten hatten aus demselben Grund einmal `.dep-front` + mit `z-index:4`; sie liegen jetzt vollständig hinten — D41-Nachtrag 2.) */ .cheap-overlay.cheap-front{z-index:5} /* Querverbindungen der Abhängigkeiten (SPEC §9, D41): blassgrau GEPUNKTET und gekrümmt — Punktierung und Krümmung unterscheiden sie doppelt von den diff --git a/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json b/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json index f8f1854..bf36f7e 100644 --- a/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +++ b/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json @@ -1 +1 @@ -{"version":"4.1.11","results":[[":frontend/tests/render.test.js",{"duration":98.47688799999997,"failed":false}],[":frontend/tests/focusmark.test.js",{"duration":35.79027499999995,"failed":false}],[":frontend/tests/fold.test.js",{"duration":41.154863999999975,"failed":false}],[":frontend/tests/optional.test.js",{"duration":35.42018200000001,"failed":false}],[":frontend/tests/parser.test.js",{"duration":33.422897999999975,"failed":false}],[":frontend/tests/xor.test.js",{"duration":52.44134100000002,"failed":false}],[":frontend/tests/desc.test.js",{"duration":31.248038000000008,"failed":false}],[":frontend/tests/deps.test.js",{"duration":31.736107000000004,"failed":false}],[":frontend/tests/closure.test.js",{"duration":24.077101999999968,"failed":false}],[":frontend/tests/effective.test.js",{"duration":27.93907200000001,"failed":false}],[":frontend/tests/ids.test.js",{"duration":25.51923499999998,"failed":false}],[":frontend/tests/remote.test.js",{"duration":20.999619999999993,"failed":false}],[":frontend/tests/warnings.test.js",{"duration":9.594386999999983,"failed":false}],[":frontend/tests/fresh.test.js",{"duration":22.15039999999999,"failed":false}]]} \ No newline at end of file +{"version":"4.1.11","results":[[":frontend/tests/render.test.js",{"duration":76.60164399999996,"failed":false}],[":frontend/tests/focusmark.test.js",{"duration":40.93189599999994,"failed":false}],[":frontend/tests/fold.test.js",{"duration":56.39246000000003,"failed":false}],[":frontend/tests/optional.test.js",{"duration":34.46531600000003,"failed":false}],[":frontend/tests/parser.test.js",{"duration":25.05400099999997,"failed":false}],[":frontend/tests/xor.test.js",{"duration":65.50341500000002,"failed":false}],[":frontend/tests/desc.test.js",{"duration":59.75648000000001,"failed":false}],[":frontend/tests/deps.test.js",{"duration":67.85368099999994,"failed":false}],[":frontend/tests/closure.test.js",{"duration":29.96200700000003,"failed":false}],[":frontend/tests/effective.test.js",{"duration":55.79072299999996,"failed":false}],[":frontend/tests/ids.test.js",{"duration":48.80462399999999,"failed":false}],[":frontend/tests/remote.test.js",{"duration":17.515127999999947,"failed":false}],[":frontend/tests/warnings.test.js",{"duration":9.082986000000005,"failed":false}],[":frontend/tests/fresh.test.js",{"duration":21.491277000000025,"failed":false}],[":frontend/tests/shortids.test.js",{"duration":40.74205600000005,"failed":false}],[":frontend/tests/snapshots.test.js",{"duration":105.82867499999998,"failed":false}],[":frontend/tests/frontier.test.js",{"duration":80.81959199999994,"failed":false}],[":frontend/tests/continuation.test.js",{"duration":36.78602599999999,"failed":false}],[":frontend/tests/news.test.js",{"duration":21.62978800000002,"failed":false}]]} \ No newline at end of file