For this week of Everything is Spatial, we used some geolocation data we generated over the last two weeks with the Moves application, and visualized the paths we took as well as the locations we visited.

spatial_allroads/basic.png

This is the base map of my last two weeks– all roads lead back to ITP… I’m here a lot. I changed the paths to be a thinner line for travelling with public transit, and a thicker line for just walks.

We were then meant to enhance this data with one of the following:

  • Distance
  • Animations
  • Time
  • Details of the places we visited (it’s currently just coordinates)
  • A key or legend
  • Frequency of visits

I decided to go for the fourth option, and find details about the places I visited. Some of the locations I visited are already annotated, since I did so via the Moves app earlier, but I failed to do most of them. The rest I decided to use Google Maps’ geocoder to annotate, because I had done so before and was vaguely familiar with the process. I generated an API key, and wrote the following code to annotate the places with tooltips:

onEachFeature(feature, layer) {
            if (feature.properties &&
                feature.properties.place &&
                feature.properties.place.name) {
                layer.bindTooltip(feature.properties.place.name, {permanent: true}).addTo(map);
            } else {
                var latlng = feature.properties.place.location;

                geocoder.geocode({'location': {lat: parseFloat(latlng.lat), lng: parseFloat(latlng.lon)}}, function(results, status) {
                if (status === 'OK') {
                  if (results[0]) {
                    layer.bindTooltip(results[0].formatted_address, {permanent: true}).addTo(map);
                  }
                }
                });
            }
        }

and this worked fairly well, as the following screenshot shows:

spatial_allroads/annotations.png

The problm with this code, however, is that Google Maps rate limits free accounts, and it fires the requests too rapidly. The majority of places go unlabeled. To solve this, we can slow down the labelling, but this is also not ideal: for a web application, you want to load as fast as possible.

Another problem with this code is that the API key is needed on the client side, leaving you exposed to potential abuse. Someone could use this code to ping Google with their own georequests, and waste your money or rates. To protect you from this, Google lets you restrict your key to usage by certain websites and IP addresses, which should help.

The practical solution for this would be to prepopulate the information, and do the Geomapping before on the server side. (Or else pay Google to no longer be rate limited.) This would solve both of these problems.

I’m very lazy though, so I decided to just restrict my key, and deal with the rate limit by just removing the addresses that failed to populate:

        onEachFeature(feature, layer) {
            if (feature.properties &&
                feature.properties.place &&
                feature.properties.place.name) {
                layer.bindTooltip(feature.properties.place.name, {permanent: true}).addTo(map);
            } else {
                var latlng = feature.properties.place.location;

                geocoder.geocode({'location': {lat: parseFloat(latlng.lat), lng: parseFloat(latlng.lon)}}, function(results, status) {
                if (status === 'OK') {
                  if (results[0]) {
                    layer.bindTooltip(results[0].formatted_address, {permanent: true}).addTo(map);
                  } else {
                    placesLayer.removeLayer(layer);
                  }
                } else {
                    placesLayer.removeLayer(layer);
                }
                });
            }
        }

Done! Here’s the map below: