This is the 8th post in our tutorial series created by getstream.io. The final result is your own feature-rich, scalable social network app built with React and Redux! Visit getstream.io/cabin for an overview of all the tutorials, as well as a live demo. The source code can be found on the Stream GitHub repository for Cabin, and all blog posts can be found at their respective links below:

Introduction

Foursquare, Evernote, Instacart, Pinterest, GitHub, and Etsy have something in common – their maps are powered by Mapbox.

Mapbox provides a number of incredible services that are easy to integrate with your application, from Maps and Directions to Geocoding, and even Satellite Imagery. For Cabin we will be using two of their services: displaying custom maps and geocoding user provided locations. We really like using Mapbox because of their dedication to making developer tools intuitive. In addition, Mapbox has Open Source Components, which makes them a great fit for our integration. After this tutorial you’ll have the following map up and running:

Getting Started

Step 1:

Head over to the Mapbox Studio and sign up for a free account. Next up, we’re going to be incorporating a map into our app. A style is a document that defines the visual appearance of a map. More here.

Step 2:

In Mapbox Studio, click on Styles.

Step 3:

Select your template option, and click “Create”.

Style URL

Next up we need to get the Style URL, which we will use in our client-side code and API.

Step 1:

Click on your published style as shown below – and then click “Share & Use”.

Step 2:

Get your Style URL, which you will use in your JavaScript:

Step 3:

Go back to the Home page in Studio – and get your access token from the sidebar. That should be enough work in the Mapbox Studio to get started! Now it’s time to implement Mapbox in our code...

Client Side

So, in our Cabin app, we have the functionality to click on a post and visualize its location. This is where our the Mapbox JavaScript library comes into play: Mapbox GL JS is a JavaScript library that uses WebGL to render interactive maps from vector tiles and Mapbox GL styles. It is part of the Mapbox GL ecosystem, which includes Mapbox Mobile, a compatible renderer written in C++ with bindings for desktop and mobile platforms.

Step 1:

Let’s add the library in our project in /app/views/index.ejs :

//api.tiles.mapbox.com/mapbox-gl-js/v0.17.0/mapbox-gl.js

Step 2:

Next, we can add our access token to our env.sh file: From the Mapbox dashboard, head over to Account (bottom left), and then click on “Access Token” on the top right corner of your screen. Here you will be able to generate a new token for use.

Now that we have our token, replace the default value in our env.sh file with the actual token:

export MAPBOX_ACCESS_TOKEN=VALUE

Restart the app and make sure to run Webpack:

cd /app source ../env.sh; webpack --watch --progress

Note: The watch and progress flags are great for development. As you might guess, watch keeps an eye on the filesystem and automatically rebuilds your application when you make a change. Progress is a nice feature that keeps you up to date on the status of your build, which can be nice for apps that become very large (like Cabin).

Step 3:

Open /app/modules/routes/Location/Location.js . The loadMapboxMapmethod component is used to render our map. As can be seen below:

loadMapboxMap = (lng, lat, name) => { mapboxgl.accessToken = config.mapbox.accessToken; let map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/nickatstream/cinj7vvpf000ib7mbzpyhkw38', center: [lng, lat], zoom: 9, }); map.on('load', function() { map.addSource('markers', { type: 'geojson', data: { type: 'FeatureCollection', features: [ { type: 'Feature', geometry: { type: 'Point', coordinates: [lng, lat], }, properties: { title: name, 'marker-symbol': 'default_marker', }, }, ], }, }); map.addLayer({ id: 'markers', type: 'symbol', source: 'markers', layout: { 'icon-image': 'default_marker', 'text-field': name, 'text-font': [ 'Open Sans Semibold', 'Arial Unicode MS Bold', ], 'text-offset': [0, 0.6], 'text-anchor': 'top', }, }); }); };

For the most part, our map functionality is handled solely by JSX inside of our render.

Server Side

When we upload a glorious photo of a cabin to our app, we need a way to geocode the location the user has entered in the freeform text box. No worries, Mapbox has us covered. Setting up the geocoding functionality is easy. Let's install the library via npm:

npm install --save mapbox-geocoding

_Note: You’ll need to source and restart the API since we added an updated token to our env.sh file by hitting control + c (to stop the api), followed by MARKDOWN_HASHcb1433aa08826cde46013cb650ea3c6dMARKDOWNHASH (to start the api).

Step 4:

Next, open up /api/routes/uploads.js and head down to around line ~261. Here, we are creating a POST method to /uploads that we will use to upload images to our server. Sounds like a lot, right? It’s actually simple. Here’s the code:

// use mapbox to get latitude and longitude function(cb) { // initialize mapbox client geo.setAccessToken(config.mapbox.accessToken); // get location data geo.geocode('mapbox.places', data.location, function( err, location, ) { if (err) { cb(err); } else { // if the location was found if (location.features.length) { // extract coorindates var coords = location.features[0].geometry.coordinates; if (coords.length) { // assign to latitude and longitude in data object data.longitude = coords[0]; data.latitude = coords[1]; } } cb(null); } }); }

Note: We’re using the popular NPM module, Async, to handle our waterfall approach of actions. You’re welcome to use any other promise style library; however, we felt that Async was the best for our scenario. As you can see, we are passing a plain text string (data.location) to the .geocode method – and, in return, we are getting a longitude and latitude value. More documentation on the Geocoding API can be found here. And that’s it! (Really, it’s that easy to get Mapbox implemented in your application.)

Additional Features

Mapbox is the superior product when it comes to mapping and geocoding. They bolster some great features and services – all with open source libraries and SDKs that make their products easy to implement. While the Mapbox functions that we use for Cabin are all free, Mapbox also has an impressive offering of paid services. It would be well worth your time to check out a few of their other services, like:

Conclusion

We admire the way Mapbox has created a product that is both powerful AND intuitive. It is the perfect solution to handle custom themed maps and geo locations. In the next post, we’ll cover how we’re using Digital Ocean to power the hosting for Cabin. Add your email on cabin.getstream.io or follow @getstream_io on Twitter to stay up to date about the latest Cabin tutorials. This tutorial series is created by getstream.io. Try the 5 min interactive tutorial to learn how Stream works.