author Damien Dell'Amico <damien.dellamico@gmail.com>
 *  copyright license import { Injectable } from '@angular/core' ; import { Observable } from 'rxjs/Observable' ; import { Geolocation , Geoposition } from 'ionic-native' ; import { MapConst } from './map.constants' ; import { } from '@types/googlemaps' ; interface IMapOptions { lat : number ; lon : number ; zoom : number ; } @ Injectable ( ) export class MapService { private map : google . maps . Map = null ; private infoWindow : google . maps . InfoWindow = null ; constructor ( ) { } public createMap ( mapEl , opts = { lat : MapConst . DEFAULT_LAT , lon : MapConst . DEFAULT_LNG , zoom : MapConst . DEFAULT_ZOOM } ) { return this . loadMap ( ) . then ( ( ) => { const myLatLng = new google . maps . LatLng ( opts . lat , opts . lon ) ; const styleArray = [ { featureType : 'poi' , elementType : 'labels' , stylers : [ { visibility : 'off' } ] } ] ; const mapOptions = { zoom : opts . zoom , minZoom : opts . zoom , center : myLatLng , mapTypeId : google . maps . MapTypeId . ROADMAP , disableDefaultUI : true , scaleControl : false , styles : styleArray , zoomControl : false , zoomControlOptions : { position : google . maps . ControlPosition . BOTTOM_CENTER } } ; this . map = new google . maps . Map ( mapEl , mapOptions ) ; return this . map ; } ) ; } returns { LatLng } public get mapCenter ( ) : google . maps . LatLng { return this . map . getCenter ( ) ; } public set mapCenter ( location ) { this . map . setCenter ( location ) ; } returns { Element } public get mapElement ( ) : Element { return this . map . getDiv ( ) ; } param content param position public createInfoWindow ( content , position ) { this . closeInfoWindow ( ) ; const opt = { content , position , pixelOffset : new google . maps . Size ( 0 , - 50 ) , disableAutoPan : true } ; this . infoWindow = new google . maps . InfoWindow ( opt ) ; setTimeout ( ( ) => this . infoWindow . open ( this . map ) , 100 ) ; } /***
     * close the current infoWindow
     */ public closeInfoWindow ( ) { if ( this . infoWindow ) { this . infoWindow . close ( ) ; } } param addressEl returns { Observable } public createAutocomplete ( addressEl ) { const autocomplete = new google . maps . places . Autocomplete ( addressEl ) ; autocomplete . bindTo ( 'bounds' , this . map ) ; return new Observable ( ( sub ) => { google . maps . event . addListener ( autocomplete , 'place_changed' , ( ) => { const place = autocomplete . getPlace ( ) ; if ( ! place . geometry ) { sub . error ( { message : 'Autocomplete returned place with no geometry' } ) ; } else { sub . next ( place . geometry . location ) ; sub . complete ( ) ; } } ) ; } ) ; } returns { Promise < google . maps . LatLng > } public setPosition ( ) { return this . getCurrentPosition ( ) . then ( ( coords ) => { if ( ! coords ) { console . warn ( 'invalid coordinates: ' , coords ) ; return null ; } const myLatLng = new google . maps . LatLng ( coords . latitude , coords . longitude ) ; this . map . setCenter ( myLatLng ) ; this . map . setZoom ( MapConst . MAX_ZOOM ) ; return this . mapCenter ; } ) ; } /***
     * trigger map resize event
     */ public resizeMap ( ) { if ( this . map ) { google . maps . event . trigger ( this . map , 'resize' ) ; } } returns { Observable } public loadNearbyPlaces ( ) { const position = this . mapCenter ; const placesService = new google . maps . places . PlacesService ( this . map ) ; const request = { location : position , radius : 500 } ; return new Observable ( ( sub ) => { placesService . nearbySearch ( request , ( results , status ) => { const _nearbyPlaces = [ ] ; if ( status === google . maps . places . PlacesServiceStatus . OK ) { for ( let i = 0 ; i < results . length ; i ++ ) { const place = results [ i ] ; const distance = google . maps . geometry . spherical . computeDistanceBetween ( position , place . geometry . location ) ; place . distance = distance . toFixed ( 2 ) ; _nearbyPlaces . push ( place ) ; } sub . next ( _nearbyPlaces ) ; sub . complete ( ) ; } else { sub . error ( { message : `Invalid response status from nearbySearch : ${ status }` } ) ; } } ) ; } ) ; } returns { Promise } private loadMap ( ) { return new Promise ( ( resolve , reject ) => { if ( ( < any > window ) . google && ( < any > window ) . google . maps ) { resolve ( ) ; } else { this . loadGoogleMapApi ( ) . then ( ( ) => resolve ( ) ) . catch ( reason => { reject ( reason ) ; } ) ; } } ) ; } param maximumAge returns { Promise < Coordinates > } private getCurrentPosition ( maximumAge = 10000 ) { const options = { timeout : 10000 , enableHighAccuracy : true , maximumAge } ; return Geolocation . getCurrentPosition ( options ) . then ( ( pos ) => { return pos . coords ; } ) ; } returns { Promise } private private loadGoogleMapApi ( ) { const _loadScript = ( ) => { const script = document . createElement ( 'script' ) ; script . src = `https://maps.googleapis.com/maps/api/js?libraries=places,geometry&language=it&components=country:IT&callback=initMap` ; script . type = 'text/javascript' ; script . async = true ; const s = document . getElementsByTagName ( 'script' ) [ 0 ] ; s . parentNode . insertBefore ( script , s ) ; } ; return new Promise ( ( resolve ) => { ( < any > window ) . initMap = ( ) => { return resolve ( ) ; } ; _loadScript ( ) ; } ) ; } }