Learn how I created an app to help with the COVID-19 outbreak in less than a day using Stryke and Glitch. Photo by Capturing the human heart. on Unsplash 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 to show to the authorities in case we are stopped on the street. self-justification form 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: and . Stryke 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 Photo by Mehrad Vosoughi on Unsplash 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: and . For all tasks related with mapping we will use the . Stryke Glitch Google Maps APIs We will create an app in 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 Stryke is a great platform to implement a project like this as it is very quick to setup the following features: Data persistence Define the business logic through short JS code snippets Create a callable via HTTP requests custom API to keep things secure Authentication A to do back office UI for the app 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 to create these simple HTML pages and host them. Glitch is a great tool to put things together quickly and easily. Glitch Data entry (finding places easily and getting their coordinates), route calculation, as well as the heatmap visualisation require working with geo locations and maps. provides a host of very useful APIs to achieve these tasks. To achieve all of the above we will use the following APIs: The Google Maps Platform Maps JavaScript API Places API Directions API The Back End — Stryke is a platform for developers to create cloud applications easily. It speeds up development by providing many infrastructural features and an easy environment. 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 from the export file you can find . import the app 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 to the platform. signing up 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 . This is a format created by google that allows storing data for many points in an encoded string. The 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. encoded polyline response from the directions API _jv{F_zhLp@ @g@ `AHLHM~CsEfCqDl@y@^h@R\DAL?^Hb@RhGtElBtAvAdARWNQCe@RRR[^e@fBgCHMHLvC|DzBdDnFjIvN|Sf@r@~HhLpEvGzG~JfJvMfA|Al@}@lAmBj@eA` `@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 : Carrer de Mallorca, , Barcelona, Spain to: Rambla de Catalunya, , Barcelona, Spain from 481 08013 2 08007 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 , which is automatically constructed for the app when we create it, via POST and GET requests. Stryke’s REST API [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 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. API actions [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 . 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. Google direction’s API The action will first retrieve the start and end points, and method of transport from the request’s payload: payload = stryke.data.requestData; startPoint = ; endPoint = ; routeType = payload.routeType ? payload.routeType : ; const const ` , ` ${payload.start_lat} ${payload.start_lng} const ` , ` ${payload.end_lat} ${payload.end_lng} const 'walking' Then it will call the Google API to calculate a route: url = ; response = axios.get(url); const `https://maps.googleapis.com/maps/api/directions/json?origin= &destination= &key= &mode= ` ${startPoint} ${endPoint} ${apiKey} ${routeType} const await Finally, it will store the route details in a new route record in Stryke selectedRoute = response.data.routes[ ]; routeLegs = selectedRoute.legs; route = { : selectedRoute.overview_polyline.points, : routeLegs[ ].start_location.lat, : routeLegs[ ].start_location.lng, : routeLegs[routeLegs.length ].end_location.lat, : routeLegs[routeLegs.length ].end_location.lng, : } stryke.create( , route); const 0 const const path start_lat 0 start_lng 0 end_lat -1 end_lng -1 routeName ` from: to: ` ${routeType} ${routeLegs[ ].start_address} 0 ${routeLegs[routeLegs.length ].end_address} -1 await '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. DATA_WINDOW_DAYS = ; startDate = moment().add(-DATA_WINDOW_DAYS, ); routes = stryke.find( ); const 7 const 'days' const await `{ Route ( filter: { created : { gt : " " }} ) { start_lat, start_lng, end_lat, end_lng, path } }` ${startDate.toISOString()} Queries in Stryke are written using notation. For every entity created, Stryke will provide callable 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. GraphQL GraphQL queries See the full source code . here The Front End — Glitch I used 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! 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. I first started implementing the heatmap layer using . 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. Google’s JS Heatmap API 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. polyObj = google.maps.geometry.encoding.decodePath(route.path); path = google.maps.Polyline({ : polyObj, : , : , : , : }); path.setMap(map); // decode the polyline const // define the look of the polyline var new path geodesic true strokeColor '#8ADE42' strokeOpacity 0.3 strokeWeight 7 // draw the polyline on the 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 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. Google’s address autocomplete component 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( { routeDetails.start_lat = position.coords.latitude; routeDetails.start_lng = position.coords.longitude; .getElementById( ).value = ; }); ( ) function position document "start" 'Current location' Live Demo You can see a live demo of what we have discussed so far, here: https://covidheatmap.glitch.me/ 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!