import { Directive , ElementRef , EventEmitter , HostListener , Input , NgZone , OnChanges , OnDestroy , OnInit , Output , SimpleChange } from '@angular/core' ; import { latLng , LatLng , LatLngBounds , LeafletEvent , LeafletMouseEvent , map , Map , MapOptions } from 'leaflet' ; import { LeafletUtil } from './leaflet.util' ; @ Directive ( { selector : '[leaflet]' } ) export class LeafletDirective implements OnChanges , OnDestroy , OnInit { readonly DEFAULT_ZOOM = 1 ; readonly DEFAULT_CENTER = latLng ( 38.907192 , - 77.036871 ) ; readonly DEFAULT_FPZ_OPTIONS = { } ; resizeTimer : any ; map : Map ; @ Input ( 'leafletFitBoundsOptions' ) fitBoundsOptions = this . DEFAULT_FPZ_OPTIONS ; @ Input ( 'leafletPanOptions' ) panOptions = this . DEFAULT_FPZ_OPTIONS ; @ Input ( 'leafletZoomOptions' ) zoomOptions = this . DEFAULT_FPZ_OPTIONS ; @ Input ( 'leafletZoomPanOptions' ) zoomPanOptions = this . DEFAULT_FPZ_OPTIONS ; @ Input ( 'leafletOptions' ) options : MapOptions = { } ; @ Output ( 'leafletMapReady' ) mapReady = new EventEmitter < Map > ( ) ; @ Input ( 'leafletZoom' ) zoom : number ; @ Output ( 'leafletZoomChange' ) zoomChange = new EventEmitter < number > ( ) ; @ Input ( 'leafletCenter' ) center : LatLng ; @ Output ( 'leafletCenterChange' ) centerChange = new EventEmitter < LatLng > ( ) ; @ Input ( 'leafletFitBounds' ) fitBounds : LatLngBounds ; @ Input ( 'leafletMaxBounds' ) maxBounds : LatLngBounds ; @ Input ( 'leafletMinZoom' ) minZoom : number ; @ Input ( 'leafletMaxZoom' ) maxZoom : number ; @ Output ( 'leafletClick' ) onClick = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletDoubleClick' ) onDoubleClick = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletMouseDown' ) onMouseDown = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletMouseUp' ) onMouseUp = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletMouseMove' ) onMouseMove = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletMouseOver' ) onMouseOver = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletMouseOut' ) onMouseOut = new EventEmitter < LeafletMouseEvent > ( ) ; @ Output ( 'leafletMapMove' ) onMapMove = new EventEmitter < LeafletEvent > ( ) ; @ Output ( 'leafletMapMoveStart' ) onMapMoveStart = new EventEmitter < LeafletEvent > ( ) ; @ Output ( 'leafletMapMoveEnd' ) onMapMoveEnd = new EventEmitter < LeafletEvent > ( ) ; @ Output ( 'leafletMapZoom' ) onMapZoom = new EventEmitter < LeafletEvent > ( ) ; @ Output ( 'leafletMapZoomStart' ) onMapZoomStart = new EventEmitter < LeafletEvent > ( ) ; @ Output ( 'leafletMapZoomEnd' ) onMapZoomEnd = new EventEmitter < LeafletEvent > ( ) ; private mapEventHandlers : any = { } ; constructor ( private element , private zone ) { } ngOnInit ( ) { this . zone . runOutsideAngular ( ( ) => { this . map = map ( this . element . nativeElement , this . options ) ; this . addMapEventListeners ( ) ; } ) ; if ( null != this . center && null != this . zoom ) { this . setView ( this . center , this . zoom ) ; } if ( null != this . fitBounds ) { this . setFitBounds ( this . fitBounds ) ; } if ( null != this . maxBounds ) { this . setMaxBounds ( this . maxBounds ) ; } if ( null != this . minZoom ) { this . setMinZoom ( this . minZoom ) ; } if ( null != this . maxZoom ) { this . setMaxZoom ( this . maxZoom ) ; } this . doResize ( ) ; this . mapReady . emit ( this . map ) ; } ngOnChanges ( changes ) { if ( changes [ 'zoom' ] && changes [ 'center' ] && null != this . zoom && null != this . center ) { this . setView ( changes [ 'center' ] . currentValue , changes [ 'zoom' ] . currentValue ) ; } else if ( changes [ 'zoom' ] ) { this . setZoom ( changes [ 'zoom' ] . currentValue ) ; } else if ( changes [ 'center' ] ) { this . setCenter ( changes [ 'center' ] . currentValue ) ; } if ( changes [ 'fitBounds' ] ) { this . setFitBounds ( changes [ 'fitBounds' ] . currentValue ) ; } if ( changes [ 'maxBounds' ] ) { this . setMaxBounds ( changes [ 'maxBounds' ] . currentValue ) ; } if ( changes [ 'minZoom' ] ) { this . setMinZoom ( changes [ 'minZoom' ] . currentValue ) ; } if ( changes [ 'maxZoom' ] ) { this . setMaxZoom ( changes [ 'maxZoom' ] . currentValue ) ; } } ngOnDestroy ( ) { this . map . remove ( ) ; } public getMap ( ) { return this . map ; } @ HostListener ( 'window:resize' , [ ] ) onResize ( ) { this . delayResize ( ) ; } private addMapEventListeners ( ) { const registerEventHandler = ( eventName , handler ) => { this . mapEventHandlers [ eventName ] = handler ; this . map . on ( eventName , handler ) ; } ; registerEventHandler ( 'click' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onClick , e ) ) ; registerEventHandler ( 'dblclick' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onDoubleClick , e ) ) ; registerEventHandler ( 'mousedown' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMouseDown , e ) ) ; registerEventHandler ( 'mouseup' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMouseUp , e ) ) ; registerEventHandler ( 'mouseover' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMouseOver , e ) ) ; registerEventHandler ( 'mouseout' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMouseOut , e ) ) ; registerEventHandler ( 'mousemove' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMouseMove , e ) ) ; registerEventHandler ( 'zoomstart' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMapZoomStart , e ) ) ; registerEventHandler ( 'zoom' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMapZoom , e ) ) ; registerEventHandler ( 'zoomend' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMapZoomEnd , e ) ) ; registerEventHandler ( 'movestart' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMapMoveStart , e ) ) ; registerEventHandler ( 'move' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMapMove , e ) ) ; registerEventHandler ( 'moveend' , ( e ) => LeafletUtil . handleEvent ( this . zone , this . onMapMoveEnd , e ) ) ; const outputUpdateHandler = ( ) => { const zoom = this . map . getZoom ( ) ; if ( zoom !== this . zoom ) { this . zoom = zoom ; LeafletUtil . handleEvent ( this . zone , this . zoomChange , zoom ) ; } const center = this . map . getCenter ( ) ; if ( null != center || null != this . center ) { if ( ( ( null == center || null == this . center ) && center !== this . center ) || ( center . lat !== this . center . lat || center . lng !== this . center . lng ) ) { this . center = center ; LeafletUtil . handleEvent ( this . zone , this . centerChange , center ) ; } } } ; registerEventHandler ( 'moveend' , outputUpdateHandler ) ; registerEventHandler ( 'zoomend' , outputUpdateHandler ) ; } /**
     * Resize the map to fit it's parent container
     */ private doResize ( ) { this . zone . runOutsideAngular ( ( ) => { this . map . invalidateSize ( { } ) ; } ) ; } /**
     * Manage a delayed resize of the component
     */ private delayResize ( ) { if ( null != this . resizeTimer ) { clearTimeout ( this . resizeTimer ) ; } this . resizeTimer = setTimeout ( this . doResize . bind ( this ) , 200 ) ; } param center param zoom private setView ( center , zoom ) { if ( this . map && null != center && null != zoom ) { this . map . setView ( center , zoom , this . zoomPanOptions ) ; } } param zoom private setZoom ( zoom ) { if ( this . map && null != zoom ) { this . map . setZoom ( zoom , this . zoomOptions ) ; } } param center private setCenter ( center ) { if ( this . map && null != center ) { this . map . panTo ( center , this . panOptions ) ; } } param latLngBounds private setFitBounds ( latLngBounds ) { if ( this . map && null != latLngBounds ) { this . map . fitBounds ( latLngBounds , this . fitBoundsOptions ) ; } } param latLngBounds private setMaxBounds ( latLngBounds ) { if ( this . map && null != latLngBounds ) { this . map . setMaxBounds ( latLngBounds ) ; } } param number private setMinZoom ( zoom ) { if ( this . map && null != zoom ) { this . map . setMinZoom ( zoom ) ; } } param number private setMaxZoom ( zoom ) { if ( this . map && null != zoom ) { this . map . setMaxZoom ( zoom ) ; } } }