import { HttpClient } from '@angular/common/http' ; import { AfterViewInit , ChangeDetectionStrategy , Component , ElementRef , Input , ViewChild , ViewEncapsulation } from '@angular/core' ; import * as L from 'leaflet' ; import { LegendControl } from '../map-control/legend-control' ; import { MobileCheckPipe } from '@shared/mobile-check.pipe' ; import { MousePosition } from '../map-control/mouse-position' ; import { WindowRef } from './../window-ref-wrapper' ; param baselayer param showAttributionControl @ Component ( { changeDetection : ChangeDetectionStrategy . OnPush , encapsulation : ViewEncapsulation . None , selector : 'shared-map' , styleUrls : [ './map.component.scss' ] , templateUrl : './map.component.html' } ) export class MapComponent implements AfterViewInit { _bounds : Array < Array < number > > = null ; _interactive = false ; _isMobile = false ; _isMobilePipe = new MobileCheckPipe ( new WindowRef ( ) ) ; _overlays : Array < L . Layer > = [ ] ; _showLayersControl = false ; _showLegendControl = false ; _showMousePosition = false ; _showScaleControl = false ; @ Input ( ) baselayer = 'Topographic' ; layersControl : L . Control . Layers ; legendControl : L . Control ; map : L . Map ; @ ViewChild ( 'mapWrapper' , { static : true } ) mapWrapper : ElementRef ; mousePositionControl : L . Control ; overlaysAdded : Array < L . Layer > = [ ] ; scaleControl : L . Control . Scale ; @ Input ( ) scrollWheelZoom : Boolean = false ; @ Input ( ) showAttributionControl : Boolean = true ; zoomControl : L . Control . Zoom ; constructor ( private httpClient ) { } return { any } getOverlayBounds ( ) { let bounds = null ; this . overlays . forEach ( overlay => { if ( overlay . bounds !== null ) { if ( bounds === null ) { bounds = L . latLngBounds ( overlay . bounds ) ; } else { bounds = bounds . extend ( overlay . bounds ) ; } } } ) ; return bounds ; } ngAfterViewInit ( ) { const worldTopoLayer = L . tileLayer ( 'https://services.arcgisonline.com/' + 'arcgis/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}' , { attribution : 'Esri, HERE, Garmin, Intermap, increment P Corp., ' + 'GEBCO, USGS, FAO, NPS, NRCAN, GeoBase, IGN, Kadaster NL, ' + 'Ordnance Survey, Esri Japan, METI, Esri China (Hong Kong), ' + 'swisstopo, © OpenStreetMap contributors, and the GIS User ' + 'Community' , maxZoom : 16 } ) ; const worldImageryLayer = L . tileLayer ( 'https://services.arcgisonline.com/' + 'arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' , { attribution : 'Esri, DigitalGlobe, GeoEye, Earthstar Geographics, ' + 'CNES/Airbus DS, USDA, USGS, AeroGRID, IGN, and the GIS ' + 'User Community' , maxZoom : 16 } ) ; const worldStreetLayer = L . tileLayer ( 'https://services.arcgisonline.com/' + 'arcgis/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}' , { attribution : 'Esri, HERE, Garmin, USGS, Intermap, INCREMENT P, ' + 'NRCan, Esri Japan, METI, Esri China (Hong Kong), Esri Korea, ' + 'Esri (Thailand), NGCC, © OpenStreetMap contributors, and the ' + 'GIS User Community' , maxZoom : 16 } ) ; const grayscaleLayer = L . tileLayer ( 'https://services.arcgisonline.com/' + 'arcgis/rest/services/Canvas/World_Light_Gray_Base/' + 'MapServer/tile/{z}/{y}/{x}' , { attribution : 'Esri, HERE, Garmin, © OpenStreetMap contributors, ' + 'and the GIS user community' , maxZoom : 16 } ) ; this . _isMobile = this . _isMobilePipe . transform ( ) ; this . _isMobilePipe = null ; const baselayers = { Aerial : worldImageryLayer , Grayscale : grayscaleLayer , Street : worldStreetLayer , Topographic : worldTopoLayer } ; this . map = L . map ( this . mapWrapper . nativeElement , { attributionControl : this . showAttributionControl , boxZoom : true , doubleClickZoom : true , dragging : true , keyboard : true , layers : [ baselayers [ this . baselayer ] ] , scrollWheelZoom : this . scrollWheelZoom , tap : true , touchZoom : true , zoomControl : false , zoomSnap : 0 } ) ; this . mousePositionControl = new MousePosition ( ) ; this . layersControl = L . control . layers ( baselayers , { } ) ; this . legendControl = new LegendControl ( { position : 'topright' } ) ; this . scaleControl = L . control . scale ( { position : 'bottomleft' } ) ; this . zoomControl = L . control . zoom ( ) ; this . updateControls ( ) ; this . updateInteractive ( ) ; this . updateOverlays ( ) ; if ( this . map ) { const northEastGlobal = L . latLng ( - 90.0 , - 180.0 * 2 ) ; const southWestGlobal = L . latLng ( 90.0 , 180.0 * 2 ) ; const globalBounds = L . latLngBounds ( northEastGlobal , southWestGlobal ) ; this . map . setMaxBounds ( globalBounds ) ; } } param bounds @ Input ( ) set bounds ( bounds ) { this . _bounds = bounds ; this . setBounds ( ) ; } return { Array < number > } get bounds ( ) : Array < Array < number > > { return this . _bounds ; } param interactive @ Input ( ) set interactive ( interactive ) { this . _interactive = interactive ; this . updateControls ( ) ; this . updateInteractive ( ) ; } return { boolean } get interactive ( ) : boolean { return this . _interactive ; } param overlays @ Input ( ) set overlays ( overlays ) { this . _overlays = overlays ; this . updateOverlays ( ) ; this . updateLegend ( ) ; } return { Array < L . layer > } get overlays ( ) : Array < L . Layer > { return this . _overlays ; } param showLayersControl @ Input ( ) set showLayersControl ( showLayersControl ) { this . _showLayersControl = showLayersControl ; this . updateControls ( ) ; } return { boolean } get showLayersControl ( ) : boolean { return this . _showLayersControl ; } param showLegendControl @ Input ( ) set showLegendControl ( showLegendControl ) { this . _showLegendControl = showLegendControl ; this . updateControls ( ) ; } return { boolean } get showLegendControl ( ) : boolean { return this . _showLegendControl ; } param showScaleControl @ Input ( ) set showScaleControl ( showScaleControl ) { this . _showScaleControl = showScaleControl ; this . updateControls ( ) ; } return { boolean } get showScaleControl ( ) : boolean { return this . _showScaleControl ; } /**
     * Set map to match overlay bounds
     */ setBounds ( ) { if ( ! this . map ) { return ; } let bounds = this . bounds ; if ( ! bounds || ( bounds . isValid && ! bounds . isValid ( ) ) ) { bounds = this . getOverlayBounds ( ) ; } if ( ! bounds || ( bounds . isValid && ! bounds . isValid ( ) ) ) { bounds = [ [ 85.0 , 179.999 ] , [ - 85.0 , - 179.999 ] ] ; } setTimeout ( ( ) => { if ( this . map ) { this . map . fitBounds ( bounds ) ; this . map . invalidateSize ( ) ; } } , 0 ) ; } /**
     * Update/add map controls
     */ updateControls ( ) { if ( ! this . map ) { return ; } if ( ! this . _isMobile && this . interactive === true ) { this . map . addControl ( this . mousePositionControl ) ; } else { this . map . removeControl ( this . mousePositionControl ) ; } if ( this . showLayersControl && this . interactive === true ) { this . map . addControl ( this . layersControl ) ; } else { this . map . removeControl ( this . layersControl ) ; } if ( this . showLegendControl && this . interactive === true ) { this . map . addControl ( this . legendControl ) ; } else { this . map . removeControl ( this . legendControl ) ; } if ( this . showScaleControl ) { this . map . addControl ( this . scaleControl ) ; } else { this . map . removeControl ( this . scaleControl ) ; } if ( this . interactive ) { this . map . addControl ( this . zoomControl ) ; } else { this . map . removeControl ( this . zoomControl ) ; } } /**
     * Make the map interactive
     */ updateInteractive ( ) { if ( ! this . map ) { return ; } const handlers = [ this . map . boxZoom , this . map . doubleClickZoom , this . map . dragging , this . map . keyboard , this . map . tap , this . map . touchZoom ] ; const interactive = this . interactive ; handlers . forEach ( handler => { if ( ! handler ) { return ; } if ( interactive ) { handler . enable ( ) ; } else { handler . disable ( ) ; } } ) ; } /**
     * Update legend control
     */ updateLegend ( ) { if ( ! this . legendControl ) { return ; } this . legendControl . displayLegends ( ) ; } /**
     * Update map overlays
     */ updateOverlays ( ) { if ( ! this . map || ! this . layersControl ) { return ; } const overlays = this . _overlays ; this . overlaysAdded = this . overlaysAdded . filter ( overlay => { if ( ! overlays . includes ( overlay ) ) { this . layersControl . removeLayer ( overlay ) ; this . map . removeLayer ( overlay ) ; return false ; } else { return true ; } } ) ; overlays . forEach ( overlay => { if ( overlay . hasOwnProperty ( 'httpClient' ) ) { overlay . httpClient = this . httpClient ; } if ( ! this . overlaysAdded . includes ( overlay ) ) { this . overlaysAdded . push ( overlay ) ; this . layersControl . addOverlay ( overlay , overlay . title ) ; } if ( overlay . enabled ) { this . map . addLayer ( overlay ) ; } else { this . map . removeLayer ( overlay ) ; } } ) ; this . setBounds ( ) ; } }