Google Maps JS Implementation Tips

Introduction

Google’s Maps Platform is undeniably one of the most widely used technologies. And in supporting web applications, Google’s Maps JavaScript API is one of the most popular used throughout. Utilizing the API, web applications are able to offer a myriad of features that require map-based functionality.

As an avid web developer and traveler, I’ve used the Maps JavaScript API a few times, and most particularly with a recent comprehensive client feature requiring maps that our team just completed. I’ve aggregated various thoughts, opinions, and tips with regards to Google’s Maps JavaScript API:

1) ADA and WCAG Compliance Priority

If the web application you are supporting is required to hold a degree of ADA and WCAG compliance, ensuring that your maps experience is designed to be ADA-friendly should be the priority before diving into development.

Google has focused much energy and development effort into ensuring their Maps product is ADA compliant. But, if you are likely building custom, comprehensive functionality around a Google Maps experience you will want to ensure the design and technical approach are ADA-friendly.

For example, let us consider an application that displays a list of results. One consideration is that you will want to ensure the experience is keyboard and screen-reader friendly. It is optimal to ensure the list of results is before the map’s iFrame in the tabbing order, to help provide the information before the user’s tabbing reaches the complex map.

Additionally, having descriptive aria-label‘s is incredibly important to have integrated within each result. To illustrate this, there is sometimes designed context that is implied through the style of each individual map pin/marker (possibly the shape and/or color of each pin). But for non-sighted users, they are unable to obtain this context, so having these comprehensive aria-label‘s in-place is critical.

For illustrating the importance of aria-label‘s, consider the following example where we have three items on the map nearby Kenya’s Maasai Mara National Reserve, each having a different pin icon & color:

To sighted users, there is a visual implication that can be made that all three locations are present but represent different categories: an airport, a wildlife park, and a campsite. But, non-sighted users would need to have this information present in a screen-reader friendly manner. Sometimes the titles can contain this context (such as “Serena Airstrip“), but it is most convenient and efficient to utilize a dynamic aria-label for each location represented. For example, the aria-label for Mara Triangle could be: “Mara Triangle. This is a wildlife preserve.”

One last example is the possible usage of aria-live. Map components often have multiple elements in different locales that trigger certain events that change the state. This can include searching, filtering, focusing on an item, etc. Important context can be announced to screen-reader users upon a Map component state change via the aria-live usage. For example, if the user toggles a filter, the aria-live queue can possibly announce: “Five results remain after filtering on the state ‘Alaska'”.

There are numerous ADA optimizations and discussions around map component implementations, but the key takeaway is to ensure you are prioritizing ADA considerations over other requirements.

2) Third-party libraries not needed.

When starting an implementation that involves the Google Maps JavaScript API, the first impulse of most developers is likely to search for a quality third-party library that streamlines integration. I am usually a supporter of utilizing third-party libraries within reason, but with the Google Maps JavaScript API, you won’t need to in my opinion.

One exception that could be made is if you opted for dynamic package loading, in which Google recommends the npm package @googlemaps/js-api-loader. But, my recommendation is primarily targeted at using Google’s Maps JS API without having to use a third-party library that abstracts the loading, data management, and other features.

You also gain the benefit of remaining agnostic with regards to the JS technologies you’re using. For example, you won’t need to have a dependency on seeking out tooling that works specifically with React, Vue, Angular, etc.

Sometimes, one benefit of adding a third-party library is that some comprehensive functionality is abstracted to appear cleaner and easier to use. But having utilized Google’s Maps JavaScript API, I can confidently say that the documentation is possibly the best I’ve seen yet as a developer and it is incredibly easy to understand.

The bottom-line, with an increasing emphasis on reducing JavaScript bundle sizes, this is great news!

3) GeoJSON is king.

A standard format when using geographic data structures is GeoJSON. Most location-based data is usually already structured under the specified GeoJSON format, which makes managing the data with the Google Maps JavaScript API an absolute breeze.

Consider the following GeoJSON example representing a collection of airports, including one airport as Mumbai’s major international airport (BOM):

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [
          72.874564,
          19.095102
        ]
      },
      "properties": {
        "city": "Mumbai",
        "country": "India",
        "iata_code": "BOM",
        "isInternational": true,
        "name": "Chhatrapati Shivaji Int'l"
      }
    },
    {
      ...additional airports
    }
  ]
}

If our goal is to display all airports on Earth within a Google Map, we can have an array of GeoJSON objects [such as above] that represent each airport and easily add them to the map using Google’s Data class. Within this class is a method called addGeoJson(geoJson). If you set the geoJson parameter to our array of airport GeoJSON objects, the Google Map will display each airport using their coordinates automatically!

Aside from the advantage of not having to manually create a secondary set of data objects representing the airports for Google Maps to consume, we can also dynamically set a customized list of properties. Consider one of our requirements is to display airports with international destinations in contrast to domestic-only airports using a filter toggle available to the user. We can set a boolean field under properties named isInternational and use this context to ensure our filter can work.

Consider the toggle is labelled “Show only International Airports” and we run the following code upon the user’s toggle event:

const onUserToggleShowOnlyIntl = (googleMap, showOnlyIntl) => {
  googleMap.data.setStyle(airport => {
    return {
      visible: showOnlyIntl ? airport.getProperty('isInternational') : true
    };
  });
};

The method setStyle() under Google’s Data class has been one of my favorites. We’re able to use setStyle() to iterate through each data feature (each airport) on the map and set styles accordingly. With our use case, when showing/hiding specific features we’re able to utilize Google’s visible boolean property. We first check to see if the user wants to show only international airports with the showOnlyIntl value, and if this is true we simply set visible equal to the airport’s isInternational boolean value.

If your source data is formatted to align with GeoJSON, integrating with Google’s JavaScript API will be a smooth experience. If not, it may be a worthy investment to ensure the data is GeoJSON compliant or construct a method to convert the data, respectively.

4) Use Google’s Client-Side Services

In the past, I’ve used Google’s Geocoding API web service server-side (namely in conjunction with my Amazon Alexa Skill), but an important note is that you can also utilize these web services client-side as part of the Maps JavaScript API.

The Geocoding Service is available client-side through the Maps JavaScript API, alongside others such as the Directions, Distance Matrix, Elevation, Imagery, and Street View services.

This is an important distinction, as the server-side services offer separate API key security restrictions in comparison to the client-side services. When utilizing the client-side services, you will likely track to utilize the HTTP referrers restriction. This allows you to define an origin URL representing your web page and only allow API calls when the origin matches the URL you set.

The server-side web services do not allow for the HTTP referrers restriction, so initially ensuring the usage of the client-side services can prevent critical rework when nearing the deployment of your map application.

5) Chrome’s DevTools Geolocation Override

If you track to utilize the user’s location via the Geolocation Web API, an important note is that you can use Google Chrome’s Geolocation Override functionality from DevTools.

This is a vital note, as it allows you to QA your work more easily, especially if you have conditional functionality based upon if the user is in a certain locale.

Essentially, you just need to navigate to the DevTools window, press Command+Shift+P (or Control+Shift+P if you’re not using a Mac) and search for Sensors. On the Sensors tab, you’re able to select from a set of preset locations Google has provided, but you can also set a custom location override.

Consider the situation where we want to set our location to Quito, Ecuador. After doing a brief Google for the coordinates of Quito (-0.1807, -78.4678), we can set the Location dropdown value to “Other…” and set the respective latitude and longitude values:

Otherwise, without this DevTools functionality, someone might have had to roll back to using a VPN that offers various locations to connect through.

Additionally, to note, Firefox does not appear to have an official geolocation override at this time, but there are add-ons currently available.

6) Explore the documentation and helpful methods.

In developing comprehensive map application functionality in conjunction with Google’s Map JavaScript API, I can confidently state there are a wide variety of helpful methods and categorized “sub-libraries” that help immensely with implementations. I’m going to review two helpful tools to illustrate this point:

fitBounds()

There is a common requirement in most map application implementations to ensure the pins/markers of an entire set of clustered location data is to be fit into the Google Map’s iFrame. At first, this is a somewhat daunting task to fill as a JavaScript developer, as you have to ensure that the map has the correct zoom level, center point, etc.

But, fortunately, there is a non-manual solution to this: the fitBounds() method!

Rather than calculating/performing this manually, you can utilize the fitBounds() method to trigger the Google Map iFrame to resize, zoom, and center correctly on a set of clustered location points. Consider our earlier example where we have a set of airports, and assume we narrow the set of airports to a subset of airports in a singular country. We can use fitBounds() similar to this example:

const mapFitBounds = (googleMap) => {
  let bounds = new google.maps.LatLngBounds();
  googleMap.data.forEach(airport => {
    airport.getGeometry().forEachLatLng(latLng => {
      bounds.extend(latLng);
    });
  });
  googleMap.fitBounds(bounds);
};

The above example will ensure Google resizes the map’s iFrame to focus on only the airports we’ve narrowed down to in a given country. When using fitBounds(), we have to pass a LatLngBounds object which essentially represents a rectangle in geographical coordinates. To generate this bounds object, we can iterate through each airport in our dataset, each time extending from our bounds object. In the end, we simply call fitBounds() and pass our compiled bounds object!

Another note about fitBounds() that makes it so fantastic is the responsiveness of it. Whether you are using a mobile device, tablet, or desktop the pins/markers will all be in view after using fitBounds() accurately.

Spherical Geometry

Another common challenge can be distance measurement, especially with spherical distance measurement needed for the distance between two coordinates on Earth.

Given the need for measurement of spherical distance, we cannot use a more simple mathematical equation such as Euclidean distance. We must use a more accurate measurement to find the distance between two coordinates on Earth, and it escalates in complexity quite fast.

Math, YIKES! That is not a preferred subject!

The good news is that we don’t have to worry about this beyond the abstraction of knowing a spherical distance calculation is needed. Whew, technology saves us from testing our code with a graphing calculator!

Google luckily has a Geometry library, and a subset of this library contains logic to calculate spherical distance.

Let’s run an example and calculate the spherical distance between Dakar, Senegal (14.73904, -17.49016) and Rio de Janeiro, Brazil (-22.81481, -43.24977). Fun fact: in 1976 the Concorde supersonic jet made its initial journey from Paris to Rio [via Dakar]!

Consider the following code example that calculates the distance [in miles] between Dakar and Rio:

const getMiles = (meters) => {
  return meters * 0.000621371192;
};

const dakarLatLng = new google.maps.LatLng(14.73904, -17.49016);
const rioLatLng = new google.maps.LatLng(-22.81481, -43.24977);

const distanceInMeters = google.maps.geometry.spherical.computeDistanceBetween(dakarLatLng, rioLatLng);
const distanceInMiles = getMiles(distanceInMeters);

console.log(`Distance between DKR -> RIO: ${distanceInMiles.toFixed(2)} miles`);

The above code will output to the console: Distance between DKR -> RIO: 3128.97 miles

All we essentially have to do is define a function that converts miles to meters, define our LatLng objects representing Dakar and Rio, and call the function computeDistanceBetween() passing our LatLng objects. Our result is 3,128.97 miles. Let’s check our work manually with Google’s Distance Measurement tool in Maps:

Our math when using computeDistanceBetween() from Google’s Spherical library looks good!

The bottom-line: outside of these two examples (fitBounds(), and Spherical Geometry), there is a wide spectrum of functionality built around Google’s Maps JavaScript API and I encourage you to explore the documentation before starting formal development.

Conclusion

As an avid web application JavaScript developer, I can state that utilizing the Google Maps JavaScript API is a fun and rewarding tool to work with. I encourage every developer to explore its functionality, whether it be in an enterprise setting or for a personal project.

In the endeavor of utilizing and exploring the Maps JavaScript API, I hope these tips have provided some insight and aid.

Safe travels!

Leave a Reply

avatar
  Subscribe  
Notify of