author Yermo Lamers, Flying Brick Software, LLC https://github.com/Yermo
 import { Component , OnInit , OnDestroy , ViewChild , ViewContainerRef , Input , NgZone , HostListener } from '@angular/core' ; import * as dialogs from "tns-core-modules/ui/dialogs" ; import * as app from "tns-core-modules/application" ; import { Mapbox , MapboxViewApi } from "nativescript-mapbox" ; import { PlatformService } from '../../services/platform.service' ; import { EventsService } from '../../services/events.service' ; import { SettingsService } from '../../services/settings.service' ; import { DebugService } from '../../services/debug.service' ; import { registerElement } from "nativescript-angular/element-registry" ; registerElement ( "Mapbox" , ( ) => require ( "nativescript-mapbox" ) . MapboxView ) ; todo @ Component ( { selector : "map" , moduleId : module . id , template : `

    <StackLayout height="100%" width="100%">
      <ContentView height="100%" width="100%">
        <Mapbox
          accessToken="{{access_token}}"
          mapStyle="{{style}}"
          latitude="{{fallbackLatitude}}"
          longitude="{{fallbackLongitude}}"
          zoomLevel="10"
          delay="10"
          showUserLocation="false"
          hideCompass="false"
          hideAttribution="false"
          hideLogo="false"
          disableZoom="false"
          disableRotation="false"
          disableScroll="false"
          disableTilt="false"
         (mapReady)="onMapReady($event)"
         (mapDestroyed)="onMapDestroyed($event)"
         (moveBeginEvent)="onMoveBegin($event)"
         (locationPermissionGranted)="onLocationPermissionGranted($event)"
         (locationPermissionDenied)="onLocationPermissionDenied($event)">
        </Mapbox>
      </ContentView>
    </StackLayout>

  ` , styleUrls : [ "./map.component.css" ] } ) export class MapComponent implements OnInit , OnDestroy { loading : any ; /**
    * ready promise
    *
    * The map can take some time to be "ready" especially if it's slow to load the style
    * so this promise is used by child tags. Before attempting to access the map, they
    * wait for the promise to be resolved.
    */ public readyPromise : Promise < any > ; public readyPromiseResolver : any ; public isReady : boolean = false ; @ Input ( ) id : string ; @ Input ( ) style : string ; @ Input ( ) access_token : string ; @ Input ( ) location : any ; /**
    * The map template
    */ @ ViewChild ( 'mapTemplate' , { static : false } ) mapTemplate ; /**
    * the reference to the element that contains the map.
    */ @ ViewChild ( 'mapContainer' , { read : ViewContainerRef , static : false } ) mapContainer ; public mapboxView : MapboxViewApi = null ; public mapboxApi : Mapbox = null ; @ Input ( ) fallbackLatitude : string ; @ Input ( ) fallbackLongitude : string ; shown : boolean = true ; afterMapDestroyed : any = null ; link constructor ( public ngZone , public viewContainerRef , public platform , public settingsService , public events , public debugService ) { console . log ( "MapComponent::constructor(): top" ) ; this . isReady = false ; this . readyPromise = new Promise ( ( resolve , reject ) => { this . readyPromiseResolver = resolve ; } ) ; this . registerEventHandlers ( ) ; } link link registerEventHandlers ( ) { this . events . subscribe ( 'platform:pause' , ( ) => { this . onPause ( ) ; } ) ; this . events . subscribe ( 'platform:exit' , ( ) => { this . onExit ( ) ; } ) ; this . events . subscribe ( 'platform:resume' , ( ) => { this . onResume ( ) ; } ) ; } /**
    * unregister event handlers
    */ unRegisterEventHandlers ( ) { this . events . unsubscribe ( 'platform:pause' ) ; this . events . unsubscribe ( 'platform:exit' ) ; this . events . unsubscribe ( 'platform:resume' ) ; this . events . unsubscribe ( 'destroyMap' ) ; this . readyPromise = null ; } ngOnInit ( ) { console . log ( "MapComponent::ngOnInit(): with style '" + this . style + "' and access token '" + this . access_token + "'" ) ; } /**
    * when the map is ready
    *
    * The onMapReady() callback is invoked when the MapboxView class instance is ready.
    */ onMapReady ( args ) { console . log ( "MapComponent:onMapReady(): top" ) ; if ( ! this . isReady ) { console . log ( "MapComponent:onMapReady(): First call to onMapReady()" ) ; this . isReady = true ; } else { console . error ( "MapComponent:onMapReady(): duplicate call to onMapReady()" ) ; } if ( this . mapboxView ) { console . error ( "MapComponent:onMapReady() callback called when we already have a valid mapboxView. isReady is:" , this . isReady ) ; return ; } this . mapboxView = args . map ; this . declareReady ( ) ; console . log ( "MapComponent:onMapReady(): after declareReady()" ) ; } /**
    * when the app is paused
    *
    * Workaround for android pause/resume crash.
    */ async onPause ( ) { console . log ( "MapComponent::onPause()" ) ; this . shown = false ; } /**
    * when the app exits
    */ onExit ( ) { console . log ( "MapComponent::onExit()" ) ; this . shown = false ; } /**
    * when the app is resumed
    */ onResume ( ) { console . log ( "MapComponent::onResume()" ) ; this . shown = true ; } /**
    * returns the ready promise
    */ ready ( ) { return this . readyPromise ; } /**
    * declare that we are ready
    *
    * Resolves our ready promise.
    */ declareReady ( ) { console . log ( "MapComponent:declareReady(): the map component is ready" ) ; this . isReady = true ; this . readyPromiseResolver ( true ) ; } link todo @ HostListener ( 'unloaded' ) async ngOnDestroy ( ) { console . log ( "MapComponent:ngOnDestroy()" ) ; this . unRegisterEventHandlers ( ) ; this . mapboxView . destroy ( ) ; } /**
    * Save map settings
    *
    * To support creating and destroying the map as necessary to work around issues with
    * the Mapbox Android SDK, we have to save the settings of the map so we can restore it
    * to the same state as it was when the app was paused.
    */ async saveMapState ( ) { let center = await this . mapboxView . getCenter ( ) ; let zoom = await this . mapboxView . getZoomLevel ( ) ; let viewport = await this . mapboxView . getViewport ( ) ; let settings = { center : center , zoom : zoom , viewport : viewport } ; console . log ( "MapComponent:saveMapState(): got map settings:" , settings ) ; await this . settingsService . set ( 'mapSettings' , settings ) ; } /**
    * restore map settings
    *
    * When the map is recreated after a pause we return it to the settings it had when it was paused.
    */ async restoreMapState ( ) { let settings = await this . settingsService . get ( 'mapSettings' ) ; console . log ( "MapComponent:restoreMapState(): got settings :" , settings ) ; if ( settings ) { console . log ( "MapComponent:restoreMapState(): animating camera" ) ; await this . mapboxView . animateCamera ( { target : { lat : settings . center . lat , lng : settings . center . lng } , zoomLevel : settings . zoom , altitude : 2000 , bearing : 0 , tilt : 0 , duration : 2000 } ) ; } return settings ; } /**
    * on scroll event
    */ onMoveBegin ( event ) { console . log ( "MapComponent::onMoveBegin()" ) ; this . events . publish ( "map:moveBegin" ) ; } todo onLocationPermissionGranted ( ) { console . log ( "MapComponent:onLocationPermissionGranted(): callback" ) ; } onLocationPermissionDenied ( ) { console . log ( "MapComponent:onLocationPermissionDenied(): callback" ) ; return dialogs . alert ( { title : "Location Denied" , message : "Unable to get current location because the location permission has not been granted." , okButtonText : "OK" , } ) ; } /**
    * Center the map on a location
    *
    * Move the map to center on the given coordinates.
    */ centerOn ( location ) { console . log ( "MapComponent::centerOn(): top" ) ; this . mapboxView . setCenter ( { lat : location . latitude , lng : location . longitude , animated : true } ) ; } /**
    * Set the zoom to the specified value
    */ zoom ( zoomLevel ) { } /**
    * Attribution Control
    */ addAttributionControl ( position ) { } /**
    * Zoom control
    */ addZoomControl ( position ) { } addTestCircle ( ) { console . log ( "MapComponent:addTestCircle(): Adding test circle" ) ; const metersToPixelsAtMaxZoom = ( radius , latitude ) => radius / 0.075 / Math . cos ( latitude * Math . PI / 180 ) ; const pixels = metersToPixelsAtMaxZoom ( 500 , 39.007846 ) ; let style = { "id" : 'testCircle' , "type" : 'circle' , "circle-radius" : 250 , "source" : { "type" : 'geojson' , "data" : { "type" : "Feature" , "geometry" : { "type" : "Point" , "coordinates" : [ - 76.947041 , 39.007846 ] } } } , "paint" : { "circle-radius" : { "stops" : [ [ 0 , 0 ] , [ 20 , pixels ] ] , "base" : 2 } , 'circle-opacity' : 0.05 , 'circle-color' : '#ed6498' , 'circle-stroke-width' : 2 , 'circle-stroke-color' : '#ed6498' } } ; this . mapboxView . addLayer ( style ) . catch ( ( error ) => { console . error ( "MapComponent:addTestCircle(): addTestCircle threw an error:" , error ) ; } ) ; this . mapboxView . onMapEvent ( 'click' , 'testCircle' , ( point ) => { console . log ( "MapComponent:addTestCircle(): circle clicked" ) ; return true ; } ) ; } }