Data Layer

Select platform: Android iOS JavaScript

The Google Maps Data layer provides a container for arbitrary geospatial data. You can use the Data layer to store your custom data, or to display GeoJSON data on a Google map.

Overview

Watch this DevBytes video to learn more about the Data Layer.

With the Maps JavaScript API you can mark up a map with a variety of overlays, such as markers, polylines, polygons, etc. Each of these annotations combines styling information with location data. The google.maps.Data class is a container for arbitrary geospatial data. Instead of adding these overlays, you can use the Data layer to add arbitrary geographical data to your map. If that data contains geometries, such as points, lines or polygons, the API will render these by default as markers, polylines and polygons. You can style these features as you would a normal overlay, or apply styling rules based on other properties contained in your data set.

The google.maps.Data class allows you to:

  • Draw polygons on your map.
  • Add GeoJSON data to your map.
    GeoJSON is a standard for geospatial data on the internet. The Data class follows the structure of GeoJSON in its data representation and makes it easy to display GeoJSON data. Use the loadGeoJson() method to easily import GeoJSON data and display points, line-strings and polygons.
  • Use google.maps.Data to model arbitrary data.
    Most real-world entities have other properties associated with them. For example, stores have opening hours, roads have traffic speed, and each Girl Guide troupe has cookie-selling turf. With google.maps.Data, you can model these properties, and style your data accordingly.
  • Choose how your data is represented, and change your mind on the fly.
    The Data layer lets you make decisions about the visualization and interaction of your data. For example, when looking at a map of convenience stores you might choose to display only those stores that sell transit tickets.

Draw a polygon

The Data.Polygon class handles polygon winding for you. You can pass it an array of one or more linear rings, defined as latitude/longitude coordinates. The first linear ring defines the outer boundary of the polygon. If you pass more than one linear ring, the second and subsequent linear rings are used to define inner paths (holes) in the polygon.

The following example creates a rectangular polygon with two holes in it:

TypeScript

// This example uses the Google Maps JavaScript API's Data layer
// to create a rectangular polygon with 2 holes in it.

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 6,
      center: { lat: -33.872, lng: 151.252 },
    }
  );

  // Define the LatLng coordinates for the outer path.
  const outerCoords = [
    { lat: -32.364, lng: 153.207 }, // north west
    { lat: -35.364, lng: 153.207 }, // south west
    { lat: -35.364, lng: 158.207 }, // south east
    { lat: -32.364, lng: 158.207 }, // north east
  ];

  // Define the LatLng coordinates for an inner path.
  const innerCoords1 = [
    { lat: -33.364, lng: 154.207 },
    { lat: -34.364, lng: 154.207 },
    { lat: -34.364, lng: 155.207 },
    { lat: -33.364, lng: 155.207 },
  ];

  // Define the LatLng coordinates for another inner path.
  const innerCoords2 = [
    { lat: -33.364, lng: 156.207 },
    { lat: -34.364, lng: 156.207 },
    { lat: -34.364, lng: 157.207 },
    { lat: -33.364, lng: 157.207 },
  ];

  map.data.add({
    geometry: new google.maps.Data.Polygon([
      outerCoords,
      innerCoords1,
      innerCoords2,
    ]),
  });
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example uses the Google Maps JavaScript API's Data layer
// to create a rectangular polygon with 2 holes in it.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 6,
    center: { lat: -33.872, lng: 151.252 },
  });
  // Define the LatLng coordinates for the outer path.
  const outerCoords = [
    { lat: -32.364, lng: 153.207 }, // north west
    { lat: -35.364, lng: 153.207 }, // south west
    { lat: -35.364, lng: 158.207 }, // south east
    { lat: -32.364, lng: 158.207 }, // north east
  ];
  // Define the LatLng coordinates for an inner path.
  const innerCoords1 = [
    { lat: -33.364, lng: 154.207 },
    { lat: -34.364, lng: 154.207 },
    { lat: -34.364, lng: 155.207 },
    { lat: -33.364, lng: 155.207 },
  ];
  // Define the LatLng coordinates for another inner path.
  const innerCoords2 = [
    { lat: -33.364, lng: 156.207 },
    { lat: -34.364, lng: 156.207 },
    { lat: -34.364, lng: 157.207 },
    { lat: -33.364, lng: 157.207 },
  ];

  map.data.add({
    geometry: new google.maps.Data.Polygon([
      outerCoords,
      innerCoords1,
      innerCoords2,
    ]),
  });
}

window.initMap = initMap;

Load GeoJSON

GeoJSON is a common standard for sharing geospatial data on the internet. It is lightweight and easily human-readable, making it ideal for sharing and collaborating. With the Data layer, you can add GeoJSON data to a Google map in just one line of code.

map.data.loadGeoJson('google.json');

Every map has a map.data object, which acts as a data layer for arbitrary geospatial data, including GeoJSON. You can load and display a GeoJSON file by calling the loadGeoJSON() method of the data object. The below example shows how to add a map and load external GeoJSON data.

TypeScript

let map: google.maps.Map;

function initMap(): void {
  map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
    zoom: 4,
    center: { lat: -28, lng: 137 },
  });

  // NOTE: This uses cross-domain XHR, and may not work on older browsers.
  map.data.loadGeoJson(
    "https://storage.googleapis.com/mapsdevsite/json/google.json"
  );
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

let map;

function initMap() {
  map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -28, lng: 137 },
  });
  // NOTE: This uses cross-domain XHR, and may not work on older browsers.
  map.data.loadGeoJson(
    "https://storage.googleapis.com/mapsdevsite/json/google.json",
  );
}

window.initMap = initMap;
View example

Try Sample

Sample GeoJSON

Most of the examples on this page use a common GeoJSON file. This file defines the six characters in ‘Google’ as polygons over Australia. Please feel free to copy or modify this file as you test out the Data layer.

Note: In order to load a json file from another domain, that domain must have enabled Cross-origin resource sharing.

The full text of the file can be seen below by expanding the small arrow next to the words google.json.

google.json

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "properties": {
        "letter": "G",
        "color": "blue",
        "rank": "7",
        "ascii": "71"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [123.61, -22.14], [122.38, -21.73], [121.06, -21.69], [119.66, -22.22], [119.00, -23.40],
            [118.65, -24.76], [118.43, -26.07], [118.78, -27.56], [119.22, -28.57], [120.23, -29.49],
            [121.77, -29.87], [123.57, -29.64], [124.45, -29.03], [124.71, -27.95], [124.80, -26.70],
            [124.80, -25.60], [123.61, -25.64], [122.56, -25.64], [121.72, -25.72], [121.81, -26.62],
            [121.86, -26.98], [122.60, -26.90], [123.57, -27.05], [123.57, -27.68], [123.35, -28.18],
            [122.51, -28.38], [121.77, -28.26], [121.02, -27.91], [120.49, -27.21], [120.14, -26.50],
            [120.10, -25.64], [120.27, -24.52], [120.67, -23.68], [121.72, -23.32], [122.43, -23.48],
            [123.04, -24.04], [124.54, -24.28], [124.58, -23.20], [123.61, -22.14]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "letter": "o",
        "color": "red",
        "rank": "15",
        "ascii": "111"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [128.84, -25.76], [128.18, -25.60], [127.96, -25.52], [127.88, -25.52], [127.70, -25.60],
            [127.26, -25.79], [126.60, -26.11], [126.16, -26.78], [126.12, -27.68], [126.21, -28.42],
            [126.69, -29.49], [127.74, -29.80], [128.80, -29.72], [129.41, -29.03], [129.72, -27.95],
            [129.68, -27.21], [129.33, -26.23], [128.84, -25.76]
          ],
          [
            [128.45, -27.44], [128.32, -26.94], [127.70, -26.82], [127.35, -27.05], [127.17, -27.80],
            [127.57, -28.22], [128.10, -28.42], [128.49, -27.80], [128.45, -27.44]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "letter": "o",
        "color": "yellow",
        "rank": "15",
        "ascii": "111"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [131.87, -25.76], [131.35, -26.07], [130.95, -26.78], [130.82, -27.64], [130.86, -28.53],
            [131.26, -29.22], [131.92, -29.76], [132.45, -29.87], [133.06, -29.76], [133.72, -29.34],
            [134.07, -28.80], [134.20, -27.91], [134.07, -27.21], [133.81, -26.31], [133.37, -25.83],
            [132.71, -25.64], [131.87, -25.76]
          ],
          [
            [133.15, -27.17], [132.71, -26.86], [132.09, -26.90], [131.74, -27.56], [131.79, -28.26],
            [132.36, -28.45], [132.93, -28.34], [133.15, -27.76], [133.15, -27.17]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "letter": "g",
        "color": "blue",
        "rank": "7",
        "ascii": "103"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [138.12, -25.04], [136.84, -25.16], [135.96, -25.36], [135.26, -25.99], [135, -26.90],
            [135.04, -27.91], [135.26, -28.88], [136.05, -29.45], [137.02, -29.49], [137.81, -29.49],
            [137.94, -29.99], [137.90, -31.20], [137.85, -32.24], [136.88, -32.69], [136.45, -32.36],
            [136.27, -31.80], [134.95, -31.84], [135.17, -32.99], [135.52, -33.43], [136.14, -33.76],
            [137.06, -33.83], [138.12, -33.65], [138.86, -33.21], [139.30, -32.28], [139.30, -31.24],
            [139.30, -30.14], [139.21, -28.96], [139.17, -28.22], [139.08, -27.41], [139.08, -26.47],
            [138.99, -25.40], [138.73, -25.00 ], [138.12, -25.04]
          ],
          [
            [137.50, -26.54], [136.97, -26.47], [136.49, -26.58], [136.31, -27.13], [136.31, -27.72],
            [136.58, -27.99], [137.50, -28.03], [137.68, -27.68], [137.59, -26.78], [137.50, -26.54]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "letter": "l",
        "color": "green",
        "rank": "12",
        "ascii": "108"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [140.14,-21.04], [140.31,-29.42], [141.67,-29.49], [141.59,-20.92], [140.14,-21.04]
          ]
        ]
      }
    },
    {
      "type": "Feature",
      "properties": {
        "letter": "e",
        "color": "red",
        "rank": "5",
        "ascii": "101"
      },
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [144.14, -27.41], [145.67, -27.52], [146.86, -27.09], [146.82, -25.64], [146.25, -25.04],
            [145.45, -24.68], [144.66, -24.60], [144.09, -24.76], [143.43, -25.08], [142.99, -25.40],
            [142.64, -26.03], [142.64, -27.05], [142.64, -28.26], [143.30, -29.11], [144.18, -29.57],
            [145.41, -29.64], [146.46, -29.19], [146.64, -28.72], [146.82, -28.14], [144.84, -28.42],
            [144.31, -28.26], [144.14, -27.41]
          ],
          [
            [144.18, -26.39], [144.53, -26.58], [145.19, -26.62], [145.72, -26.35], [145.81, -25.91],
            [145.41, -25.68], [144.97, -25.68], [144.49, -25.64], [144, -25.99], [144.18, -26.39]
          ]
        ]
      }
    }
  ]
}

Style GeoJSON Data

Use the Data.setStyle() method to specify how your data should look. The setStyle() method takes either a StyleOptions object literal, or a function that computes the style for each feature.

Simple style rules

The simplest way to style features is to pass a StyleOptions object literal to setStyle(). This will set a single style for each feature in your collection. Note that each feature type is only able to render a subset of the available options. This means that its possible to combine styles for different feature types in a single object literal. For example, the below snippet sets both a custom icon, which only affects point geometries, and fillColor, which only affects polygons.

map.data.setStyle({
  icon: '//example.com/path/to/image.png',
  fillColor: 'green'
});

More information on valid style/feature combinations can be found in Style Options.

Below is an example of setting the stroke and fill color for several features using a StyleOptions object literal. Notice that each polygon is styled the same.

// Set the stroke width, and fill color for each polygon
map.data.setStyle({
  fillColor: 'green',
  strokeWeight: 1
});

Declarative style rules

If you want to update the style of a large number of overlays, such as markers or polylines, you typically have to iterate through each overlay on your map and set its style individually. With the Data layer, you can set rules declaratively and they will be applied across your entire data set. When either the data, or the rules, are updated, the styling will be automatically applied to every feature. You can use a features properties to customize its style.

For example, the below code sets the color of each character in our google.json by examining its position in the ascii character set. In this case we’ve encoded the character position along with our data.

// Color Capital letters blue, and lower case letters red.
// Capital letters are represented in ascii by values less than 91
map.data.setStyle(function(feature) {
    var ascii = feature.getProperty('ascii');
    var color = ascii > 91 ? 'red' : 'blue';
    return {
      fillColor: color,
      strokeWeight: 1
    };
});

Remove styles

If you’d like to remove any applied styles, pass an empty object literal to the setStyles() method.

// Remove custom styles.
map.data.setStyle({});

This will remove any custom styles that you’ve specified, and the features will render using the default styles. If you’d instead like to no longer render the features, set the visible property of StyleOptions to false.

// Hide the Data layer.
map.data.setStyle({visible: false});

Override default styles

Styling rules are typically applied to every feature in the Data layer. However, there are times when you’d like to apply special styling rules to specific features. For example, as a way to highlight a feature on click.

To apply special styling rules, use the overrideStyle() method. Any properties that you change with the overrideStyle() method are applied in addition to the global styles already specified in setStyle(). For example, the below code will change the fill color of a polygon on click, but will not set any other styles.

// Set the global styles.
map.data.setStyle({
  fillColor: 'green',
  strokeWeight: 3
});

// Set the fill color to red when the feature is clicked.
// Stroke weight remains 3.
map.data.addListener('click', function(event) {
   map.data.overrideStyle(event.feature, {fillColor: 'red'});
});

Call the revertStyle() method to remove all style overrides.

Style options

The options available for styling each feature depend upon the feature type. For example, fillColor will only render on polygon geometries, while icon will only appear on a point geometry. More information is available in the reference documentation for StyleOptions.

Available on all geometries

  • clickable: If true, the feature receives mouse and touch events
  • visible: If true, the feature is visible.
  • zIndex: All features are displayed on the map in order of their zIndex, with higher values displaying in front of features with lower values. Markers are always displayed in front of line-strings and polygons.

Available on point geometries

  • cursor: Mouse cursor to show on hover.
  • icon: Icon to show for the point geometry.
  • shape: Defines the image map used for hit detection.
  • title: Rollover text.

Available on line geometries

  • strokeColor: The stroke color. All CSS3 colors are supported except for extended named colors.
  • strokeOpacity: The stroke opacity between 0.0 and 1.0.
  • strokeWeight: The stroke width in pixels.

Available on polygon geometries

  • fillColor: The fill color. All CSS3 colors are supported except for extended named colors.
  • fillOpacity: The fill opacity between 0.0 and 1.0.
  • strokeColor: The stroke color. All CSS3 colors are supported except for extended named colors.
  • strokeOpacity: The stroke opacity between 0.0 and 1.0.
  • strokeWeight: The stroke width in pixels.

Add Event Handlers

Features respond to events, such as mouseup or mousedown. You can add event listeners to allow users to interact with the data on the map. In the below example, we add a mouseover event, that displays information about the feature under the mouse cursor.

// Set mouseover event for each feature.
map.data.addListener('mouseover', function(event) {
  document.getElementById('info-box').textContent =
      event.feature.getProperty('letter');
});

Data layer events

The following events are common to all features, regardless of their geometry type:

  • addfeature
  • click
  • dblclick
  • mousedown
  • mouseout
  • mouseover
  • mouseup
  • removefeature
  • removeproperty
  • rightclick
  • setgeometry
  • setproperty

More information about these events can be found in the reference documentation for the google.maps.data class.

Change Appearance Dynamically

You can set the style of the Data layer by passing a function that computes the style of each feature to the google.maps.data.setStyle() method. This function will be called each time a feature’s properties are updated.

In the below example, we add an event listener for the click event that updates the feature’s isColorful property. The feature styling is updated to reflect the change as soon as the property is set.

// Color each letter gray. Change the color when the isColorful property
// is set to true.
map.data.setStyle(function(feature) {
  var color = 'gray';
  if (feature.getProperty('isColorful')) {
    color = feature.getProperty('color');
  }
  return /** @type {!google.maps.Data.StyleOptions} */({
    fillColor: color,
    strokeColor: color,
    strokeWeight: 2
  });
});

// When the user clicks, set 'isColorful', changing the color of the letters.
map.data.addListener('click', function(event) {
  event.feature.setProperty('isColorful', true);
});

// When the user hovers, tempt them to click by outlining the letters.
// Call revertStyle() to remove all overrides. This will use the style rules
// defined in the function passed to setStyle()
map.data.addListener('mouseover', function(event) {
  map.data.revertStyle();
  map.data.overrideStyle(event.feature, {strokeWeight: 8});
});

map.data.addListener('mouseout', function(event) {
  map.data.revertStyle();
});