Photo by Thomas Kvistholt on Unsplash

A small serverless app I created to take screenshots of particular coordinates on Google Maps with the traffic layer applied to it in order to track how the traffic changes during my commute.  

Overview

This is a small serverless app I created to take screenshots of particular coordinates on Google Maps with the traffic layer applied to it in order to track how the traffic changes during my commute. 

The idea is to load the map on a simple static website hosted on S3, then using a lambda function take a screenshot of the map every 5 minutes for 2 hours and save those screenshots into an S3 bucket in order to analyze the traffic later and find the best gap in it.
 

Technologies used:

  • phantomjs (yes it’s deprecated and development ceased but I was familiar with it and wanted to get a working prototype quickly)
  • serverless framework
    • lambda function - handler takes in a url (could have used google maps directly like in the github repo above) and uses phantomjs to take a screenshot of it, save it in the lambda temporary file system and then upload it to s3
    • s3 bucket
      • serves a very basic one page static website which simply loads the google maps library with the traffic layer for given coordinates
      • stores the screenshots in folder per ‘place name’ -> date -> time of day
    • cloudwatch logs to store lambda logs
    • cloudwatch rules - schedule the lambda function run (mon-friday 7am-9am every 5 minutes) and passes the url with coordinates and the place name

Inspired by

https://serverless.com/blog/building-a-serverless-screenshot-service-with-lambda/

https://github.com/alykat/snowzilla-traffic

Repository:

https://github.com/dumityty/serverless-traffic-maps

Traffic map static website

This is a simple html site with a very basic google map loaded at the given coordinates with the traffic layer enabled.

The reason I didn’t just use the normal static map api from Google Maps is that they don’t provide the traffic layer with it.

var map = new google.maps.Map(document.getElementById('map'), {
  zoom: 15,
  center: new google.maps.LatLng(lat, lon),
  disableDefaultUI: true
});

var trafficLayer = new google.maps.TrafficLayer();
trafficLayer.setMap(map);

Where latitude and longitude are provided via url query parameters.

Full code here:

https://github.com/dumityty/serverless-traffic-maps/blob/master/public/traffic.html

Screenshot lambda function

This uses phantom js to load the traffic map site from S3 and saves a screenshot of it into lambda temporary file system in the /tmp folder. This screenshot is then uploaded to an S3 bucket in folders named by location name, current date and time. 

The phantom screenshot script boils down to loading the url of the s3 static site and rendering it to the destination file:

url = args[1];
output = args[2];
...
page.open(url);
…
page.render(output);
phantom.exit();

You can see it in detail here:

https://github.com/dumityty/serverless-traffic-maps/blob/master/serverless/phantomjs/screenshot.js

The lambda function handler retrieves the static site url and the name of the place we are screenshotting from the even variable, then runs the phantom screenshot script, load the screenshot that was saved in the temporary file system, and then uploads it to the S3 bucket:

...
const cmd = `./phantomjs/phantomjs --debug=yes --ignore-ssl-errors=true ./phantomjs/screenshot.js "${targetUrl}" /tmp/${targetHash}.png`;
…
const fileBuffer = fs.readFileSync(`/tmp/${targetHash}.png`);
const s3 = new AWS.S3();
s3.putObject({
  ACL: 'public-read',
  Key: targetFilename,
  Body: fileBuffer,
  Bucket: targetBucket,
  ContentType: 'image/png',
});

Full handler code here:

https://github.com/dumityty/serverless-traffic-maps/blob/master/serverless/handler.js

Analyze traffic

This bit is still not finished, especially since it’s been running over Christmas time and will not reflect normal commuting times.

As a quick test I have synced a few ‘day’ folders locally and ran imagemagick to convert them into gifs:

convert -background white -alpha remove -layers optimize-plus -delay 15x60 -resize 800 *.png -loop 0 2017-12-19.gif

The result can be seen here:

screenshot gif