Pages

How to Integrate Mapbox GL JS Maps with an Ionic Application

Mapbox GL JS is a JavaScript library that uses WebGL to render interactive maps from vector tiles and Mapbox styles. 
Mapbox's GL JS allows us to add features like Tilt, Custom Map Styles, 3D Building's etc. 
In this tutorial I am going to walk you through how to integrate the Mapbox GL JS Maps into an Ionic application. Create a New Ionic Application 

 First things first, let’s create a new Ionic project. For this project I'm going to create an ionic blank project.
Run the Following Command to create a new ionic project
 ionic start Mapbox-Gl-maps blank 
After the Project is created, navigate to the project folder, in my case "Mapbox-Gl-maps" is the folder name. Since we want our app to work on Both ios and Android we should also add respective platform's to the ionic project.
Run the following commands to add the Android & iOS platforms

ionic platform add ios

ionic platform add android
Add Geolocation Plugin In this post, We are also going to Geolocate the users location on the map, so we need to install native Geolocation plugin. 
Although Geolocating user works perfectly on browser, it may not work as expected on devices.
Run the following commands to add Geolocation plugin.
 cordova plugin add cordova-plugin-geolocation 

Add required JS and Css files 

Open index.html file in your project. include the following Mapbox GL JS & Css files just before cordova.js file.

<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.32.1/mapbox-gl.js"></script>
    <link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.32.1/mapbox-gl.css" rel="stylesheet"></link>  
 
Create a Map in Your ionic Application Now we’re going to look at how to display map in our ionic application. To Display map on our ionic application, add the following code below ion-pane.
Copy and Paste the code given below
      <ion-header-bar class="bar-dark">
      <h1 class="title">MapBox Map</h1>
      </ion-header-bar>
      <ion-content scroll="false">
       <div id='map' style="width:{{mapwidth}}px; height:{{mapheight}}px"></div>
      </ion-content>

Now assigned it a controller in app.js file. Create controller in app.js with name "MapCtrl". This controller will be responsible for initialising the MapBox Map.
Add the following controller to your app.js file

.controller('MapCtrl', function($scope) {

})

 Now that we have created our controller, lets add the code to display map on our ionic application.
Add the following code to your MapCtrl controller in app.js file

    $scope.mapwidth = screen.width;
    $scope.mapheight = screen.height;

    var lat;
    var lng;
 
 // executes onSuccess Callback
    var onSuccess = function(position) {
                console.log('Latitude: '  + position.coords.latitude + '\n' +
                            'Longitude: ' + position.coords.longitude + '\n' +
                            'Accuracy: '  + position.coords.accuracy )
    lat =  position.coords.latitude;  
    lng =  position.coords.longitude; 
 
     // accessToken is provided by mapbox once you signup @ https://www.mapbox.com 
   
  mapboxgl.accessToken = '< Your mapbox gl js Access Token here >';
  
  var map = new mapboxgl.Map({
   container: 'map', // container id
   style: 'mapbox://styles/mapbox/streets-v9', //stylesheet location
   center: [lng, lat], // starting position
   zoom: 15,
   pitch: 45 // starting zoom
  });
  
 map.on('load', function () {
  // Code which is executed after the map is loaded
 }) 

    };
 
    // executes onError Callback
 
    function onError(error) {
        aconsole.log('code: '    + error.code    + '\n' +
                     'message: ' + error.message + '\n');
    }
 
     // to get currentposition
 
     navigator.geolocation.getCurrentPosition(onSuccess, onError);

if you run your code using "ionic serve" command, you will notice that Mapbox map is already functional and is visible on your app. 



Add a marker to the map 

Well Map is centered to our current location, but we actually don't know the exact location on the map without any indicator right !. 

 let's add a marker on the map, to indicate our location. markers position uses the same coordinates that are used to center the map.
Add the following code to your MapCtrl controller, just after you map's initialization code. in map.on('load') function.
// Beolow code Add's a layer showing the places
   map.addLayer({
     "id": "places",
     "type": "symbol",
     "source": {
   "type": "geojson",
   "data": {
    "type": "FeatureCollection",
    "features": [{
     "type": "Feature",
     "geometry": {
      "type": "Point",
      "coordinates": [lng, lat]
     },
     "properties": {
      "title": "My Location",
      "description": "This is My Location!",
      "icon": "monument"
     }
    }]
   }
     },
     "layout": {
   "icon-image": "{icon}-15",
   "text-field": "{title}",
   "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
   "text-offset": [0, 0.6],
   "text-anchor": "top"
     }
    });

Add a PopUp  to the map

Let's add a popup to the marker. we can do this by adding a click event to the map, when ever a click event is detected we will open a popup saying "This is My Location!".

Add the following code to your MapCtrl controller, just after you map.addLayer() code block.

  map.on('click', function (e) {
   console.log(e)
    var features = map.queryRenderedFeatures(e.point, { layers: ['places'] });
       if (!features.length) {
     return;
    }
   var popup = new mapboxgl.Popup()
    .setLngLat(features[0].geometry.coordinates)
    .setHTML(features[0].properties.description)
    .addTo(map);
    
  })



Now if you tap the marker you should see a little popup saying “This is My Location!”.

How to Display 3D Building on mapbox map?

If you want to view 3D building on mapbox map just add the below given code, inside map.on('load') function.


 map.addLayer({
        'id': '3d-buildings',
        'source': 'composite',
        'source-layer': 'building',
        'filter': ['==', 'extrude', 'true'],
        'type': 'fill-extrusion',
        'minzoom': 15,
        'paint': {
            'fill-extrusion-color': '#aaa',
            'fill-extrusion-height': {
                'type': 'identity',
                'property': 'height'
            },
            'fill-extrusion-base': {
                'type': 'identity',
                'property': 'min_height'
            },
            'fill-extrusion-opacity': .6
        }
    });



That's it guys, now you can view 3D buildings on your mapbox map .

Below is the full code of the controller that we just did, if you encounter any error's in the above process just copy and paste the below code on to your app.js file.

.controller('MapCtrl', function($scope) {

// executes onSuccess Callback
 $scope.mapwidth = screen.width;
 $scope.mapheight = screen.height;

    var lat;
    var lng;
    var onSuccess = function(position) {
                console.log('Latitude: '  + position.coords.latitude + '\n' +
                            'Longitude: ' + position.coords.longitude + '\n' +
                            'Accuracy: '  + position.coords.accuracy )
    lat =  position.coords.latitude;  
    lng =  position.coords.longitude; 
 
     // accessToken is provided by mapbox once you signup @ https://www.mapbox.com 
   
  mapboxgl.accessToken = '< Your mapbox gl js Access Token here >';
  var map = new mapboxgl.Map({
   container: 'map', // container id
   style: 'mapbox://styles/mapbox/streets-v9', //stylesheet location
   center: [lng, lat], // starting position
   zoom: 15,
   pitch: 45 // starting zoom
  });
  
 map.on('load', function () {
  map.addLayer({
     "id": "places",
     "type": "symbol",
     "source": {
   "type": "geojson",
   "data": {
    "type": "FeatureCollection",
    "features": [{
     "type": "Feature",
     "geometry": {
      "type": "Point",
      "coordinates": [lng, lat]
     },
     "properties": {
      "title": "My Location",
      "description": "This is My Location!",
      "icon": "monument"
     }
    }]
   }
     },
     "layout": {
   "icon-image": "{icon}-15",
   "text-field": "{title}",
   "text-font": ["Open Sans Semibold", "Arial Unicode MS Bold"],
   "text-offset": [0, 0.6],
   "text-anchor": "top"
     }
    });
    
  map.addLayer({
   'id': '3d-buildings',
   'source': 'composite',
   'source-layer': 'building',
   'filter': ['==', 'extrude', 'true'],
   'type': 'fill-extrusion',
   'minzoom': 15,
   'paint': {
    'fill-extrusion-color': '#aaa',
    'fill-extrusion-height': {
     'type': 'identity',
     'property': 'height'
    },
    'fill-extrusion-base': {
     'type': 'identity',
     'property': 'min_height'
    },
    'fill-extrusion-opacity': .6
   }
  });
     
  map.on('click', function (e) {
   console.log(e)
    var features = map.queryRenderedFeatures(e.point, { layers: ['places'] });
       if (!features.length) {
     return;
    }
   var popup = new mapboxgl.Popup()
    .setLngLat(features[0].geometry.coordinates)
    .setHTML(features[0].properties.description)
    .addTo(map);
    
  })  

 
 }) 

    };
 
    // executes onError Callback
 
    function onError(error) {
        aconsole.log('code: '    + error.code    + '\n' +
                     'message: ' + error.message + '\n');
    }
 
     // to get currentposition
 
     navigator.geolocation.getCurrentPosition(onSuccess, onError);

})

PS: Don't forget to add the mapbox Access Token, without which the map wont be displayed.

vinay kumar

Founder of Gowriter.Blogspot.com, Tech Enthusiast, Normal type of Person with passion toward's work.

6 comments:

Sasidhar said...

Dear Vinay,
Can you please post the entire code of this example. It will be of great help for all of us.

Sasidhar

vinay kumar said...

Hi Sasidhar,

Sorry for the late response, if you are still working on this code, i've updated the post with the full code. please take a look & thank's for visiting my blog.

Anonymous said...

Hi, thanks for this tuto. This might be beacause i'm new to Ionic and Angular, but i don't see where you bind your view to the controller.
I followed the steps but nothing is showing up.

vinay kumar said...

Hi, div tag containing id as map, is the place where the map is displayed. Can you post the error that you are getting on your console log.

Yeniz said...

Hi, my problem is partially solved. I can now display the map and add markers in my desktop browser (edge).
However when i run the app on my android device i have a blank screen where the map should be displayed.

Have you encountered this problem? How can i fix it?

Thanks

andrea valenzano said...

Hi,
I have the same problem when run in a device (Android and iOS).
I thinks that the problem is that webviewer used by cordova not used webgl.