import { Directive , ElementRef , NgZone , OnInit , Renderer2 } from '@angular/core' ; interface Point { x : number ; y : number ; } @ Directive ( { selector : '[airgapTraceInput]' } ) export class TraceInputDirective implements OnInit { private readonly canvas : HTMLCanvasElement ; private readonly context : CanvasRenderingContext2D ; private mousePos : Point = { x : 0 , y : 0 } ; private lastPos : Point = this . mousePos ; private isDrawing : boolean ; constructor ( elementRef , private readonly ngZone , private readonly renderer ) { this . canvas = elementRef . nativeElement ; const context = this . canvas . getContext ( '2d' ) ; if ( context ) { this . context = context ; } } public ngOnInit ( ) { this . renderer . listen ( this . canvas , 'mousedown' , ( event ) => { this . lastPos = this . getMousePosition ( this . canvas , event ) ; this . mousePos = { ... this . lastPos } ; this . isDrawing = true ; this . startDrawing ( ) ; } ) ; this . renderer . listen ( this . canvas , 'touchstart' , ( event ) => { this . lastPos = this . getTouchPosition ( this . canvas , event ) ; this . mousePos = { ... this . lastPos } ; this . isDrawing = true ; this . startDrawing ( ) ; } ) ; this . renderer . listen ( this . canvas , 'mouseup' , ( event ) => { this . lastPos = this . getMousePosition ( this . canvas , event ) ; this . isDrawing = false ; } ) ; this . renderer . listen ( this . canvas , 'touchend' , ( event ) => { this . lastPos = this . getTouchPosition ( this . canvas , event ) ; this . isDrawing = false ; } ) ; this . renderer . listen ( this . canvas , 'mousemove' , ( event ) => { this . mousePos = this . getMousePosition ( this . canvas , event ) ; } ) ; this . renderer . listen ( this . canvas , 'touchmove' , ( event ) => { this . mousePos = this . getTouchPosition ( this . canvas , event ) ; } ) ; } public startDrawing ( ) { if ( ! this . isDrawing ) { return ; } this . ngZone . runOutsideAngular ( ( ) => { requestAnimationFrame ( ( ) => { this . renderEntropyDrawing ( ) ; } ) ; } ) ; } public getMousePosition ( canvas , event ) { const rect = canvas . getBoundingClientRect ( ) ; return { x : event . clientX - rect . left , y : event . clientY - rect . top } ; } public getTouchPosition ( canvas , event ) { const rect = canvas . getBoundingClientRect ( ) ; if ( ! event . touches [ 0 ] ) { return this . lastPos ; } return { x : event . touches [ 0 ] . clientX - rect . left , y : event . touches [ 0 ] . clientY - rect . top } ; } public renderEntropyDrawing ( ) { this . context . strokeStyle = 'rgb(255, 255, 255)' ; this . context . moveTo ( this . lastPos . x , this . lastPos . y ) ; this . context . lineTo ( this . mousePos . x , this . mousePos . y ) ; this . lastPos = this . mousePos ; this . context . stroke ( ) ; this . startDrawing ( ) ; } }