Polyline Sorcery With React Native

I owe my first 6 months of college attendance to Google Maps. You could say, I would not be where I am today if that location marker and the blue path to my destination had not got along so well. I also would not be where I am right now. It’s just a dot and a line though, what’s the big deal? And that’s exactly right; it isn’t a big deal, but that’s all thanks to the nice guys at Google. Their algorithms are out there figuring out the fastest routes to drive, walk, and Heely (RIP) to your destination. It’s up to us to figure how best to leverage this in our apps.

There are many ways to render a route on Google Maps. All you really need is a little bit of HTML knowledge (you will be using script tags though), and you’re on your way using the Google Maps Direction Service. But I wanted to recreate the same mobile experience that guides me to 3 AM burritos every Saturday. My weapon of choice: React Native (If You Don’t Know, Now You Know). I’ll trust you to learn the basics, and if you want to try it out Expo is a great tool to see your app come to life.


The Map Component:

I totally would love to figure out how to implement Google Maps as a React Native component but baby steps here. The first baby step: AirBnB’s MapView Component. [Tl;dr : It’s a wrapper that took React Native’s MapView component and augmented it with so many options and optimisations that the original component is now deprecated.]

//In Your Terminal (Yes, I Know You Already Know This)
npm install --save react-native-maps
//React Component (Apple Map on iOS, Google Map on Android)
import MapView from 'react-native-maps'

At this point you should be able to literally drop the<Mapview /> component into your class’ render function and have a functional map (although you might want to look into the options to tweak the appearance or focus).


Polylines, Finally

We are finally ready to talk about polylines. Simply put, a polyline is just a mash of many smaller line segments. These line segments use latitude & longitude values to plot parts of your path. Put em all together, and you have your route! The Google Maps API helps us out with the lat/lng values, so go ahead and grab an API key from their developers site. A simple call now lets us get all the information we need to plot our polyline, and it looks something like this:

https://maps.googleapis.com/maps/api/directions/json?origin=40.71855466,-73.98899738&destination=40.72867347,-74.00473773&mode=walking&key=[YOUR_API_KEY_HERE]

Go ahead and input that in your browser to see what the result looks like. It’s an object that gives us information for a walking route (note the walking option in the URL; go on, mess around). Use what you’d like (the place_id lets you access a lot more information about a place using the Google Places service). What we (I) care about here is the “overview_polyline” property, which gives us a (slightly modified) base64 encoded string. Crack that code and you’re magically left with an array of lat/lng objects that make up your line segments and subsequently your polyline. I do encourage checking out base64 encoding/decoding, as it is a more stable way to get data across a network using a string of common characters.

Here’s a visual of your points, segments, and polyline:

“Ooooh Aaaaah” — Larry Page

Enough Talk

Here’s straight up code to get your polylines going. Note: you can definitely do this all on the front end, but don’t. Smartphone processors around the world will thank you.

React:

import React, { Component } from 'react';
import { MapView } from 'expo';
import { getDirections } from '../redux'; //next section, patience
class Map extends Component {
constructor(props) {
super(props)
this.state = {
//you want to locally store your start location and destination, and your polyline coordinates
}
}
 componentDidMount() {
//use your current location as your starting point, if you'd like. I am.
navigator.geolocation.getCurrentPosition((res, rej) => {
//you will get a res.coords property
res ? this.setState({ ...etc }): console.log(rej);
});
}
onButtonPress(){
let { startLocation, destination } = this.state;
getDirectionsToBar(startLocation, destination) //lat-lng objects
.then(res=> this.setState({...set your coordinates})
.catch(er => console.log(er))
}
render(){
//Make sure you set your destination (using markers or a dropdown or however you want the user to set it) and create a button
//Within your MapView
{ this.state.coordinates &&
<MapView.Polyline
coordinates={this.state.coordinates}
strokeWidth={4}
strokeColor="rgba(255,140,0,0.8)"/>
}
}

Redux:

import axios from 'axios';
export function getDirectionsToBar(startLoc, destLoc){
return axios.post('YOUR_ROUTE', { startLocation, destination })
.then(res => { return res.data })
.catch(er=>console.log(er))
}

Express (Your API):

//I'll use a router so you cant mount this code on your api path or wherever else you'd like
const router = require('express').Router();
//axios helps us make calls to the Google Maps Api
const axios = require('axios');
//mapbox gives us a great polyline tool that does the decoding for us. sorry I sent you down the base64 rabbithole. But also, you're welcome.
const Polyline = require('@mapbox/polyline');
module.exports = router;
router.post('/', (req, res, next) => {
let { startLocation, destination } = req.body
  //remember this url? you can do an async await/fetch too
  axios.get(`https://maps.googleapis.com/maps/api/directions/json?origin=${startLocation.latitude},${startLocation.longitude}&destination=${destination.latitude},${destination.longitude}&mode=walking&key=YOUR_API_KEY`)
.then(result=> result.data)
.then(result=> {
let array = Polyline.decode(result.routes[0].overview_polyline.points);
//your base64 string is now an array of lat/lng objects
    let coordinates = array.map((point) => {
return {
latitude :point[0],
longitude :point[1]
}
})
res.send(coordinates)
}).catch(er=>console.log(er.message))
})

Houston, We Have A Polyline

Coolest Polyline On The Block

And that’s about it. You want to think about things like using the distance and duration Google gives you, and giving the user the option of cancelling navigation by clearing your state and adding conditionals. But that wasn’t so bad, and now you can find your own way to class!