Where is Jasper (v1)? Connecting Google Calendar, Maps, and Places APIs

Where am I? In real time: whereis.jshowers.com

When I went full time digital nomad, I started using a public Google calendar to share with family and friends where I was. This also helped me organize my thoughts and travel dates.

I wanted to make a simple graphical representation of this calendar, so I decided to make a site that would use the data I already have in the calendar. I wanted to show where I currently am, where I was previously, and where I’m going next. I also wanted to show a google map with a pin at my current location.

Disclaimer: there are a thousand different ways I could have done this, and a thousand more ideas to expand on it. This works, and is very basic.

HTML

I used bootstrap for page layout, as I can whip it together easily. The page consists of a basic page-header class and a 3-column table layout.

<div class="page-header text-center">
    <h1>Where is Jasper?</h1>
</div>
<table class="table text-center">
    <thead>
      <tr>
        <th class="text-center"><h3><span class="label label-default">Previous</span></h3>
        <th class="text-center"><h3><span class="label label-primary">Now</span></h3></th>
        <th class="text-center"><h3><span class="label label-default">Next</span></h3></th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td><h3 id="past-place"></h3></td>
        <td><h3 id="current-place"></h3></td>
        <td><h3 id="next-place"></h3></td>
      </tr>
    </tbody>
</table>

<div id="map"></div>

JavaScript Libraries

To make this work I need:

  1. The current date, in order to see which calendar event (location) we are currently on.
    • MomentJS is a quick and easy date parsing and comparison library.
  2. List of all calendar events.
  3. Figure out which event we are currently on by comparing today’s date with event dates.
    • Basic date comparison logic.
  4. Figure out the latitude/longitude of the place we are in (from the calendar event’s title).
  5. Show a map and center it on the current location with a dropped pin.

Other libraries used:

  • jQuery – oh yeah baby, like it’s 2008! This is a dependency of Bootstrap and also makes it easy to add our place names to the HTML elements. Also an easy way to make our API calls.

JavaScript Code

Now the fun stuff!

First some constants and a date comparison function for sorting calendar events.

const date_now = moment().format("YYYY-MM-DD");
const calendar_id = "{Calendar ID}";
const api_key = "{Google API Key}";

function compare_dates(a, b) {
  if ( a.end.date < b.end.date ){ return -1; }
  if ( a.end.date > b.end.date ){ return 1; }
  return 0;
}

Now we get the list of all calendar events, sort them by date, and get our current, past, and future events. We also put the calendar invite name (the location, like “London, England”) into our HTML for display.

$.get({
  url:`https://www.googleapis.com/calendar/v3/calendars/${calendar_id}/events?key=${api_key}`,
    success: function(data) {
      let events = data.items;

      // Sort list since &sortBy doesn't seem to work with the google calendar API call and this event type
      events.sort(compare_dates)

      // Find today's event
      let current_event_index = events.findIndex( event => event.end.date >= date_now );
      let current_event = events[current_event_index]
      
      // Since our events are sorted,
      // the previous and next events will be +/- one index away
      let past_event = events[current_event_index - 1]
      let next_event = events[current_event_index + 1]

      // Insert the event summary (the place name in my calendar) into our HTML
      $("#past-place").text(past_event.summary);
      $("#current-place").text(current_event.summary);
      $("#next-place").text(next_event.summary);

      // Now iniit the Google maps with our current place selected
      initMap(current_event.summary)
  }
});

Finally, we initialize the map on the page, passing in our current location. This searches the Places API to get the corresponding latitude/longitude in order to center the map at that location and to drop a pin there.

// Initialize and add the map
let map;
let map_element = document.getElementById("map")
async function initMap(current_location) {
    // Request needed libraries
    const { Map } = await google.maps.importLibrary("maps");
    const { AdvancedMarkerView } = await google.maps.importLibrary("marker");
    const { Places } = await google.maps.importLibrary("places");

    // Construct the Map object
    map = new Map(map_element, {
        zoom: 5,
    });

    // Places request to get lat/long based on passed in location
    var request = {
        query: current_location,
        fields: ['name', 'geometry'],
    };
    var service = new google.maps.places.PlacesService(map);
    service.findPlaceFromQuery(request, function(results, status) {
    if (status === google.maps.places.PlacesServiceStatus.OK) {
        // Assume top result is fine, place marker on map
        let top_result = results[0]
        const marker = new AdvancedMarkerView({
            map: map,
            position: top_result.geometry.location,
            title: top_result.name,
        });
        map.setCenter(top_result.geometry.location);
    }
    });
}

Tada! Mission accomplished.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.