Building a geolocation app using Google Maps API in Vanilla JavaScript
Tags: javascript, tutorial, webdev
Published: 2020-11-26 14:09:46

Recently I worked on this geolocation-based app that fetches and maps real-time availability of [London’s Santander Bikes](https://tfl.gov.uk/modes/cycling/santander-cycles) with [Navigator](https://developer.mozilla.org/en-US/docs/Web/API/Navigator), [Google Maps API](https://developers.google.com/maps/documentation/javascript/overview), [Transport For London API](https://api.tfl.gov.uk/). All in vanilla JavaScript.

💻 You can see mine working [here]( https://tfl-bikes.netlify.app/)💻 

I thought it would be good to share a step-by-step guide on how to build it. This could be easily replicated for your own city, providing the local authorities or the service you want to use have an API. A similar take would be fetching local shops or restaurants from the Google Places API, and getting reviews or any other data.



First of all, we want to breakdown our plan into small tasks, so here’s what we need to do:  

##Steps
####1. Get the users location from the browser 
####2. Render a Google map and create a request to Google Maps using the users location
####3. Create a request to Travel For London (TfL) for bike information
####4. Parse the Tfl API responses and add the data to the map 
####5. Retrieve specific info and create and InfoWindow
####6. Add bikepoint info and image elements to the InfoWindow
####7. Add custom markers





##1. Get the user's location from the browser 

In order for this app to be more relevant to a Londoner, we want to retrieve the user's location and show the bikes available nearby.
"Right, but how on earth do we do that?", you ask. 🧐

We will use the Navigator object for this. The Navigator object lives under the hood in your browser, and it allows scripts to query state and to register themselves to carry on some activities.
There's a lot of properties in the Navigator object, which you can read more about [here]( https://developer.mozilla.org/en-US/docs/Web/API/Navigator), but for this purpose we want to use Geolocation.

>The `Navigator.geolocation` read-only property returns a Geolocation object that gives Web content access to the location of the device. This allows a Web site or app to offer customised results based on the user's location.

Once we call `navigator.geolocation`, it will prompt the user to allow for their location to be shared. If you're on Google Chrome you will see this alert:

![user_your_location](https://dev-to-uploads.s3.amazonaws.com/i/5a1v5n86l1p3cg1h048g.png)
 
In Firefox, for example, you will likely have to change the geolocation sharing permissions in the settings.

This will be done on pageload so we can handle the success case (as in, getting the user's current position).

![01_Get_Users_Location](https://dev-to-uploads.s3.amazonaws.com/i/2saelfkl46sn7485u75w.png)
 
We take in `createMap` as parameter. This will be a function that we'll create in Step 2.
If sharing location was not allowed, we will get an error on the console.


##2. Render a Google map and create a request to Google Maps

For the next step, we want to render a Google map on our page which we'll wrap in a function.
You will have to sign up with Google Maps Platform and get an API key. [Here's how you get started.](https://developers.google.com/maps/documentation/javascript/get-api-key)

Once you have your API key, you'll have to include it in your Maps JavaScript API request as per the documentation. Include the Google `script` tag in your html file.

![02_render_google_map_center_on_location](https://dev-to-uploads.s3.amazonaws.com/i/ciw6ktala60qtcg3i4oc.png)

Then, we create a request to Google Maps using the user's location. The `position.coords` are retrieved from `navigator.geolocation.getCurrentPosition()` from Step 1.

`map` is just an id given to a `<div>` so we can use it as a selector. We want to center the map based in the current location, so we use `center: { lat: latitude, lng: longitude }` which store our `position.coords`. We also want to tweak the `zoom` property so it's more zoomed in than the default value.

Here's [more](https://developers.google.com/maps/documentation/javascript/geolocation) on geolocation using the Google Maps API, if you would like to try a different approach.

Within the `createMap` function we also want to invoke the `getBikeData()`, which we'll create in the next step.


###Destructuring objects
```
const { latitude, longitude } = position.coords;
```
If you've never came across this weird looking syntax this is called _destructuring_. This was a feature added to ES6 and you can read more about it [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment).
Destructuring on objects lets you bind variables to different properties of an object. You specify the property being bound, followed by the variable you are binding its value to.


##3. Create request to Transport for London API for bike information.

Now we'll write our `getBikeData()` function, where we'll create a fetch request to Transport for London API for real-time bike data.

We don't need an API key to fetch data from the TfL API, so we simply use the endpoint provided to retrieve bikepoint data. We'll receive the data in JSON. 

![03_tfl_getBikeData_Function](https://dev-to-uploads.s3.amazonaws.com/i/mbe9w03i1uhrbshjkdlj.png)

Once the fetch response is successful, we want to add our bike markers. We'll create a function for that shortly.

There's several types of data you can get from TfL, which you can access [here](https://api.tfl.gov.uk/).


##4. Parse TfL API response and add bike locations to map

![04_parseAPI_addlocationstomap](https://dev-to-uploads.s3.amazonaws.com/i/m9zvi7arwa68an1wa9e2.png)

We want to parse our TfL API response where we take in bikepoints as our function's parameter.

We'll have quite a few bikepoints to parse so we'll run a forEach loop on each of them. We want to store the `bikeLocation` as a variable, which will store each bikepoint's latitude and longitude.

Then, for each of them, we want to create a Google marker, so we'll use one of the Google's functions for that. Relevant documentation on markers [here](https://developers.google.com/maps/documentation/javascript/markers). The Google marker is in fact an object which has `position`, `map`, and `icon` as properties. Position will take an object with the bikepoint latitude and longitude. Map will refer to the map we've previously created. And lastly, icon refers to the marker image, which will come to on our last step.

Within our `addBikeMarkers` function, we also invoke `createBikeInfo()` with bikepoint and marker as parameters. You guessed it, we'll jump onto that now.

This is how your app should look like at this point, with gorgeous markers for each Santander bike point. Gorgeous!

![Screenshot 2020-11-11 at 09.09.16](https://dev-to-uploads.s3.amazonaws.com/i/9k89i63dpxbflvqgeyvb.png)
 

##5. Retrieve specific TfL info and create an information window for when a user selects a bike point

It's nice to have all the bikepoints mapped, but we need to provide more info to the user. What happens when you click on a marker? We want to display a window with all info such as  number of bikes available, number of spaces available and number of docks in each bikepoint.
 
![05_create_infoWindow](https://dev-to-uploads.s3.amazonaws.com/i/5ui4jeme6wo593l0ktox.png)

We create a function that retrieves and stores this data so we can then display it in a user-friendly format. This window will be prompted when each marker is clicked on.

You'll see in the JSON data, that the `Place` object has an `addtionalProperties` array which contains the `nbBikes`, `nbDocks` and `nbSpaces`. This actaully gives us real-time values, so we can display an accurate status of all bikepoints in London. 
If you notice that there's a mismatch in these numbers (i.e. `nbDocks - (nbBikes + nbSpaces) != 0`), this indicates broken docks.
In order to find the exact property we want (nbBikes, nbDocks, nbSpaces), we use the `find()` array method so it can find the exact key within that object.
I'm logging a few bits here to confirm that the data that is being pulled is correct.

Finally, we add an event listener to each `marker`. Please note, that this is in fact using a Google method that replaces `addEventListener`. In here, we use `addListener` instead to interact with the Google marker. More on events on the Google Maps API documentation [here](https://developers.google.com/maps/documentation/javascript/events).
We call the `createInfoWindowForMarker()` function (that we will create in the next step) to where we will pass in `marker`, `bikepoint` and `bikeInfo` as arguments.


##6. Add bikepoint info and image elements to the InfoWindow

![06_creates_infoWindow_for_marker](https://dev-to-uploads.s3.amazonaws.com/i/8fseuqn0uv1hwbnopjko.png)
 
Almost there! In this function we will want to create a InfoWindow to display our bikepoint data.

InfoWindow is a type of overlay provided by Google Maps. It displays content (usually text or images) in a popup window above the map, at a given location. You can read more on InfoWindows [here](https://developers.google.com/maps/documentation/javascript/infowindows)

First, we declare the `infoWindow` variable outside the function so it remains in global scope, which we'll assign with a new.google.maps.InfoWindow inside our function. This Google Maps function will take in an object literal which specifies the parameters for displaying the info window.
The one we will use is `content`, which is the equivalent to an `innerHtml`/`innerText` in JavaScript.
In here, we want to pass in html to the DOM, creating a div that holds an image and the data we fetched from the TfL API (the bikepoint name, number of bikes available, number of spaces available, number of docks and also the bike availability percentage). We calculate this percentage in a separate variable above.

You'll see that the first line in our code block here tells an existing open infoWindow to close. We only want to show one infoWindow at a time, so this guarantees that if there is already an infoWindow open this will be closed, so a new one can be displayed.

```
infoWindow.open(map, marker);
map.setCenter(marker.getPosition());
```

Lastly, we want to open a new infoWindow which will display the real-time bikepoint info. We pass in the `map` and `marker` as arguments so it's linked to the marker trigged by the user click. We also want to center the infoWindow in our map. Again, we use `setCenter` which is a built-in method that we can use with the Google Maps map, which then takes `getPosition()` chained to `marker`. `getPosition()` is a Google Maps method associated to `marker`. If you'd like to learn more on Google Maps map and marker methods, go [here](https://developers.google.com/maps/documentation/javascript/reference).

Et voila! What a beaut.

![Screenshot 2020-11-26 at 10.53.58](https://dev-to-uploads.s3.amazonaws.com/i/iz1njapqc7hszd22ch8w.png)
 

##7. Add custom markers

![Screenshot 2020-11-26 at 13.20.03](https://dev-to-uploads.s3.amazonaws.com/i/if0s2t0wmvzzbp0kwabj.png)
 
This is entirely optional as we already have a fully-functioning geolocation based app that tells us the availability of public-use bikes in London. 🤩
 
For our final step, we just want to give it a little personal touch and add our own custom marker images.

![07_icon_base](https://dev-to-uploads.s3.amazonaws.com/i/go8dqln2k9ec238tte9c.png) 

Remember in Step 4 when we created our marker? One of the properties the marker object takes is `icon`. The `google.maps.Icon` interface is a structure that represents a Marker icon image. There's quite a few properties associated to `icon`, you can learn more on that [here](https://developers.google.com/maps/documentation/javascript/reference/marker#Icon).

For our InfoWindow we will use `url` (pulling an image file of your choice), `scaledSize` (instantly scaling the original image to the desired size), and `origin` and `anchor` (which will position the marker image in correspondence to the location of the marker on the map).

There we have it, a geolocation-driven app using Navigator, Google Maps API and fetching data from the Transport for London bikes API.

![Screenshot 2020-11-11 at 11.36.24](https://dev-to-uploads.s3.amazonaws.com/i/1j94kfbykvslgej6bndw.png)



-

_This is my first ever technical blogpost so would love to know if you found this helpful in any of your projects using the Google Maps API! Your constructive feedback is appreciated._