KML Layers

When the general tools of Google Maps are not enough, you can always turn to KML layers (opens new window) in order to "kick it up a notch". Within the context of a KML layer, the options to decorate a map are practically boundless.

Here is a map of the Chicago subway system using a KML layer...

Screenshot of a KML layer showing a map of the Chicago subway system

# Which method should I use?

KML is only one of several ways to draw on a map. Depending on what you want to show, a different method may be a better fit...

To show... Use
Custom shapes (routes, regions, landmarks) kml or geoJson
GPS tracks (a hike, a bike ride, a run) gpx
An image (a floor plan, a historic map) groundOverlay
Countries, states, cities, or ZIP codes boundaries
A large set of shapes uploaded to Google dataset

When in doubt between kml and geoJson, just use whichever format your file is already in.

KML Is Still Supported

Google officially dropped KML support in version 3.66 of the Maps JavaScript API, but we have added backwards-compatible support to the Google Maps plugin for Craft. If you were already using KML layers, you may continue to safely do so.

# Adding a KML layer

There are a few tools for creating KML files, here's the official Google resource:

However you go about creating your KML file, it's easy to apply it to an existing map...

map.kml(url, options);

Practically speaking, your code could look something like this...

// Create a plain dynamic map
const map = googleMaps.map();

// Add a KML layer to the map
map.kml(url);

For more information, take a look at the details of the kml method. If you intend to further manipulate the KML layers, it will be necessary to provide an id value.

KMZ files work too. A KMZ file is simply a zipped KML file, and it will be unzipped automatically.

# How it works

Once the map loads, the visitor's browser fetches the KML file, converts it, and draws it onto the map as a Data layer (opens new window).

  • Styles carry over. Line colors, fill colors, line widths, and icons from the KML file are all applied.
  • Info windows open on click. Clicking a shape shows its name and description. Any HTML in the description is sanitized first.
  • The map fits itself to the layer. Once the file has loaded, the map will zoom to show the entire layer (unless you set preserveViewport).

The tools for reading KML and KMZ files are bundled with the plugin, and only load when a map actually needs them. Nothing is pulled from a third-party CDN, so a strict Content Security Policy won't get in the way.

# The url parameter

Because the browser fetches the file directly, the KML file can live almost anywhere:

  • A complete URL (including the http(s):// prefix) works.
  • A relative URL (like /files/subway.kml) works.
  • A local URL works, so you can test KML layers on your local development site.

The one exception is a file which lives on another domain...

# Files on another domain

If the KML file is hosted on a different domain, that server must allow cross-origin requests (opens new window) by sending an Access-Control-Allow-Origin header. If it doesn't, the browser will refuse to load the file, and the JavaScript console will show a [GM] error mentioning CORS.

The easiest fix is to host a copy of the file on your own site. For example, you could upload it as an Asset, then pass the Asset's URL into the kml method.

The same rule applies to GeoJSON and GPX files.

Google My Maps

Maps made with Google My Maps (opens new window) work as-is, because Google allows cross-origin requests for them. Share the map publicly, then pass its KML link into the kml method:

https://www.google.com/maps/d/kml?mid=YOUR_MAP_ID

The map ID is the mid value in the map's own URL. Google sends that link as a KMZ file, which the plugin unpacks automatically.

# The options parameter

All options are optional.

Option Type Description
id string Reference point for each KML layer.
preserveViewport bool If true, the map will not zoom to fit the layer once it loads.
suppressInfoWindows bool If true, clicking a shape will not open an info window.
clickable bool If false, the layer will ignore clicks entirely (and no info windows will open).
zIndex int Stacking order of the layer, relative to other layers.
style object Any google.maps.Data.StyleOptions (opens new window) properties. Overrides the styles from the KML file.

There's no need to specify map or url values, as they will be set automatically.

map.kml(url, {
    'id': 'my-kml',
    'preserveViewport': true
});

Nested options work too

Each of these options can also be nested within a kmlLayerOptions value, so existing code written for Google's KmlLayerOptions (opens new window) will keep working. If an option is set both ways, the nested value wins.

In JavaScript, the style option can also be a styling function (opens new window), which receives each shape and returns its style.

Further KML Adjustments

To manipulate a KML layer, you will need to refer to it by its assigned ID. If you plan to manipulate the KML layers, be sure to set the id option of each KML layer when initially adding it to the map.

# Known limitations

Most KML files will display exactly as expected. However, a few KML elements can't be shown on a dynamic map, and will be skipped:

  • <NetworkLink> (a link to another KML file)
  • <ScreenOverlay>
  • <PhotoOverlay>
  • <Model> (3D models)

Each skipped element will be named in a [GM] warning in the JavaScript console. If your file relies on a <NetworkLink>, you can load the linked file directly with its own kml call.

Regions (level of detail) are also ignored, so every shape will always be visible regardless of the zoom level.

A <GroundOverlay> is supported, and will be shown as an image on the map. For more on placing images, see the guide for Ground Overlays...

# Further manipulating KML layers

If you only need to hide or show each KML layer, there are two convenient universal methods...

// Hide the KML layer
map.hideKml('my-kml');

// Show the KML layer
map.showKml('my-kml');

# Beyond hiding and showing

When you need to do more than hide or show a layer, you can get the raw Google Data layer object (opens new window), and manipulate it further using Google's own API.

This method is only available in JavaScript.

// Get the raw Google Data layer object
const kml = map.getKml('my-kml');

Returns a Data layer

The getKml method returns a google.maps.Data (opens new window) object, not a google.maps.KmlLayer. If your own JavaScript calls any KmlLayer methods directly, it will need to be updated to work with a Data object instead.