I Built A Low-Code App To Monitor Crowds During the COVID-19 Outbreak

Written by edoStryke | Published 2020/04/16
Tech Story Tags: stryke | covid-19 | heatmap | google-maps | javascript | cloud-based-apps | low-code | hackernoon-top-story

TLDR I Built A Low-Code App To Monitor Crowds During the COVID-19 Outbreak. I Built a low-code app to monitor crowds using Stryke and Glitch. The app 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. A publicly accessible heatmap could guide people in choosing their routes or places to go to (example: preferring one shop to another)via the TL;DR App

Learn how I created an app to help with the COVID-19 outbreak in less than a day using Stryke and Glitch.

Sometimes you need to act fast!
We are currently facing some challenging times with the COVID-19 outbreak. In Barcelona we are confined to our homes, and are encouraged to fill in a self-justification form to show to the authorities in case we are stopped on the street.
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.
Disclaimer: In this project I make use of a platform called Stryke. I work for Stryke so my opinion can be biased. There are other platforms with which you could develop a similar solution. However, I feel that Stryke is a really good fit for this solution based on the features it provides and how it allows to get something functional very quickly.

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.
I wanted to have something working quickly so I resorted to 2 platforms that aim to speed up the development of cloud apps: Stryke and Glitch.
In this article I will explain how I put together this project.
All code is available here: https://github.com/strykeio/covid-heatmap
You can see a live demo here: https://covidheatmap.glitch.me/
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.
The “time to final solution” is key in this project. We will use two platforms that allow reaching a working solution very quickly: Stryke and Glitch. For all tasks related with mapping we will use the Google Maps APIs.
We will create an app in Stryke that will serve as the backend where data is persisted and can be created and retrieved via an API. Creating an app in Stryke also automatically creates a user interface where we can check and manage the data if necessary.
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
We will use Glitch to create these simple HTML pages and host them. Glitch is a great tool to put things together quickly and easily.
Data entry (finding places easily and getting their coordinates), route calculation, as well as the heatmap visualisation require working with geo locations and maps. The Google Maps Platform provides a host of very useful APIs to achieve these tasks. To achieve all of the above we will use the following APIs:

The Back End — Stryke

Stryke is a platform for developers to create cloud applications easily. It speeds up development by providing many infrastructural features and an easy environment.
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

First of all, let’s login to Stryke to create a new app for our project. If you do not have a Stryke user, you can create one by signing up to the platform.
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
In order to make things efficient we will store the route’s path as an encoded polyline. This is a format created by google that allows storing data for many points in an encoded string. The response from the directions API contains an encoded polyline for the route called overview_polyline. It is very straightforward to draw encoded polylines, we will see how to do that when discussing the heatmap page.
_jv{F_zhLp@`AHLHM~CsEfCqDl@y@^h@R\DAL?^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
You can see the JSON that defines this entity here.

The API

Now that we have an entity to store routes, we want to be able to submit and retrieve them from clients.
We could create a retrieve route records using the standard Stryke’s REST API, which is automatically constructed for the app when we create it, via POST and GET requests.
[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.
We will create two API actions in Stryke for this. API actions allow us to write a JS script in Stryke that can be called via an HTTP request. This script can perform our business logic as well as create records or retrieve and return them.
[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).
From this information we will extract a route path using the Google direction’s API. This method of coming up with the route may not be 100% accurate when looking at a single case, since users may travel in different ways. However, when looking at a large number of routes, it should provide a description of how people are moving with an acceptable degree of error.
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);
See the full source code here.

“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
  }
}`);
Queries in Stryke are written using GraphQL notation. For every entity created, Stryke will provide callable GraphQL queries to retrieve all records, retrieve a record by ID or retrieve data filtered by criteria. In this case we will query using a filter that will only retrieve records created in the last 7 days.
See the full source code here.

The Front End — Glitch

I used Glitch to develop and host the heat map page and data entry form. I chose this platform because it allows me to focus on the HTML, JS and CSS and not have to worry about hosting, deploying, it even does source control for you behind the scenes!
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.
I first started implementing the heatmap layer using Google’s JS Heatmap API. However, I soon discovered that, for the heatmap API to draw full lines instead of isolated dots along a route I needed to send to the front end a very large number of points. This made the page quite slow.
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.
We will use the Google’s address autocomplete component to help fill in addresses quickly, as well as an option to auto-fill the current location. Both these options rely on the browser’s location service, which need to be allowed by the user.
The search used to do the address autocomplete is biased using the current location, as described in the example from Google.
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!

Written by edoStryke | Software engineer. Co-founder and CEO @ www.stryke.io
Published by HackerNoon on 2020/04/16