2D: Tab-Feld-Controller für Kreis/Bogen-Griffe repariert (Radius/Winkel tippbar)

Nutzer-Report: Editieren bestehender Linien/Kreise fühlt sich noch
eingeschränkt an, man sollte einen Wert eingeben können.

Root Cause bei Kreis/Bogen: cycleGripEditField() ermittelt den Anker für die
Tab-Feld-Eingabe (Länge/Winkel) über eine Polylinien-Heuristik ("Nachbar-
Griff im Array") — für den Kreis-Radius-Griff (nur 1 Griff, kein Nachbar)
gab das GAR KEINEN Anker, Tab tat nichts. Beim Bogen (3 Griffe) fand die
Heuristik zwar irgendeinen Nachbar-Griff als Anker, aber semantisch falsch —
moveGrip() misst dort tatsächlich Winkel/Radius relativ zum ZENTRUM, nicht
relativ zum jeweils anderen Griff.

Fix: cycleGripEditField() erkennt jetzt Kreis/Bogen (selectedDrawing.geom)
und nimmt deren `center` als Anker — "Länge" tippen setzt damit exakt den
Radius, konsistent mit moveGrip()s eigener Distanz-vom-Zentrum-Logik.

tsc -b / vitest run (919/919) / npm run build grün. Keine Unit-Tests ergänzt
(useGripEditing ist ein React-Hook ohne renderHook-Infrastruktur im
Projekt — bestehende Testgrenze, s. andere Hooks). Nutzer prüft in der
laufenden App.
This commit is contained in:
2026-08-21 20:37:15 +02:00
parent d6fde93c57
commit d9cbf2cb07
+14 -3
View File
@@ -363,12 +363,23 @@ export function useGripEditing(opts: {
// Stabiler Ref auf cycleGripEditField (der globale Tab-Handler hat leere Deps).
const cycleGripEditFieldRef = useRef<() => void>(() => {});
// Tab im Vertex-Drag: Feld-Controller öffnen/zyklen (length ↔ angle).
// Tab im Vertex-Drag: Feld-Controller öffnen/zyklen (length ↔ angle). Der
// Anker ist normalerweise die BENACHBARTE Ecke (Polylinien-Semantik: Länge/
// Winkel relativ zum Nachbarpunkt) — bei Kreis/Bogen ist das falsch (deren
// Griffe liegen auf dem Ring, "Länge" muss der RADIUS sein, also relativ
// zum ZENTRUM). Ohne diese Sonderfälle blieb der Kreis-Radius-Griff sogar
// ganz ohne Anker (nur 1 Griff, kein Nachbar) → Tab tat nichts.
const cycleGripEditField = () => {
const info = gripDragInfoRef.current;
if (!info) return;
const refIndex = info.index > 0 ? info.index - 1 : grips.length > 1 ? 1 : -1;
const anchor = refIndex >= 0 ? grips[refIndex] : null;
const g = selectedDrawing?.geom;
const anchor =
g && (g.shape === "circle" || g.shape === "arc")
? g.center
: (() => {
const refIndex = info.index > 0 ? info.index - 1 : grips.length > 1 ? 1 : -1;
return refIndex >= 0 ? grips[refIndex] : null;
})();
if (!anchor) return; // ohne Anker keine polare Eingabe möglich
setGripEdit((prev) =>
prev