Bladeren bron

fix: pinch-zoom gesture handling on Android WebView

- touchstart: passive listener (prevents WebView from blocking multi-touch)
- touchmove: passive:false, only preventDefault on actual gesture
- Math.hypot → Math.sqrt for broader compatibility
- Added initialPinch flag to distinguish pinch from pan
- Scale bounds: 0.1x–20x range, 0.3x–3x per frame limit
- Double-tap reset: only fires when not in pinch gesture
- Canvas CSS: max-width instead of fixed width, added user-select:none

Co-Authored-By: Claude <noreply@anthropic.com>
nonvioce 3 maanden geleden
bovenliggende
commit
60be6dbb4a
2 gewijzigde bestanden met toevoegingen van 33 en 20 verwijderingen
  1. 3 2
      app/src/main/assets/console.css
  2. 30 18
      app/src/main/assets/console.js

+ 3 - 2
app/src/main/assets/console.css

@@ -1429,10 +1429,11 @@ body {
 }
 .plot-canvas {
     display: block;
-    width: 100%;
-    height: auto;
+    max-width: 100%;
     border-radius: 4px;
     touch-action: none;
+    -webkit-user-select: none;
+    user-select: none;
 }
 
 /* ── MCP 同步事件 ────────────────────────────────── */

+ 30 - 18
app/src/main/assets/console.js

@@ -2324,27 +2324,35 @@ class PlotRenderer {
             canvas.removeEventListener('touchmove', this._touchHandlers.move);
             canvas.removeEventListener('touchend', this._touchHandlers.end);
         }
-        let lastDist = 0, lastX = 0, lastY = 0, lastTap = 0;
+        let lastDist = 0, lastX = 0, lastY = 0, lastTap = 0, initialPinch = false;
         const self = this;
 
         const onStart = (e) => {
-            if (e.touches.length === 2) {
-                lastDist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY);
-            } else if (e.touches.length === 1) {
+            if (e.touches.length >= 2) {
+                const dx = e.touches[0].clientX - e.touches[1].clientX;
+                const dy = e.touches[0].clientY - e.touches[1].clientY;
+                lastDist = Math.sqrt(dx*dx + dy*dy);
+                initialPinch = true;
+            }
+            if (e.touches.length === 1 && !initialPinch) {
                 lastX = e.touches[0].clientX;
                 lastY = e.touches[0].clientY;
             }
-            e.preventDefault();
         };
         const onMove = (e) => {
-            if (e.touches.length === 2) {
-                const dist = Math.hypot(e.touches[0].clientX - e.touches[1].clientX, e.touches[0].clientY - e.touches[1].clientY);
+            if (e.touches.length >= 2 && initialPinch && lastDist > 0) {
+                const dx = e.touches[0].clientX - e.touches[1].clientX;
+                const dy = e.touches[0].clientY - e.touches[1].clientY;
+                const dist = Math.sqrt(dx*dx + dy*dy);
                 const scale = dist / lastDist;
-                self.transform.sx = Math.max(0.1, Math.min(20, self.transform.sx / scale));
-                self.transform.sy = Math.max(0.1, Math.min(20, self.transform.sy / scale));
+                if (scale > 0.3 && scale < 3) {
+                    self.transform.sx = Math.max(0.1, Math.min(20, self.transform.sx / scale));
+                    self.transform.sy = Math.max(0.1, Math.min(20, self.transform.sy / scale));
+                }
                 lastDist = dist;
                 self.draw();
-            } else if (e.touches.length === 1) {
+                e.preventDefault();
+            } else if (e.touches.length === 1 && !initialPinch) {
                 const dx = (e.touches[0].clientX - lastX) / canvas.clientWidth;
                 const dy = (e.touches[0].clientY - lastY) / canvas.clientHeight;
                 self.transform.ox -= dx / self.transform.sx;
@@ -2352,21 +2360,25 @@ class PlotRenderer {
                 lastX = e.touches[0].clientX;
                 lastY = e.touches[0].clientY;
                 self.draw();
+                e.preventDefault();
             }
-            e.preventDefault();
         };
         const onEnd = (e) => {
-            const now = Date.now();
-            if (now - lastTap < 300) {
-                self.transform = { ox: 0, oy: 0, sx: 1, sy: 1 };
-                self.draw();
+            if (e.touches.length === 0) {
+                const now = Date.now();
+                if (initialPinch) {
+                    initialPinch = false;
+                } else if (now - lastTap < 350) {
+                    self.transform = { ox: 0, oy: 0, sx: 1, sy: 1 };
+                    self.draw();
+                }
+                lastTap = now;
             }
-            lastTap = now;
         };
 
-        canvas.addEventListener('touchstart', onStart, { passive: false });
+        canvas.addEventListener('touchstart', onStart, { passive: true });
         canvas.addEventListener('touchmove', onMove, { passive: false });
-        canvas.addEventListener('touchend', onEnd);
+        canvas.addEventListener('touchend', onEnd, { passive: true });
         this._touchHandlers = { start: onStart, move: onMove, end: onEnd };
     }
 }