@ -125,6 +125,7 @@ import {
INITAL_SCENE_UPDATE_TIMEOUT ,
TAP_TWICE_TIMEOUT ,
SYNC_FULL_SCENE_INTERVAL_MS ,
TOUCH_CTX_MENU_TIMEOUT ,
} from "../time_constants" ;
import LayerUI from "./LayerUI" ;
@ -172,6 +173,8 @@ let isHoldingSpace: boolean = false;
let isPanning : boolean = false ;
let isDraggingScrollBar : boolean = false ;
let currentScrollBars : ScrollBars = { horizontal : null , vertical : null } ;
let touchTimeout = 0 ;
let touchMoving = false ;
let lastPointerUp : ( ( event : any ) = > void ) | null = null ;
const gesture : Gesture = {
@ -256,6 +259,7 @@ class App extends React.Component<any, AppState> {
onPointerMove = { this . handleCanvasPointerMove }
onPointerUp = { this . removePointer }
onPointerCancel = { this . removePointer }
onTouchMove = { this . handleTouchMove }
onDrop = { this . handleCanvasOnDrop }
>
{ t ( "labels.drawingCanvas" ) }
@ -409,6 +413,8 @@ class App extends React.Component<any, AppState> {
this . unmounted = true ;
this . removeSceneCallback ! ( ) ;
this . removeEventListeners ( ) ;
clearTimeout ( touchTimeout ) ;
}
private onResize = withBatchedUpdates ( ( ) = > {
@ -818,6 +824,12 @@ class App extends React.Component<any, AppState> {
} ;
removePointer = ( event : React.PointerEvent < HTMLElement > ) = > {
// remove touch handler for context menu on touch devices
if ( event . pointerType === "touch" && touchTimeout ) {
clearTimeout ( touchTimeout ) ;
touchMoving = false ;
}
gesture . pointers . delete ( event . pointerId ) ;
} ;
@ -1802,11 +1814,32 @@ class App extends React.Component<any, AppState> {
}
} ;
// set touch moving for mobile context menu
private handleTouchMove = ( event : React.TouchEvent < HTMLCanvasElement > ) = > {
touchMoving = true ;
} ;
private handleCanvasPointerDown = (
event : React.PointerEvent < HTMLCanvasElement > ,
) = > {
event . persist ( ) ;
// 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 ) ;
}
if ( lastPointerUp !== null ) {
// Unfortunately, sometimes we don't get a pointerup after a pointerdown,
// this can happen when a contextual menu or alert is triggered. In order to avoid
@ -2847,9 +2880,18 @@ class App extends React.Component<any, AppState> {
event : React.PointerEvent < HTMLCanvasElement > ,
) = > {
event . preventDefault ( ) ;
this . openContextMenu ( event ) ;
} ;
private openContextMenu = ( {
clientX ,
clientY ,
} : {
clientX : number ;
clientY : number ;
} ) = > {
const { x , y } = viewportCoordsToSceneCoords (
event ,
{ clientX , clientY } ,
this . state ,
this . canvas ,
window . devicePixelRatio ,
@ -2888,8 +2930,8 @@ class App extends React.Component<any, AppState> {
action : this.toggleGridMode ,
} ,
] ,
top : event. clientY,
left : event. clientX,
top : clientY,
left : clientX,
} ) ;
return ;
}
@ -2920,8 +2962,8 @@ class App extends React.Component<any, AppState> {
( action ) = > ! CANVAS_ONLY_ACTIONS . includes ( action . name ) ,
) ,
] ,
top : event. clientY,
left : event. clientX,
top : clientY,
left : clientX,
} ) ;
} ;