module import { CameraState } from "../../types" ; import Sigma from "../../sigma" ; import Captor , { getWheelDelta , getMouseCoords , getPosition , getWheelCoords } from "./captor" ; /**
 * Constants.
 */ const DRAG_TIMEOUT = 100 ; const DRAGGED_EVENTS_TOLERANCE = 3 ; const MOUSE_INERTIA_DURATION = 200 ; const MOUSE_INERTIA_RATIO = 3 ; const MOUSE_ZOOM_DURATION = 250 ; const ZOOMING_RATIO = 1.7 ; const DOUBLE_CLICK_TIMEOUT = 300 ; const DOUBLE_CLICK_ZOOMING_RATIO = 2.2 ; const DOUBLE_CLICK_ZOOMING_DURATION = 200 ; constructor export default class MouseCaptor extends Captor { enabled = true ; draggedEvents = 0 ; downStartTime : number | null = null ; lastMouseX : number | null = null ; lastMouseY : number | null = null ; isMouseDown = false ; isMoving = false ; movingTimeout : number | null = null ; startCameraState : CameraState | null = null ; clicks = 0 ; doubleClickTimeout : number | null = null ; currentWheelDirection : - 1 | 0 | 1 = 0 ; lastWheelTriggerTime ? : number ; constructor ( container , renderer ) { super ( container , renderer ) ; this . handleClick = this . handleClick . bind ( this ) ; this . handleRightClick = this . handleRightClick . bind ( this ) ; this . handleDown = this . handleDown . bind ( this ) ; this . handleUp = this . handleUp . bind ( this ) ; this . handleMove = this . handleMove . bind ( this ) ; this . handleWheel = this . handleWheel . bind ( this ) ; this . handleOut = this . handleOut . bind ( this ) ; container . addEventListener ( "click" , this . handleClick , false ) ; container . addEventListener ( "contextmenu" , this . handleRightClick , false ) ; container . addEventListener ( "mousedown" , this . handleDown , false ) ; container . addEventListener ( "wheel" , this . handleWheel , false ) ; container . addEventListener ( "mouseout" , this . handleOut , false ) ; document . addEventListener ( "mousemove" , this . handleMove , false ) ; document . addEventListener ( "mouseup" , this . handleUp , false ) ; } kill ( ) { const container = this . container ; container . removeEventListener ( "click" , this . handleClick ) ; container . removeEventListener ( "contextmenu" , this . handleRightClick ) ; container . removeEventListener ( "mousedown" , this . handleDown ) ; container . removeEventListener ( "wheel" , this . handleWheel ) ; container . removeEventListener ( "mouseout" , this . handleOut ) ; document . removeEventListener ( "mousemove" , this . handleMove ) ; document . removeEventListener ( "mouseup" , this . handleUp ) ; } handleClick ( e ) { if ( ! this . enabled ) return ; this . clicks ++ ; if ( this . clicks === 2 ) { this . clicks = 0 ; if ( typeof this . doubleClickTimeout === "number" ) { clearTimeout ( this . doubleClickTimeout ) ; this . doubleClickTimeout = null ; } return this . handleDoubleClick ( e ) ; } setTimeout ( ( ) => { this . clicks = 0 ; this . doubleClickTimeout = null ; } , DOUBLE_CLICK_TIMEOUT ) ; if ( this . draggedEvents < DRAGGED_EVENTS_TOLERANCE ) this . emit ( "click" , getMouseCoords ( e , this . container ) ) ; } handleRightClick ( e ) { if ( ! this . enabled ) return ; this . emit ( "rightClick" , getMouseCoords ( e , this . container ) ) ; } handleDoubleClick ( e ) { if ( ! this . enabled ) return ; e . preventDefault ( ) ; e . stopPropagation ( ) ; const mouseCoords = getMouseCoords ( e , this . container ) ; this . emit ( "doubleClick" , mouseCoords ) ; if ( mouseCoords . sigmaDefaultPrevented ) return ; const camera = this . renderer . getCamera ( ) ; const newRatio = camera . getBoundedRatio ( camera . getState ( ) . ratio / DOUBLE_CLICK_ZOOMING_RATIO ) ; camera . animate ( this . renderer . getViewportZoomedState ( getPosition ( e , this . container ) , newRatio ) , { easing : "quadraticInOut" , duration : DOUBLE_CLICK_ZOOMING_DURATION , } ) ; } handleDown ( e ) { if ( ! this . enabled ) return ; this . startCameraState = this . renderer . getCamera ( ) . getState ( ) ; const { x , y } = getPosition ( e , this . container ) ; this . lastMouseX = x ; this . lastMouseY = y ; this . draggedEvents = 0 ; this . downStartTime = Date . now ( ) ; this . isMouseDown = true ; this . emit ( "mousedown" , getMouseCoords ( e , this . container ) ) ; } handleUp ( e ) { if ( ! this . enabled || ! this . isMouseDown ) return ; const camera = this . renderer . getCamera ( ) ; this . isMouseDown = false ; if ( typeof this . movingTimeout === "number" ) { clearTimeout ( this . movingTimeout ) ; this . movingTimeout = null ; } const { x , y } = getPosition ( e , this . container ) ; const cameraState = camera . getState ( ) , previousCameraState = camera . getPreviousState ( ) || { x : 0 , y : 0 } ; if ( this . isMoving ) { camera . animate ( { x : cameraState . x + MOUSE_INERTIA_RATIO * ( cameraState . x - previousCameraState . x ) , y : cameraState . y + MOUSE_INERTIA_RATIO * ( cameraState . y - previousCameraState . y ) , } , { duration : MOUSE_INERTIA_DURATION , easing : "quadraticOut" , } ) ; } else if ( this . lastMouseX !== x || this . lastMouseY !== y ) { camera . setState ( { x : cameraState . x , y : cameraState . y , } ) ; } this . isMoving = false ; setTimeout ( ( ) => { this . draggedEvents = 0 ; this . renderer . refresh ( ) ; } , 0 ) ; this . emit ( "mouseup" , getMouseCoords ( e , this . container ) ) ; } handleMove ( e ) { if ( ! this . enabled ) return ; const mouseCoords = getMouseCoords ( e , this . container ) ; this . emit ( "mousemovebody" , mouseCoords ) ; if ( e . target === this . container ) { this . emit ( "mousemove" , mouseCoords ) ; } if ( this . isMouseDown ) { this . isMoving = true ; this . draggedEvents ++ ; if ( typeof this . movingTimeout === "number" ) { clearTimeout ( this . movingTimeout ) ; } this . movingTimeout = window . setTimeout ( ( ) => { this . movingTimeout = null ; this . isMoving = false ; } , DRAG_TIMEOUT ) ; const camera = this . renderer . getCamera ( ) ; const { x : eX , y : eY } = getPosition ( e , this . container ) ; const lastMouse = this . renderer . viewportToFramedGraph ( { x : this . lastMouseX as number , y : this . lastMouseY as number , } ) ; const mouse = this . renderer . viewportToFramedGraph ( { x : eX , y : eY } ) ; const offsetX = lastMouse . x - mouse . x , offsetY = lastMouse . y - mouse . y ; const cameraState = camera . getState ( ) ; const x = cameraState . x + offsetX , y = cameraState . y + offsetY ; camera . setState ( { x , y } ) ; this . lastMouseX = eX ; this . lastMouseY = eY ; e . preventDefault ( ) ; e . stopPropagation ( ) ; } } handleWheel ( e ) { if ( ! this . enabled ) return ; e . preventDefault ( ) ; e . stopPropagation ( ) ; const delta = getWheelDelta ( e ) ; if ( ! delta ) return ; const wheelCoords = getWheelCoords ( e , this . container ) ; this . emit ( "wheel" , wheelCoords ) ; if ( wheelCoords . sigmaDefaultPrevented ) return ; const ratioDiff = delta > 0 ? 1 / ZOOMING_RATIO : ZOOMING_RATIO ; const camera = this . renderer . getCamera ( ) ; const newRatio = camera . getBoundedRatio ( camera . getState ( ) . ratio * ratioDiff ) ; const wheelDirection = delta > 0 ? 1 : - 1 ; const now = Date . now ( ) ; if ( this . currentWheelDirection === wheelDirection && this . lastWheelTriggerTime && now - this . lastWheelTriggerTime < MOUSE_ZOOM_DURATION / 5 ) { return ; } camera . animate ( this . renderer . getViewportZoomedState ( getPosition ( e , this . container ) , newRatio ) , { easing : "quadraticOut" , duration : MOUSE_ZOOM_DURATION , } , ( ) => { this . currentWheelDirection = 0 ; } ) ; this . currentWheelDirection = wheelDirection ; this . lastWheelTriggerTime = now ; } handleOut ( ) { } }