author Christopher Cook
*  copyright import { Observable } from 'rxjs/Observable' ; import { Utils } from '../../../core/Utils' ; import { MappingAPI , IMapProvider , MapOptions , IMapManager } from '../interfaces/mapping' ; import { Events } from '../../../services/Events' ; import { Dictionary } from 'typescript-collections' ; import { GeoPosition , GeoLatLng , GeoBounds } from './../../../model/GeoPosition' ; import { Logging , LogLevel } from './../../Logging' ; import { GoogleMaps , GoogleMap , GoogleMapsEvent , GoogleMapOptions , CameraPosition , MarkerCluster , MarkerOptions , Marker , BaseArrayClass , GoogleMapsMapTypeId , Environment , LatLngBounds } from '@ionic-native/google-maps/ngx' ; import { environment } from '../../../../environments/environment' ; import { MapIcons } from '../Icons' ; import { PlaceSearchResult } from '../../../model/AppModels' ; module export class GoogleMapsNative implements IMapProvider { mapAPIType : MappingAPI ; mapReady : boolean ; providerError : string ; mapCanvasID : string ; private map : GoogleMap ; private markerList : Dictionary < number , Marker > ; private maxMarkers : number = 200 ; private markerAllocCount : number = 0 ; private polylinePath : any ; constructor constructor ( private events , private logging ) { this . mapAPIType = MappingAPI . GOOGLE_NATIVE ; this . mapReady = false ; this . mapCanvasID = "map-view" ; this . markerList = new Dictionary < number , Marker > ( ) ; } initAPI ( ) { } param mapcanvasID param mapConfig param mapManipulationCallback initMap ( mapCanvasID , mapConfig , parentMapManager ) { this . logging . log ( "GoogleMapsNative: initMap" ) ; this . mapCanvasID = mapCanvasID ; let apiAvailable = true ; if ( GoogleMaps ) { apiAvailable = true ; this . logging . log ( "Native maps plugin is available." ) ; if ( this . map == null ) { let key = environment . googleMapsKey ; Environment . setEnv ( { 'API_KEY_FOR_BROWSER_RELEASE' : key , 'API_KEY_FOR_BROWSER_DEBUG' : key } ) ; this . map = GoogleMaps . create ( mapCanvasID , { mapType : GoogleMapsMapTypeId . ROADMAP , controls : { compass : true , myLocationButton : false , zoom : true } , gestures : { scroll : true , tilt : true , rotate : true , zoom : true } , camera : { 'zoom' : 10 } } ) ; this . map . one ( GoogleMapsEvent . MAP_READY ) . then ( ( ) => { this . logging . log ( "Native Mapping Ready." , LogLevel . INFO ) ; this . map . setVisible ( true ) ; this . mapReady = true ; this . events . publish ( 'ocm:mapping:ready' ) ; this . setMapCenter ( new GeoPosition ( 37.415328 , - 122.076575 ) ) ; this . map . addEventListener ( GoogleMapsEvent . CAMERA_MOVE_END ) . subscribe ( ( ) => { this . events . publish ( 'ocm:mapping:dragend' ) ; this . events . publish ( 'ocm:mapping:zoom' ) ; } ) ; } ) ; } else { this . logging . log ( "Map object is not null at init.." ) ; } } else { this . logging . log ( "No native maps plugin available." ) ; this . mapReady = false ; } } param poiList param parentContext showPOIListOnMap ( poiList , parentContext ) { let clearMarkersOnRefresh = false ; this . map . setVisible ( true ) ; this . renderPOIMarkers ( clearMarkersOnRefresh , poiList ) ; } clearMarkers ( ) { if ( this . markerList != null ) { this . markerList . forEach ( ( key , marker ) => { try { marker . remove ( ) ; } catch { } } ) ; } this . markerList = new Dictionary < number , Marker > ( ) ; } renderPOIMarkers ( clearMarkersOnRefresh , poiList ) { let map = this . map ; let _providerContext = this ; let bounds = new LatLngBounds ( ) ; let markersAdded = 0 ; if ( clearMarkersOnRefresh == true ) { this . clearMarkers ( ) ; } let markersToAdd = [ ] ; if ( poiList != null ) { let poiCount = poiList . length ; for ( let i = 0 ; i < poiList . length ; i ++ ) { let item = poiList [ i ] ; if ( item . AddressInfo != null && item . AddressInfo . Latitude != null && item . AddressInfo . Longitude != null ) { if ( ! this . markerList . containsKey ( item . ID ) ) { markersToAdd . push ( item ) ; } } } let useClustering = false ; if ( markersToAdd . length > 0 ) { if ( useClustering ) { let markerCluster = this . map . addMarkerClusterSync ( { markers : markersToAdd , icons : [ { min : 3 , max : 9 , url : "./assets/markercluster/small.png" , label : { color : "white" } } , { min : 10 , url : "./assets/markercluster/large.png" , label : { color : "white" } } ] } ) ; } else { let baseArray = new BaseArrayClass < any > ( markersToAdd ) ; baseArray . mapAsync ( ( poi , callback ) => { let poiLevel = Utils . getMaxLevelOfPOI ( poi ) ; let iconName = MapIcons . getIconName ( poi , poiLevel , false ) ; let markerTooltip = "OCM-" + poi . ID + ": " + poi . AddressInfo . Title + ":" ; if ( poi . UsageType != null ) { markerTooltip += " " + poi . UsageType . Title ; } if ( poiLevel > 0 ) { markerTooltip += " Level " + poiLevel ; } if ( poi . StatusType != null ) { markerTooltip += " " + poi . StatusType . Title ; } let opt = { position : { lat : poi . AddressInfo . Latitude , lng : poi . AddressInfo . Longitude } , title : poi . Title , icon : { url : MapIcons . getIcon ( iconName ) , size : { width : 34 , height : 50 } } } ; map . addMarker ( opt ) . then ( ( m => { this . markerList . setValue ( poi . ID , m ) ; m . poi = poi ; m . on ( GoogleMapsEvent . MARKER_CLICK ) . subscribe ( ( poiClicked ) => { this . events . publish ( 'ocm:poi:selected' , { poi : poiClicked [ 1 ] . poi , poiId : poiClicked [ 1 ] . poi . ID } ) ; } ) ; } ) ) ; } ) . then ( ( markers ) => { markersAdded = markers . length ; this . logging . log ( markersAdded + " new map markers added out of a total " + this . markerList . values . length + " [alloc:" + this . markerAllocCount + "]" ) ; } ) ; } } } this . refreshMapLayout ( ) ; } refreshMapLayout ( ) { } setMapCenter ( pos , zoomLevel ? ) { if ( this . mapReady ) { let mapOptions = { target : { lat : pos . coords . latitude , lng : pos . coords . longitude } } ; if ( zoomLevel ) { mapOptions . zoom = zoomLevel ; } this . map . moveCamera ( mapOptions ) ; } } getMapCenter ( ) { let obs = new Observable < GeoPosition > ( ( observer => { let result = this . map . getCameraPosition ( ) ; if ( result ) { const geoPos = new GeoPosition ( result . target . lat , result . target . lng ) ; observer . next ( geoPos ) ; observer . complete ( ) ; } else { } } ) ) ; return obs ; } setMapZoom ( zoomLevel ) { this . map . setCameraZoom ( zoomLevel ) ; } getMapZoom ( ) { let obs = new Observable < number > ( observer => { let zoom = this . map . getCameraZoom ( ) ; observer . next ( zoom ) ; observer . complete ( ) ; } ) ; return obs ; } setMapType ( mapType ) { try { this . map . setMapTypeId ( "google.maps.MapTypeId." + mapType ) ; } catch ( exception ) { this . logging . log ( "Failed to set map type:" + mapType + " : " + exception . toString ( ) ) ; } } getMapBounds ( ) { let obs = new Observable < Array < GeoLatLng > > ( ( observer ) => { let mapBounds = this . map . getVisibleRegion ( ) ; if ( mapBounds != null ) { let bounds = new Array < GeoLatLng > ( ) ; bounds . push ( new GeoLatLng ( mapBounds . southwest . lat , mapBounds . southwest . lng ) ) ; bounds . push ( new GeoLatLng ( mapBounds . northeast . lat , mapBounds . northeast . lng ) ) ; observer . next ( bounds ) ; observer . complete ( ) ; } else { this . logging . log ( "google maps native: failed to get map bounds" ) ; observer . error ( ) ; } } ) ; return obs ; } moveToMapBounds ( bounds ) { } renderMap ( poiList , mapHeight , parentContext ) { if ( ! this . mapReady ) { this . logging . log ( "renderMap: skipping render, map not ready yet" ) ; } if ( this . map == null ) { this . logging . log ( "Native map not initialised" ) ; } if ( this . mapCanvasID == null ) { this . logging . log ( "mapcanvasid not set!!" ) ; } this . showPOIListOnMap ( poiList , parentContext ) ; return true ; } renderPolyline ( polyline ) { this . clearPolyline ( ) ; this . map . addPolyline ( { points : < any > google . maps . geometry . encoding . decodePath ( polyline ) , 'color' : '#AA00FF' , 'width' : 10 , 'geodesic' : true } ) ; } clearPolyline ( ) { if ( this . polylinePath != null ) { this . polylinePath . setMap ( null ) ; } } unfocusMap ( ) { this . map . setClickable ( false ) ; } focusMap ( ) { if ( this . mapReady ) { this . map . setClickable ( true ) ; } else { this . logging . log ( "focus: map not ready.." ) ; } } placeSearch ( keyword ) { return null ; } addPOILayer ( data ) { this . logging . log ( "Add POI Layer not implemented in this provider." ) ; } }