Make a running tracker with Geolocation API
Release the power of your mobile phone with Web API and Javascript
Location service is a crucial capability of mobile devices. While enjoying all the advantages like direction service, checking the nearest inventory during online shopping, I am always concerned about how much and how detailed my data is collected. Using a VPN or turning off location service is insufficient to completely protect our identity and cause lots of hassle.
Today we will explore how to use the Web API to access the geolocation and get rid of being tracked by tech providers.
Long story short, let’s watch our final product. This demo was running in Safari on iPhone X. Or if you can’t wait, try it on your phone here. 👈
If you can’t load the app, please check out the browser compatibility here.
Table of Content
- How to get geolocation
- The tracking formula
- Map view
- Map tile
- Update map
- Start/ pause button
- Log viewer
- Wiring up components
- Roundup
Real-time geolocation is the meat of the app. We will first learn the orchestration of the bits and bytes. Next, we will explore how to make practical use by playing around with the configuration.
A map view is the core presentation of the app. We will go through the setup of the map, drawing the tracked path and the current location.
To ease the experiment, we will build a real-time log viewer to make a more profound sense of the mechanics.
Lastly, we will build an event-based mechanism to glue up parts for the sake of performance and maintainability.
How to get geolocation?
We will leverage the Geolocation.watchPosition()
API to request GPS data. This function is implemented as an observer pattern. When watchPosition()
has executed, it will keep listening to a new event. We receive the event in the first argument, i.e. success
. If the API fails to locate the coordinate, it calls the second argument, error
. Both success
and error
are expected as a callback function to handle the individual situation.
If the browser supports geolocation API [line 2], we will start watchPosition()
by passing arguments success
, error
, and trackOptions
. We will discuss trackOptions
in a moment.
The tracking formula
It is a tradeoff between the sampling frequency and data accuracy. By default, it allows an infinity response time to get precise data. This setting favour application required high precision and latency is not a priority. A runner would expect a new coordinate to be recorded at a sensible frequency in our running tracker, e.g. every 2–5 seconds. A lower precision of data is acceptable as we care about the entire path rather than a single point. Hence, we dedicatedly configured trackOptions
to have frequency over accuracy as a preference.
The trackOptions
comprise parameters enableHighAccuracy
, maximumAge
, and timeout
.
enableHighAccuracy
is a boolean value to switch the modes between more accurate and use more power
and less accurate and use less power
. We will enable it in the tutorial as power consumption is not our primary concern.
timeout
determines the frequency to obtain a new position. The default value of timeout
is infinity, meaning it will return when the device successfully get the new coordinate. We will override this value to 5 seconds in our case to experience an eagerly updated path and distance meter.
If a new coordinate is not available when it reaches the timeout, it will use the cached value. Parameter maximumAge
guarantees the coordinate is not too outdated. If the cached value is older than the maximumAge
, it will look for a new reading. In our case, we use 30 seconds as the maximumAge
to keep the user experience smooth.
Map view
To stay away from the technologies designed to collect geolocation data and user identity, I used an open-source library leaflet.js in this project. Leaflet.js generate map view in browsers, with layers of geographical information received from the GPS chips in mobile phones. No geolocation data is being sent to any backend server.
We will create a full-screen map view [line 6], import leaflet.css
[line 9] and leaflet.js
[line 16], as well as our custom logic tracker.js
[line 30] and tracker.css
[line 22]. Then, a <div>
specified with id='tracker'
is added [line 28] as a placeholder for the tracker.
When the app (literally the URL) is loaded, users will see a landing page that shows the default map. I will use the London centre in the tutorial, but you might change to wherever you want. The L
object is the Leaflet functions entrance. We can associate the view with the div with the id tracker
we’ve just defined. Next, we locate the focus to the London centre and pass a zoom level of 13, showing fewer details but broader coverage.
Map tile
To display a geographical region on a map, we need a map provider.
We will use Mapbox as it offers a free tier service for small volume use. To use it,
- register a Mapbox account,
- create an API_KEY with scope to the URLs of the website.
- copy the code followed and replace
YOUR_API_KEY
with yours.
Update map
When a new geolocation event pop out, we will repeat three steps:
- extend the path segment to the new position
- relocate the current marker
- refresh the distance meter
To make sure the steps happen in sequence and for the sake of Clean Code, we organise the three steps as a function chain using Promise
.
Draw new Segment
To initialise the first path segment, beware of passing an array of latlng
array to L.polyline()
[line 8]. Next, we will pin the default London map view at the first coordinate we detect, and zoom in to level 15 by map.setView()
[line 15]. Then we use map.fitBounds()
to adjust to a comfortable view [line 16].
Refresh distance meter
The meter accumulates the distance of segments and updates the <div>
with id distance-box
. We will base on the formula provided by geoDatasource.com.
Start/ pause button
We will create a switch to start the tracking if users are ready to start the trip. The watchPosition()
start the surveillance until the web page is closed. If a user wants to take a break and not plot the locations on the map, he/ she can switch it off.
Log viewer
When I started working on this project, a pretty much time was in testing, where I travelled around the town and bought it along with my jogging. I created a log viewer using a semi-transparent overlay effect for trouble-shooting and configuration tuning. I keep this feature as it looks fantastic, and it will be helpful when we extend more functions.
Wiring up components
We’ve got the success
callback function that will be triggered when geolocation is received. We also have the updateMap
function that manages the graphical work on the map. It is the time to glue up both.
The most straightforward way is to call updateMap
in success
function. However, there are two drawbacks. First, in a multi-tasking browser environment, longer function chains are easier to suffer by being less responsive. Second, it is less flexible to change in the sense of maintenance.
Therefore, we are going to decouple it by adopting an event-driven manner.
Publisher
The success
callback function acts as a publisher to dispatchEvent()
[line 22]. The publisher is responsible for placing the event in a queue served by somebody, but it doesn’t care who it is. Hence the success
function is lightweight and responsive.
Subscriber
The subscriber, attached to the <div>
with id tracker
, serves the queue by sending the very first event to updateMap()
[line 26].
The beauty of this approach is to distribute loading to the queue and free both the success
and updateMap
function from overloading.
Are you excited to go jogging? Let’s wrap up before you leave the door.
Roundup
Today we have walked through a basic but complete solution to build a running tracker web app working in browsers. Although the purpose is more on exploring the Web API, we enjoy the benefits right away by getting rid of the tracking by the cloud providers, using a map in real-time without exposing personal identities, and most importantly, it is free and fun.
The Web Geolocation API is indeed a great place to start with if you want to turn your mobile phones into IoT devices at no cost.
Most popular browsers widely support the web geolocation API on Android and iOS, which is merit over native SDK if we deal with geographical problems. The downside is that only latitude and longitude are available, although other properties such as direction and speed are defined in the interface.
It is impressive that the API work with low/ no Internet connection when I tried to turn off mobile data during the tests. However, it is limited by real-time map API that failed to update the map tile when my location was outside the current tile. It will be exciting to explore further if we replace the map API with an offline map solution.
Thank you for reading ❤️. I hope you enjoy this sharing.
Demo 🏃
If you are interested in my other article, please visit my blogs on Medium.