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.
This commit is contained in:
Christopher Chedeau 2020-12-05 15:06:50 -08:00 committed by GitHub
parent e617ccc252
commit 545b214558
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

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