Jelajahi Sumber

Don't open context menu when multi-touch (#2455)

This was very annoying when you would zoom on mobile and the context menu would appear.

The problem was the following:
- You put a finger in, it creates a timeout
- You put a second finger in, it creates another timeout
- 300ms elapsed, which is not that much
- The context menu opens
- Now you move your fingers, which works, but the context menu is still open

The fix is to invalidate the context menu if a second finger is added even if the first one hasn't moved.
Christopher Chedeau 4 tahun lalu
induk
melakukan
545b214558
1 mengubah file dengan 25 tambahan dan 15 penghapusan
  1. 25 15
      src/components/App.tsx

+ 25 - 15
src/components/App.tsx

@@ -186,7 +186,7 @@ let isPanning: boolean = false;
 let isDraggingScrollBar: boolean = false;
 let currentScrollBars: ScrollBars = { horizontal: null, vertical: null };
 let touchTimeout = 0;
-let touchMoving = false;
+let invalidateContextMenu = false;
 
 let lastPointerUp: ((event: any) => void) | null = null;
 const gesture: Gesture = {
@@ -645,6 +645,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
     this.removeEventListeners();
     this.scene.destroy();
     clearTimeout(touchTimeout);
+    touchTimeout = 0;
   }
 
   private onResize = withBatchedUpdates(() => {
@@ -1097,7 +1098,8 @@ class App extends React.Component<ExcalidrawProps, AppState> {
     // remove touch handler for context menu on touch devices
     if (event.pointerType === "touch" && touchTimeout) {
       clearTimeout(touchTimeout);
-      touchMoving = false;
+      touchTimeout = 0;
+      invalidateContextMenu = false;
     }
 
     gesture.pointers.delete(event.pointerId);
@@ -1924,7 +1926,7 @@ class App extends React.Component<ExcalidrawProps, AppState> {
 
   // set touch moving for mobile context menu
   private handleTouchMove = (event: React.TouchEvent<HTMLCanvasElement>) => {
-    touchMoving = true;
+    invalidateContextMenu = true;
   };
 
   private handleCanvasPointerDown = (
@@ -2029,18 +2031,26 @@ class App extends React.Component<ExcalidrawProps, AppState> {
   ): void => {
     // deal with opening context menu on touch devices
     if (event.pointerType === "touch") {
-      touchMoving = false;
-
-      // open the context menu with the first touch's clientX and clientY
-      // if the touch is not moving
-      touchTimeout = window.setTimeout(() => {
-        if (!touchMoving) {
-          this.openContextMenu({
-            clientX: event.clientX,
-            clientY: event.clientY,
-          });
-        }
-      }, TOUCH_CTX_MENU_TIMEOUT);
+      invalidateContextMenu = false;
+
+      if (touchTimeout) {
+        // If there's already a touchTimeout, this means that there's another
+        // touch down and we are doing another touch, so we shouldn't open the
+        // context menu.
+        invalidateContextMenu = true;
+      } else {
+        // open the context menu with the first touch's clientX and clientY
+        // if the touch is not moving
+        touchTimeout = window.setTimeout(() => {
+          touchTimeout = 0;
+          if (!invalidateContextMenu) {
+            this.openContextMenu({
+              clientX: event.clientX,
+              clientY: event.clientY,
+            });
+          }
+        }, TOUCH_CTX_MENU_TIMEOUT);
+      }
     }
   };