Fix: Mobile-Graph drag/zoom/navigate via touch-action + touch-event fallbacks

Diagnose: Mobile Graph sichtbar aber nicht bedienbar.
Root cause: iOS Safari interpretiert Single-Finger-Touch als Scroll-Geste
statt als Drag, weil touch-action: none fehlt.

Fixes:
1. CSS: touch-action: none auf .graph-modal-canvas, canvas und .graph-modal
   (verhindert iOS-Safari Scroll-Hijacking + Rubber-Band-Effect)
2. JS: Touch-Event-Fallbacks (touchstart/move/end/cancel) parallel zu
   pointer-events (für ältere iOS-Safari-Versionen die pointer-events
   noch nicht voll unterstützen)
3. JS: Pinch-to-Zoom via Zwei-Finger-Gestenerkennung
4. JS: Initial-Render mit Resize-Retry bis Canvas echte Dimensionen hat
   (Modal-Container kann initial 0x0 sein bevor Flex-Layout settled)
5. JS: ResizeObserver auf Canvas re-rendert bei Größenänderung
6. CSS: overscroll-behavior: contain auf Modal (kein Bounce)
7. CSS: -webkit-user-select: none + tap-highlight: transparent
   (verhindert iOS-Safari Selektions-Overlay beim Drag)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-07-20 04:52:01 +00:00
co-authored by Claude
parent d0e4e8ab9e
commit 9248ae62c7
2 changed files with 192 additions and 47 deletions
+30
View File
@@ -514,15 +514,45 @@ body {
flex: 1;
position: relative;
overflow: hidden;
touch-action: none; /* critical: prevent iOS Safari scroll-hijacking */
-webkit-user-select: none;
user-select: none;
-webkit-tap-highlight-color: transparent;
min-height: 0; /* flex-child needs explicit min-height for sizing */
width: 100%;
height: 100%;
}
.graph-modal-canvas canvas {
display: block;
width: 100% !important;
height: 100% !important;
cursor: grab;
touch-action: none; /* critical: same on canvas itself */
-webkit-user-select: none;
user-select: none;
}
.graph-modal-canvas canvas:active { cursor: grabbing; }
/* Modal body must not scroll on background */
.graph-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--bg-primary);
z-index: 200;
flex-direction: column;
padding-top: var(--sat);
padding-left: var(--sal);
padding-right: var(--sar);
padding-bottom: var(--sab);
touch-action: none;
overscroll-behavior: contain;
}
.graph-modal.open { display: flex; }
/* Graph legend (small floating panel) */
.graph-legend {
position: absolute;