export interface Point { x : number ; y : number ; } export abstract class EventUtils { param el param eventName param eventInit - custom event init. See  CustomEventInit public static dispatch ( el , eventName , eventInit ? ) { const init = Object . assign ( { bubbles : true , composed : true , cancelable : true } , eventInit || { } ) ; return el . dispatchEvent ( new CustomEvent ( eventName , init ) ) ; } /** Get original CustomEvent source */ public static source ( e ) { const targets = ( e . composedPath && e . composedPath ( ) ) ; return targets ? targets [ 0 ] : e . target ; } /** Check if the passed event is  MouseEvent public static isMouseEvent ( event ) { return window . MouseEvent && event instanceof MouseEvent ; } /** Check if the passed event is  TouchEvent public static isTouchEvent ( event ) { return window . TouchEvent && event instanceof TouchEvent ; } /** Normalize TouchEvent or PointerEvent */ public static normalizeTouchPoint ( event ) { const source = EventUtils . isTouchEvent ( event ) ? event . changedTouches [ 0 ] : event ; return { x : source . pageX , y : source . pageY } ; } /** Normalize MouseEvent */ public static normalizeCoordinates ( event , elem ) { const source = EventUtils . isTouchEvent ( event ) ? event . changedTouches [ 0 ] : event ; const props = elem . getBoundingClientRect ( ) ; const top = props . top + window . scrollY ; const left = props . left + window . scrollX ; return { x : source . pageX - left , y : source . pageY - top } ; } /** Stub method to prevent event from bubbling out of target */ public static stopPropagation ( e ? ) { e ?. stopPropagation ( ) ; } /** Stub method to prevent default event behaviour */ public static preventDefault ( e ? ) { e ?. preventDefault ( ) ; } }