Lazy loading Google Maps with the IntersectionObserver API

For business web sites it is quite common to have a map on the site. In most cases clients want to add a Google Map, because that is what a lot of people use. The problem is that such a map loads a lot of JavaScript and images.

These maps are often placed at the bottom of a page. A fair number of people will probably never see the map. So the map would just waste bandwidth and make the page load slower.

Lazy loading can help here by only showing the map if it becomes visible when scrolling down. For this use case, browsers can use the IntersectionObserver API. For browsers that do not support this API, you can load the W3C IntersectionObserver Polyfill.

To achieve lazy loading you will have to load the Google Maps API with JavaScript, instead of directly from HTML. For this I use Filament Group loadJS.

Below is the code to implement a lazy loading map. To see it in action visit my demo page. Of course you can also use this technique with other maps, for example with Leaflet and OpenStreetMap data.

When loading the Google Maps API you will have to set a callback that is available on your web page. In my example this is google_maps_init. In this function you define all the settings for your map. It will be called once the API has finished loading. You also have to provide a Google Maps API key.

To trigger the IntersectionObserver you have to use observer.observe(element). Once the map has started to load you can stop observing by using observer.unobserve(element).

So go ahead and make your sites a bit more lazy.


<script src="loadJS.min.js"></script>
<script src="intersection-observer.min.js"></script>
<script>
function google_maps_init() {
  'use strict'

  var roemerberg = {lat: 50.110, lng: 8.682}
  var map = new google.maps.Map(document.getElementById('map'), {
    zoom: 15,
    center: roemerberg
  })
  var marker = new google.maps.Marker({
    position: roemerberg,
    map: map
  })
}

function google_maps_lazyload(api_key) {
  'use strict'

  if (api_key) {
    var options = {
      rootMargin: '400px',
      threshold: 0
    }

    var map = document.getElementById('map')

    var observer = new IntersectionObserver(
      function(entries, observer) {
        // Detect intersection https://calendar.perfplanet.com/2017/progressive-image-loading-using-intersection-observer-and-sqip/#comment-102838
        var isIntersecting = typeof entries[0].isIntersecting === 'boolean' ? entries[0].isIntersecting : entries[0].intersectionRatio > 0
        if (isIntersecting) {
          loadJS('https://maps.googleapis.com/maps/api/js?callback=google_maps_init&key=' + api_key )
          observer.unobserve(map)
        }
      },
      options
    )

    observer.observe(map)
  }
}

google_maps_lazyload("YOUR_GOOGLE_MAPS_API_KEY")
</script>