(this article originally appeared on Hackernoon and was written by Edoardo
Sometimes you need to act fast!
Considering the amount of data this type of requirement will generate, I set out to create an app that would help record this info and visualise it using a heatmap. Heatmaps are a great tool to visualise where people are concentrating while maintaining the information anonymous.
Knowing which are the places where a lot of people are gathering is very important in the current COVID-19 outbreak, as one of the strategies to fight it, is to avoid such situations.
Authorities could use this tool to monitor and potentially act on areas of high concentration. Even more importantly, it could be used preventively by citizens. A publicly accessible heatmap could guide people in choosing their routes or places to go to (example: preferring one shop to another) in order to avoid hotspots.
Heatmap visualisation of anonymous data stored in Stryke representing journeys and points where crowds gathered.
TL;DR;
We will create an app that displays the journeys people took over a specific period of time on a heatmap. The information is entered anonymously by users through a form (or an API call) where they just need to provide the start and destination of their journeys.
In this article I will explain how I put together this project.
Feel free to use my version or create one of your own. I am happy if this can help anybody so do not hesitate to share it or use it in your community.
The Idea
I needed to go to the supermarket.
So I went to fill in the online form provided by the authorities when breaking the COVID-19 confinement. There and then I realised that it would be pretty straightforward to create a useful visualisation of how people are moving and where they are gathering if we could send this data to an app every time a person filled in this form. With such a tool I could decide easily which supermarket to go to: it would allow me to check which of my neighbouring shops is the least busy, before even leaving the house.
A heatmap would provide the perfect visualisation for this data.
With that in mind we can formulate the following requirements.
- Data submission should be done through a very simple form (2 fields) or API request (so that it could be called from existing pages)
- Data submitted should be anonymous
- The format in which the data is stored should be efficient for display but also understandable by a person
- The data should be easily accessible and available to export
- The heatmap should display data for a given timeframe
- The heatmap should be in a dedicated page
The Architecture
I want this solution to be as simple as possible. Here is what we need based on our requirements:
- A back end to store data, accept new submissions and retrieve data with a criteria via an API.
- A front end to visualise data in a heatmap and to allow people to submit new data.
- A Mapping API capable to retrieve locations, calculate routes and draw visualisations on a map.
Stryke is a great platform to implement a project like this as it is very quick to setup the following features:
Standard Stryke user interface for our app. Great for back office work.
On the front end side of things we will develop two simple pages:
- A page that holds the heatmap
- A second page that contains the data entry form
The Back End — Stryke
In this section we will go over how to: create an app in Stryke, define the entity that will hold our data, create the API that will be called to create a new route and to retrieve routes.
Important Note
We will go through all the steps to create a Stryke app from scratch. You can choose to do the same or simply import the app from the export file you can find here.
Create an App
From the Stryke dashboard let’s create our “COVID-19 Heatmap app” (choose a unique name for your new app).
Entity
We want this app to store routes in a Database. In order to achieve that, we need to create an Entity in Stryke (which will be the table in the DB). Once your app is created, from your app’s dashboard click on “New” under the entity section.
For each route generated by a user, we will store:
- The starting point (latitude and longitude)
- The destination point (latitude and longitude)
- The full path of the route between start and destination
- A descriptive name for this route
_jv{F_zhLp@`AHLHM~CsEfCqDl@y@^h@RDAL?^Hb@RhGtElBtAvAdARWNQCe@RRR[^e@fBgCHMHLvC|DzBdDnFjIvN|Sf@r@~HhLpEvGzG~JfJvMfA|Al@}@lAmBj@eA`@g@`@SzBiD
Sample encoded route
Since most of the fields in a route record are not very easy to read by a person, we will add a descriptive name. This name will be put together when creating the route and will contain the transport type and the full address of the start and end points.
walking from: Carrer de Mallorca, 481, 08013 Barcelona, Spain to: Rambla de Catalunya, 2, 08007 Barcelona, Spain
Sample route name
The API
Now that we have an entity to store routes, we want to be able to submit and retrieve them from clients.
[GET] https://api.stryke.io/v0/{appName}/data?entityName=route
Example use of the standard Stryke API
However, in our case we want to execute some additional logic when instructed to create or retrieve routes. When a route is created, we want to calculate the path of the route from the start and end points. Additionally, when retrieving routes we want to filter out data with a certain.
[POST] https://api.stryke.io/v0/{appName}/action/submitRoute
{
"start_lat": 41.315296,
"start_lng": 2.0133208,
"end_lat": 41.4134488,
"end_lng": 2.0182425,
"routeType": "driving"
}
Submit route request with sample payload
“Submit Route” Action
We want users to have to enter as little data as possible when submitting their journey, namely just the starting point and end point (and optionally the transport type: walking, driving, etc).
The action will first retrieve the start and end points, and method of transport from the request’s payload:
const payload = stryke.data.requestData;
const startPoint = `${payload.start_lat},${payload.start_lng}`;
const endPoint = `${payload.end_lat},${payload.end_lng}`;
const routeType = payload.routeType ? payload.routeType : 'walking';
Then it will call the Google API to calculate a route:
const url = `https://maps.googleapis.com/maps/api/directions/json?origin=${startPoint}&destination=${endPoint}&key=${apiKey}&mode=${routeType}`;
const response = await axios.get(url);
Finally, it will store the route details in a new route record in Stryke
const selectedRoute = response.data.routes[0];
const routeLegs = selectedRoute.legs;
const route = {
path: selectedRoute.overview_polyline.points,
start_lat: routeLegs[0].start_location.lat,
start_lng: routeLegs[0].start_location.lng,
end_lat: routeLegs[routeLegs.length-1].end_location.lat,
end_lng: routeLegs[routeLegs.length-1].end_location.lng,
routeName: `${routeType} from: ${routeLegs[0].start_address} to: ${routeLegs[routeLegs.length-1].end_address}`
}
await stryke.create('route', route);
“Get Routes” Action
This action will retrieve routes that match a certain criteria. It will retrieve routes within a specific time period. We also want to be able to easily enhance this criteria in the future. To achieve this, we will create another custom action available through the API which will query data and only return the relevant records.
const DATA_WINDOW_DAYS = 7;
const startDate = moment().add(-DATA_WINDOW_DAYS, 'days');
const routes = await stryke.find(`{
Route ( filter: { created : { gt : "${startDate.toISOString()}" }}
) {
start_lat, start_lng, end_lat, end_lng, path
}
}`);
The Front End — Glitch
We will develop both pages using vanilla HTML+JS+CSS without using any infrastructural framework. The pages are simple enough to be developed without the aid of a framework. This has two additional advantages: code is easy to integrate in existing pages, not using a specific framework makes it easy to illustrate the point without getting into proprietary stuff.
The Heatmap
My objective with the page was to draw the routes people took on a map. We will do this by using a heatmap to highlight segments and places of higher traffic.
Instead of doing that, we will follow an approach that still uses the heatmap API to highlight key points on the map, in conjunction with drawing simple polylines to represent the segments of the routes.
The key points along the route are the start and end points. These are conceptually places where people would stay for some time. It makes sense to still draw these using the heatmap API, so that places of gathering are highlighted with both intensity and colour.
As mentioned before, the routes are stored as encoded polylines. In order to draw them we need to convert the encoded polyline into an array of points. Google provides a useful utility that makes this task a one-liner.
// decode the polyline
const polyObj = google.maps.geometry.encoding.decodePath(route.path);
// define the look of the polyline
var path = new google.maps.Polyline({
path: polyObj,
geodesic: true,
strokeColor: '#8ADE42',
strokeOpacity: 0.3,
strokeWeight: 7
});
// draw the polyline on the map
path.setMap(map);
By drawing the lines with a low opacity value, we can achieve a heatmap-like effect, where segments that are drawn fewer times are more transparent, while overlapping segments show bolder.
Route Input — Google Places
Submitting a route should be something really fast for users.
While the current location option retrieves the latitude and longitude of the current position provided by the browser.
navigator.geolocation.getCurrentPosition(function(position) {
routeDetails.start_lat = position.coords.latitude;
routeDetails.start_lng = position.coords.longitude;
document.getElementById("start").value = 'Current location';
});
Live Demo
You can see a live demo of what we have discussed so far, here:
Conclusion
In this article we saw how it is possible to develop a fully functional application very quickly if we leverage the right tools.
The solution we developed can definitely be enhanced. For example, we could allow the used to control the time window for which we retrieve data, retrieve only routes within the currently visible window of the map, or use different colours when drawing overlapping routes to highlight intensity.
However, what we have here is a good functional foundation. The heatmap can show where the places of high concentration are and as a result help guide decisions. Data is stored anonymously and both the data input (submitting routes) and visualisation can work as standalone tools or be easily integrated into other pages.
If you think that your community could use a tool like this, feel free to implement it and use it. I would be very happy to hear about it!
You must log in to post a comment.