import { TypePoint , TypeContext } from '@idraw/types' ; import { BoardEvent , TypeBoardEventArgMap } from './event' ; import { TempData } from './watcher-temp' ; export class ScreenWatcher { private _canvas : HTMLCanvasElement ; private _isMoving = false ; private _event : BoardEvent ; private _temp : TempData = new TempData ; private _container : HTMLElement | Window = window ; constructor ( canvas , ctx ) { this . _canvas = canvas ; this . _isMoving = false ; this . _initEvent ( ) ; this . _event = new BoardEvent ; } setStatusMap ( statusMap ) { this . _temp . set ( 'statusMap' , statusMap ) ; } on < T extends keyof TypeBoardEventArgMap > ( name , callback ) { this . _event . on ( name , callback ) ; } off < T extends keyof TypeBoardEventArgMap > ( name , callback ) { this . _event . off ( name , callback ) ; } _initEvent ( ) { const canvas = this . _canvas ; const container = this . _container ; container . addEventListener ( 'mousemove' , this . _listenWindowMove . bind ( this ) , false ) ; container . addEventListener ( 'mouseup' , this . _listenWindowMoveEnd . bind ( this ) , false ) ; canvas . addEventListener ( 'mousemove' , this . _listenHover . bind ( this ) , false ) ; canvas . addEventListener ( 'mousedown' , this . _listenMoveStart . bind ( this ) , false ) ; canvas . addEventListener ( 'mousemove' , this . _listenMove . bind ( this ) , false ) ; canvas . addEventListener ( 'mouseup' , this . _listenMoveEnd . bind ( this ) , false ) ; canvas . addEventListener ( 'click' , this . _listenCanvasClick . bind ( this ) , false ) ; canvas . addEventListener ( 'wheel' , this . _listenCanvasWheel . bind ( this ) , false ) ; canvas . addEventListener ( 'mousedown' , this . _listenCanvasMoveStart . bind ( this ) , true ) ; canvas . addEventListener ( 'mouseup' , this . _listenCanvasMoveEnd . bind ( this ) , true ) ; canvas . addEventListener ( 'mouseover' , this . _listenCanvasMoveOver . bind ( this ) , true ) ; canvas . addEventListener ( 'mouseleave' , this . _listenCanvasMoveLeave . bind ( this ) , true ) ; this . _initParentEvent ( ) ; } _initParentEvent ( ) { try { let target = window ; let targetOrigin = target . origin ; while ( target . self !== target . top ) { if ( target . self !== target . parent ) { if ( target . origin === targetOrigin ) { target . parent . window . addEventListener ( 'mousemove' , this . _listSameOriginParentWindow . bind ( this ) , false ) ; } } target = target . parent ; if ( ! target ) { break ; } } } catch ( err ) { console . warn ( err ) ; } } _listenHover ( e ) { e . preventDefault ( ) ; const p = this . _getPosition ( e ) ; if ( this . _isVaildPoint ( p ) ) { if ( this . _event . has ( 'hover' ) ) { this . _event . trigger ( 'hover' , p ) ; } } this . _isMoving = true ; } _listenMoveStart ( e ) { e . preventDefault ( ) ; const p = this . _getPosition ( e ) ; if ( this . _isVaildPoint ( p ) ) { if ( this . _event . has ( 'point' ) ) { this . _event . trigger ( 'point' , p ) ; } if ( this . _event . has ( 'moveStart' ) ) { this . _event . trigger ( 'moveStart' , p ) ; } } this . _isMoving = true ; } _listenMove ( e ) { e . preventDefault ( ) ; e . stopPropagation ( ) ; if ( this . _event . has ( 'move' ) && this . _isMoving === true ) { const p = this . _getPosition ( e ) ; if ( this . _isVaildPoint ( p ) ) { this . _event . trigger ( 'move' , p ) ; } } } _listenMoveEnd ( e ) { e . preventDefault ( ) ; if ( this . _event . has ( 'moveEnd' ) ) { const p = this . _getPosition ( e ) ; if ( this . _isVaildPoint ( p ) ) { this . _event . trigger ( 'moveEnd' , p ) ; } } this . _isMoving = false ; } _listSameOriginParentWindow ( ) { if ( this . _temp . get ( 'isHoverCanvas' ) ) { if ( this . _event . has ( 'leave' ) ) { this . _event . trigger ( 'leave' , undefined ) ; } } if ( this . _temp . get ( 'isDragCanvas' ) ) { if ( this . _event . has ( 'moveEnd' ) ) { this . _event . trigger ( 'moveEnd' , { x : NaN , y : NaN } ) ; } } this . _isMoving = false ; this . _temp . set ( 'isDragCanvas' , false ) ; this . _temp . set ( 'isHoverCanvas' , false ) ; } _listenCanvasMoveStart ( ) { if ( this . _temp . get ( 'isHoverCanvas' ) ) { this . _temp . set ( 'isDragCanvas' , true ) ; } } _listenCanvasMoveEnd ( ) { this . _temp . set ( 'isDragCanvas' , false ) ; } _listenCanvasMoveOver ( ) { this . _temp . set ( 'isHoverCanvas' , true ) ; } _listenCanvasMoveLeave ( ) { this . _temp . set ( 'isHoverCanvas' , false ) ; if ( this . _event . has ( 'leave' ) ) { this . _event . trigger ( 'leave' , undefined ) ; } } _listenWindowMove ( e ) { if ( this . _temp . get ( 'isDragCanvas' ) !== true ) { return ; } e . preventDefault ( ) ; e . stopPropagation ( ) ; if ( this . _event . has ( 'move' ) && this . _isMoving === true ) { const p = this . _getPosition ( e as MouseEvent | TouchEvent ) ; if ( this . _isVaildPoint ( p ) ) { this . _event . trigger ( 'move' , p ) ; } } } _listenWindowMoveEnd ( e ) { if ( ! this . _temp . get ( 'isDragCanvas' ) === true ) { return ; } e . preventDefault ( ) ; if ( this . _event . has ( 'moveEnd' ) ) { const p = this . _getPosition ( e as MouseEvent | TouchEvent ) ; if ( this . _isVaildPoint ( p ) ) { this . _event . trigger ( 'moveEnd' , p ) ; } } this . _temp . set ( 'isDragCanvas' , false ) ; this . _isMoving = false ; } _listenCanvasWheel ( e ) { if ( this . _event . has ( 'wheelX' ) && ( e . deltaX > 0 || e . deltaX < 0 ) ) { this . _event . trigger ( 'wheelX' , e . deltaX ) ; } if ( this . _event . has ( 'wheelY' ) && ( e . deltaY > 0 || e . deltaY < 0 ) ) { this . _event . trigger ( 'wheelY' , e . deltaY ) ; } const { canScrollYNext , canScrollYPrev } = this . _temp . get ( 'statusMap' ) ; if ( e . deltaX > 0 && e . deltaX < 0 ) { e . preventDefault ( ) ; } else if ( e . deltaY > 0 && canScrollYNext === true ) { e . preventDefault ( ) ; } else if ( e . deltaY < 0 && canScrollYPrev === true ) { e . preventDefault ( ) ; } } _listenCanvasClick ( e ) { e . preventDefault ( ) ; const maxLimitTime = 500 ; const p = this . _getPosition ( e as MouseEvent | TouchEvent ) ; const t = Date . now ( ) ; if ( this . _isVaildPoint ( p ) ) { const preClickPoint = this . _temp . get ( 'prevClickPoint' ) ; if ( preClickPoint && ( t - preClickPoint . t <= maxLimitTime ) && Math . abs ( preClickPoint . x - p . x ) <= 5 && Math . abs ( preClickPoint . y - p . y ) <= 5 ) { if ( this . _event . has ( 'doubleClick' ) ) { this . _event . trigger ( 'doubleClick' , { x : p . x , y : p . y } ) ; } } else { this . _temp . set ( 'prevClickPoint' , { x : p . x , y : p . y , t , } ) ; } } } _getPosition ( e ) { const canvas = this . _canvas ; let x = 0 ; let y = 0 ; if ( e && e . touches && e . touches . length > 0 ) { const touch = e . touches [ 0 ] ; if ( touch ) { x = touch . clientX ; y = touch . clientY ; } } else { x = e . clientX ; y = e . clientY ; } const p = { x : x - canvas . getBoundingClientRect ( ) . left , y : y - canvas . getBoundingClientRect ( ) . top , t : Date . now ( ) , } ; return p ; } private _isVaildPoint ( p ) { return isAvailableNum ( p . x ) && isAvailableNum ( p . y ) ; } } function isAvailableNum ( num ) { return ( num > 0 || num < 0 || num === 0 ) ; }