- Notifications
You must be signed in to change notification settings - Fork94
🗽 🗼 🗻 Native OpenGL powered Maps, by Mapbox
License
Yermo/nativescript-mapbox
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation

This project is now being maintained here:https://github.com/nativescript-community/ui-mapboxas it's become clear contrary to what I thought, I don't actually have enough time to maintain it myself.
Awesome native OpenGL-powered maps - by Mapbox
There is a NativeScript Core Modules bug under Android that causes random crashes on navigation. See ./demo-angular/README.md for a workaround.NativeScript/NativeScript#7954NativeScript/NativeScript#7867
You either need your own tile server such as the one provided byopenmaptiles.org or a Mapbox API access token (they have a 🆓 Starter plan!), sosign up with Mapbox.Once you've registered go to your Account > Apps > New token. The 'Default Secret Token' is what you'll need.
You will also need to set up your development environment. Please refer to theNativeScript documentation.
$ tns plugin install nativescript-mapboxTwo demo applications are available in the repository.
To run them, you'll need to clone the github repository and build the plugin. See below.
You will also need an access token. Your access_token can then be set in the top level mapbox_config.ts file.
The style can be set to one of the Mapbox style names or it can be the URL of your own hosted tile server.
NOTE: As of this writing, the NativeScript demo only works with a mapbox token. The demo-angular will work with either a self hosted tile server or a mapbox token.
cd srcnpm run build.releasecd ../demo-angulartns run <platform>cd srcnpm run build.releasecd ../demotns run <platform>To come up to speed on the plugin, I added extensive trace messages.These can be turned on by replacing 'npm run build.release' with 'npm run build.debug' in the commands above.
This version includes breaking API changes.
The intent moving forward is to mirror, to the maximum extent practical, the Mapbox GL JS API to enablesharing of mapping code between browser based and native applications.
If you get an error during iOS build related to Podspec versions, probably the easiest fix is:tns platform remove ios andtns platform add ios.
On Android the plugin adds this to the<application> node ofapp/App_Resources/Android/AndroidManifest.xml (the plugin already attempts to do so):
<serviceandroid:name="com.mapbox.services.android.telemetry.service.TelemetryService" />
If you get an error related toTelemetryService then please check it's there.
If you want a quickstart, see the demo in this repository.It shows you how to draw a map in XML and JS with almost all possible options.
There is also the beginnings of an Angular demo in demo-angular in this repository.
You can instantiate a map from JS or TS. As the map is yet another view component it will play nice with any NativeScript layout you throw it in. You can also easily add multiple maps to the same page or to different pages in any layout you like.
A simple layout could look like this:
Could be rendered by a definition like this:
<Pagexmlns="http://schemas.nativescript.org/tns.xsd"xmlns:map="nativescript-mapbox"navigatingTo="navigatingTo"> <StackLayout> <Labeltext="Nice map, huh!"class="title"/> <ContentViewheight="240"width="240"> <map:MapboxViewaccessToken="your_token"mapStyle="traffic_night"latitude="52.3702160"longitude="4.8951680"zoomLevel="3"showUserLocation="true"mapReady="onMapReady"> </map:MapboxView> </ContentView> </StackLayout></Page>
Component:
import{registerElement}from"nativescript-angular/element-registry";registerElement("Mapbox",()=>require("nativescript-mapbox").MapboxView);
View:
<ContentViewheight="100%"width="100%"><MapboxaccessToken="your_token"mapStyle="traffic_day"latitude="50.467735"longitude="13.427718"hideCompass="true"zoomLevel="18"showUserLocation="false"disableZoom="false"disableRotation="false"disableScroll="false"disableTilt="false"(mapReady)="onMapReady($event)"></Mapbox></ContentView>
All currently supported options for your XML based map are (don't use other properties - if you need styling wrap the map in aContentView and apply things likewidth to that container!):
| option | default | description |
|---|---|---|
accesstoken | - | see 'Prerequisites' above |
delay | 0 | A delay in milliseconds - you can set this to have better control over when Mapbox is invoked so it won't clash with other computations your app may need to perform. |
mapStyle | streets | streets, light, dark, satellite_streets, satellite, traffic_day, traffic_night, an URL starting with mapbox:// or pointing to a custom JSON definition (http://, https://, or local relative to nativescript app path ~/) |
latitude | - | Set the center of the map by passing this in |
longitude | - | .. and this as well |
zoomLevel | 0 | 0-20 |
showUserLocation | false | Requires location permissions on Android which you can remove fromAndroidManifest.xml if you don't need them |
hideCompass | false | Don't show the compass in the top right corner during rotation of the map |
hideLogo | false | Mapbox requiresfalse if you're on a free plan |
hideAttribution | true | Mapbox requiresfalse if you're on a free plan |
disableZoom | false | Don't allow the user to zoom in or out (pinch and double-tap) |
disableRotation | false | Don't allow the user to rotate the map (two finger gesture) |
disableScroll | false | Don't allow the user to move the center of the map (one finger drag) |
disableTilt | false | Don't allow the user to tilt the map (two finger drag up or down) |
mapReady | - | The name of a callback function you can declare to interact with the map after it has been drawn |
moveBeginEvent | - | The name of a function to be called when the map is moved. |
locationPermissionGranted | - | The name of a callback function you can declare to get notified when the user granted location permissions |
locationPermissionDenied | - | The name of a callback function you can declare to get notified when the user denied location permissions (will never fire on iOS because there's nothing to deny) |
This is where that last option in the table above comes in -mapReady.It allows you to interact with the map after it has been drawn to the page.
Openmain-page.[js|ts] and add this (seeaddMarkers further below for the full marker API):
varmapbox=require("nativescript-mapbox");functiononMapReady(args){// you can tap into the native MapView objects (MGLMapView for iOS and com.mapbox.mapboxsdk.maps.MapView for Android)varnativeMapView=args.ios ?args.ios :args.android;console.log("Mapbox onMapReady for "+(args.ios ?"iOS" :"Android")+", native object received: "+nativeMapView);// .. or use the convenience methods exposed on args.map, for instance:args.map.addMarkers([{lat:52.3602160,lng:4.8891680,title:'One-line title here',subtitle:'Really really nice location',selected:true,// makes the callout show immediately when the marker is added (note: only 1 marker can be selected at a time)onCalloutTap:function(){console.log("'Nice location' marker callout tapped");}}]);}exports.onMapReady=onMapReady;
varmapbox=require("nativescript-mapbox");functiononMapReady(args){args.map.setViewport({bounds:{north:52.4820,east:5.1087,south:52.2581,west:4.6816},animated:true});}exports.onMapReady=onMapReady;
The methods you can invoke like this from an XML-declared map are:addMarkers,setViewport,removeMarkers,getCenter,setCenter,getZoomLevel,setZoomLevel,getViewport,getTilt,setTilt,setMapStyle,animateCamera,addPolygon,removePolygons,addPolyline,removePolylines,getUserLocation,trackUser,setOnMapClickListener,setOnMapLongClickListener anddestroy.
Check out the usage details on the functions below.
Add a container to your view XML where you want to programmatically add the map. Give it an id.
<ContentView />constcontentView :ContentView=<ContentView>page.getViewById('mapContainer');constsettings={// NOTE: passing in the container here.container:contentView,accessToken:ACCESS_TOKEN,style:MapStyle.LIGHT,margins:{left:18,right:18,top:isIOS ?390 :454,bottom:isIOS ?50 :8},center:{lat:52.3702160,lng:4.8951680},zoomLevel:9,// 0 (most of the world) to 20, default 0showUserLocation:true,// default falsehideAttribution:true,// default falsehideLogo:true,// default falsehideCompass:false,// default falsedisableRotation:false,// default falsedisableScroll:false,// default falsedisableZoom:false,// default falsedisableTilt:false,// default falsemarkers:[{id:1,lat:52.3732160,lng:4.8941680,title:'Nice location',subtitle:'Really really nice location',iconPath:'res/markers/green_pin_marker.png',onTap:()=>console.log("'Nice location' marker tapped"),onCalloutTap:()=>console.log("'Nice location' marker callout tapped")}]};console.log("main-view-model:: doShow(): creating new MapboxView.");constmapView=newMapboxView();// Bind some event handlers onto our newly created map view.mapView.on('mapReady',(args :any)=>{console.log("main-view-model: onMapReady fired.");// this is an instance of class MapboxViewthis.mapboxView=args.map;// get a reference to the Mapbox API shim object so we can directly call its methods.this.mapbox=this.mapboxView.getMapboxApi();this.mapbox.setOnMapClickListener(point=>{console.log(`>> Map clicked:${JSON.stringify(point)}`);returntrue;});this.mapbox.setOnMapLongClickListener(point=>{console.log(`>> Map longpressed:${JSON.stringify(point)}`);returntrue;});this.mapbox.setOnScrollListener((point:LatLng)=>{// console.log(`>> Map scrolled`);});this.mapbox.setOnFlingListener(()=>{console.log(`>> Map flinged"`);}).catch(err=>console.log(err));});mapView.setConfig(settings);contentView.content=mapView;
All further examples assumemapbox has been required.Also, all functions support promises, but we're leaving out the.then() stuff for brevity where it doesn't add value.
mapbox.hide();
If you previously calledhide() you can quickly unhide the map,instead of redrawing it (which is a lot slower and you loose the viewport position, etc).
mapbox.unhide();
To clean up the map entirely you can destroy instead of hide it:
mapbox.destroy();
You can update the map style after you've loaded it.
With Mapbox Android SDK 6.1.x (used in plugin version 4.1.0) I've seen Android crash a few seconds after this has been used, so test this well and perhaps don't use it when in doubt.
mapbox.setMapStyle(mapbox.MapStyle.DARK);
import{MapboxMarker}from"nativescript-mapbox";constfirstMarker=<MapboxMarker>{//cast as a MapboxMarker to pick up helper functions such as update()id:2,// can be user in 'removeMarkers()'lat:52.3602160,// mandatorylng:4.8891680,// mandatorytitle:'One-line title here',// no popup unless setsubtitle:'Infamous subtitle!',// icon: 'res://cool_marker', // preferred way, otherwise use:icon:'http(s)://website/coolimage.png',// from the internet (see the note at the bottom of this readme), or:iconPath:'res/markers/home_marker.png',selected:true,// makes the callout show immediately when the marker is added (note: only 1 marker can be selected at a time)onTap:marker=>console.log("Marker tapped with title: '"+marker.title+"'"),onCalloutTap:marker=>alert("Marker callout tapped with title: '"+marker.title+"'")};mapbox.addMarkers([firstMarker,{// more markers..}])
Plugin version 4.2.0 added the option to update makers. Just callupdate on theMapboxMarker reference you created above.You can update the following properties (all but the icon really):
firstMarker.update({lat:52.3622160,lng:4.8911680,title:'One-line title here (UPDATE)',subtitle:'Updated subtitle',selected:true,// this will trigger the callout upon updateonTap:(marker:MapboxMarker)=>console.log(`UPDATED Marker tapped with title:${marker.title}`),onCalloutTap:(marker:MapboxMarker)=>alert(`UPDATED Marker callout tapped with title:${marker.title}`)})
You can either remove all markers by not passing in an argument,or remove specific marker id's (which you specified previously).
// remove all markersmapbox.removeMarkers();// remove specific markers by idmapbox.removeMarkers([1,2]);
If you want to for instance make the viewport contain all markers youcan set the bounds to the lat/lng of the outermost markers using this function.
mapbox.setViewport({bounds:{north:52.4820,east:5.1087,south:52.2581,west:4.6816},animated:true// default true})
mapbox.getViewport().then(function(result){console.log("Mapbox getViewport done, result: "+JSON.stringify(result));})
mapbox.setCenter({lat:52.3602160,// mandatorylng:4.8891680,// mandatoryanimated:false// default true})
Here the promise callback makes sense, so adding it to the example:
mapbox.getCenter().then(function(result){console.log("Mapbox getCenter done, result: "+JSON.stringify(result));},function(error){console.log("mapbox getCenter error: "+error);})
mapbox.setZoomLevel({level:6.5,// mandatory, 0-20animated:true// default true})
mapbox.getZoomLevel().then(function(result){console.log("Mapbox getZoomLevel done, result: "+JSON.stringify(result));},function(error){console.log("mapbox getZoomLevel error: "+error);})
// this is a boring triangle drawn near Amsterdam Central Stationmapbox.animateCamera({// this is where we animate totarget:{lat:52.3732160,lng:4.8941680},zoomLevel:17,// Androidaltitude:2000,// iOS (meters from the ground)bearing:270,// Where the camera is pointing, 0-360 (degrees)tilt:50,duration:5000// default 10000 (milliseconds)})
mapbox.setTilt({tilt:40,// default 30 (degrees angle)duration:4000// default 5000 (milliseconds)})
mapbox.getTilt().then(function(tilt){console.log("Current map tilt: "+tilt);})
If the user's location is shown on the map you can get their coordinates and speed:
mapbox.getUserLocation().then(function(userLocation){console.log("Current user location: "+userLocation.location.lat+", "+userLocation.location.lng);console.log("Current user speed: "+userLocation.speed);})
In case you're showing the user's location, you can have the map track the position.The map will continuously move along with the last known location.
mapbox.trackUser({mode:"FOLLOW_WITH_HEADING",// "NONE" | "FOLLOW" | "FOLLOW_WITH_HEADING" | "FOLLOW_WITH_COURSE"animated:true});
https://docs.mapbox.com/mapbox-gl-js/api/#map#addsource
Adds a vector to GeoJSON source to the map.
mapbox.addSource(id,{type:'vector',url:'url to source'});
-or-
mapbox.addSource(id,{'type':'geojson','data':{"type":"Feature","geometry":{"type":"LineString","coordinates":[[lng,lat],[lng,lat], .....]}}});
Remove a source by id
mapbox.removeSource(id);
NOTE: For version 5 the API for addLayer() has changed and is now a subset of the web-gl-js API.
https://docs.mapbox.com/mapbox-gl-js/style-spec/#layers
To add a line:
mapbox.addLayer({'id':someid,'type':'line','source':{'type':'geojson','data':{"type":"Feature","geometry":{"type":"LineString","coordinates":[[lng,lat],[lng,lat], .....]}}}},'layout':{'line-cap':'round','line-join':'round'},'paint':{'line-color':'#ed6498','line-width':5,'line-opacity':.8,'line-dash-array':[1,1,1,..]}});
To add a circle:
mapbox.addLayer({"id":someid,"type":'circle',"radius-meters":500,// FIXME: radius in meters used for in-circle click detection."source":{"type":'geojson',"data":{"type":"Feature","geometry":{"type":"Point","coordinates":[lng,lat]}}},"paint":{"circle-radius":{"stops":[[0,0],[20,8000]],"base":2},'circle-opacity':0.05,'circle-color':'#ed6498','circle-stroke-width':2,'circle-stroke-color':'#ed6498'}});
Source may be a geojson or vector source description or may bethe id of a source added using addSource()
Remove a layer added with addLayer() by id.
mapbox.removeLayer(id);
Dynamically add a point to a line.
mapbox.addLinePoint(<idoflinelayer>, lnglat )
where lnglat is an array of two points, a longitude and a latitude.
Draw a shape. Just connect the dots like we did as a toddler.
The first person to tweet a snowman drawn with this function gets a T-shirt.
// after adding this, scroll to Amsterdam to see a semi-transparent red squaremapbox.addPolygon({id:1,// optional, can be used in 'removePolygons'fillColor:newColor("red"),fillOpacity:0.7,// stroke-related properties are only effective on iOSstrokeColor:newColor("green"),strokeWidth:8,strokeOpacity:0.5,points:[{lat:52.3923633970718,lng:4.902648925781249},{lat:52.35421556258807,lng:4.9308013916015625},{lat:52.353796172573944,lng:4.8799896240234375},{lat:52.3864966440161,lng:4.8621368408203125},{lat:52.3923633970718,lng:4.902648925781249}]}).then(result=>console.log("Mapbox addPolygon done")).catch((error:string)=>console.log("mapbox addPolygon error: "+error));
You can either remove all polygons by not passing in an argument,or remove specific polygon id's (which you specified previously).
// remove all polygonsmapbox.removePolygons();// remove specific polygons by idmapbox.removePolygons([1,2]);
Deprecated. Use addLayer() instead.
Draw a polyline. Connect the points given as parameters.
// Draw a two segment line near Amsterdam Central Stationmapbox.addPolyline({id:1,// optional, can be used in 'removePolylines'color:'#336699',// Set the color of the line (default black)width:7,// Set the width of the line (default 5)opacity:0.6,//Transparency / alpha, ranging 0-1. Default fully opaque (1).points:[{'lat':52.3833160,// mandatory'lng':4.8991780// mandatory},{'lat':52.3834160,'lng':4.8991880},{'lat':52.3835160,'lng':4.8991980}]});
Deprecated. Use removeLayer() instead.
You can either remove all polylines by not passing in an argument,or remove specific polyline id's (which you specified previously).
// remove all polylinesmapbox.removePolylines();// remove specific polylines by idmapbox.removePolylines([1,2]);
Add a source that can be used byaddLayer. Note onlyvector type is currently supported.
mapbox.addSource(id:"terrain-source",// requiredtype:"vector",// supported types: vectorurl:"mapbox://mapbox.mapbox-terrain-v2");
Remove a source byid.
mapbox.removeSource("terrain-source");
Add a layer from a source to the map. Note onlycircle,fill andline types are currently supported.
mapbox.addLayer(id:"terrain-data",// requiredsource:"terrain-source",// id of sourcesourceLayer:"contour",// id of layer from sourcetype:"line",// supported types: circle, fill, linelineJoin:"round",lineCap:"round",lineColor:"#ff69b4",lineWidth:1,);
Remove a layer byid.
mapbox.removeLayer("terrain-data");
Add a listener to retrieve lat and lng of where the user taps the map (not a marker).
mapbox.setOnMapClickListener((point:LatLng)=>{console.log("Map clicked at latitude: "+point.lat+", longitude: "+point.lng);});
Add a listener to retrieve lat and lng of where the user longpresses the map (not a marker).
mapbox.setOnMapLongClickListener((point:LatLng)=>{console.log("Map longpressed at latitude: "+point.lat+", longitude: "+point.lng);});
Add a listener to retrieve lat and lng of where the user scrolls to on the map.
mapbox.setOnScrollListener((point?:LatLng)=>{console.log("Map scrolled to latitude: "+point.lat+", longitude: "+point.lng);});
For situations where you want the user to pre-load certain regions you can use these methods to create and remove offline regions.
Important read:the offline maps documentation by Mapbox.
This example downloads the region 'Amsterdam' on zoom levels 9, 10 and 11 for map style 'outdoors'.
mapbox.downloadOfflineRegion({accessToken:accessToken,// required for Android in case no map has been shown yetname:"Amsterdam",// this name can be used to delete the region laterstyle:mapbox.MapStyle.OUTDOORS,minZoom:9,maxZoom:11,bounds:{north:52.4820,east:5.1087,south:52.2581,west:4.6816},// this function is called many times during a download, so// use it to show an awesome progress bar!onProgress:function(progress){console.log("Download progress: "+JSON.stringify(progress));}}).then(function(){console.log("Offline region downloaded");},function(error){console.log("Download error: "+error);});
Grab the viewport with themapbox.getViewport() function and download it at various zoom levels:
// I spare you the error handling on this one..mapbox.getViewport().then(function(viewport){mapbox.downloadOfflineRegion({name:"LastViewport",// anything you like reallystyle:mapbox.MapStyle.LIGHT,minZoom:viewport.zoomLevel,maxZoom:viewport.zoomLevel+2,// higher zoom level is lower to the groundbounds:viewport.bounds,onProgress:function(progress){console.log("Download %: "+progress.percentage);}});});
To help you manage offline regions there's alistOfflineRegions function you can use. You can then fi. calldeleteOfflineRegion (see below) and pass in thename to remove any cached region(s) you like.
mapbox.listOfflineRegions({// required for Android in case no map has been shown yetaccessToken:accessToken}).then(function(regions){console.log(JSON.stringify(JSON.stringify(regions));},function(error){console.log("Error while listing offline regions: "+error);});
You can remove regions you've previously downloaded. Any region(s) matching thename param will be removed locally.
mapbox.deleteOfflineRegion({name:"Amsterdam"}).then(function(){console.log("Offline region deleted");},function(error){console.log("Error while deleting an offline region: "+error);});
On Android 6 you need to request permission to be able to show the user's position on the map at runtime when targeting API level 23+.Even if theuses-permission tag forACCESS_FINE_LOCATION is present inAndroidManifest.xml.
You don't need to do this with plugin version 2.4.0+ as permission is request when required while rendering the map. You're welcome :)
Note thathasFineLocationPermission will return true when:
- You're running this on iOS, or
- You're targeting an API level lower than 23, or
- You're using Android < 6, or
- You've already granted permission.
mapbox.hasFineLocationPermission().then(function(granted){// if this is 'false' you probably want to call 'requestFineLocationPermission' nowconsole.log("Has Location Permission? "+granted);});// if no permission was granted previously this will open a user consent screenmapbox.requestFineLocationPermission().then(function(){console.log("Location permission requested");});
Note that theshow function will also check for permission if you passed inshowUserLocation : true.If you didn't request permission before showing the map, and permission was needed, the plugin will ask the user permission while rendering the map.
If you specifyicon: 'http(s)://some-remote-image', then on iOS you'll need to whitelistthe domain. Google for iOS ATS for detailed options, but for a quick test you can add this toapp/App_Resources/iOS/Info.plist:
<key>NSAppTransportSecurity</key><dict> <key>NSAllowsArbitraryLoads</key> <true/></dict>
About
🗽 🗼 🗻 Native OpenGL powered Maps, by Mapbox
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.

