Combina y visualiza varias fuentes de datos

Descripción general

En este instructivo, se explica cómo mostrar datos de varias fuentes en un mapa de Google Maps. A modo de ejemplo, en el siguiente mapa de coropletas, se usan dos fuentes diferentes para destacar varios estados de EE.UU. y mostrar los datos específicos de cada estado.

El mapa usa datos de un archivo GeoJSON para mostrar los polígonos que definen los límites de los estados de EE.UU. También puede presentar datos correspondientes a cada estado, que provienen de una consulta simulada a la API del censo de EE.UU.

Selecciona una categoría de datos del menú desplegable del control para actualizar los polígonos en el mapa. También puedes colocar el cursor sobre el polígono de un estado para ver información específica de este estado en un control de cuadro de datos en el mapa.

En el siguiente ejemplo, se muestra el código completo que necesitas para crear este mapa.

TypeScript

const mapStyle: google.maps.MapTypeStyle[] = [
  {
    stylers: [{ visibility: "off" }],
  },
  {
    featureType: "landscape",
    elementType: "geometry",
    stylers: [{ visibility: "on" }, { color: "#fcfcfc" }],
  },
  {
    featureType: "water",
    elementType: "geometry",
    stylers: [{ visibility: "on" }, { color: "#bfd4ff" }],
  },
];
let map: google.maps.Map;

let censusMin = Number.MAX_VALUE,
  censusMax = -Number.MAX_VALUE;

function initMap(): void {
  // load the map
  map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
    center: { lat: 40, lng: -100 },
    zoom: 4,
    styles: mapStyle,
  });

  // set up the style rules and events for google.maps.Data
  map.data.setStyle(styleFeature);
  map.data.addListener("mouseover", mouseInToRegion);
  map.data.addListener("mouseout", mouseOutOfRegion);

  // wire up the button
  const selectBox = document.getElementById(
    "census-variable"
  ) as HTMLSelectElement;

  google.maps.event.addDomListener(selectBox, "change", () => {
    clearCensusData();
    loadCensusData(selectBox.options[selectBox.selectedIndex].value);
  });

  // state polygons only need to be loaded once, do them now
  loadMapShapes();
}

/** Loads the state boundary polygons from a GeoJSON source. */
function loadMapShapes() {
  // load US state outline polygons from a GeoJson file
  map.data.loadGeoJson(
    "https://storage.googleapis.com/mapsdevsite/json/states.js",
    { idPropertyName: "STATE" }
  );

  // wait for the request to complete by listening for the first feature to be
  // added
  google.maps.event.addListenerOnce(map.data, "addfeature", () => {
    google.maps.event.trigger(
      document.getElementById("census-variable") as HTMLElement,
      "change"
    );
  });
}

/**
 * Loads the census data from a simulated API call to the US Census API.
 *
 * @param {string} variable
 */
function loadCensusData(variable: string) {
  // load the requested variable from the census API (using local copies)
  const xhr = new XMLHttpRequest();

  xhr.open("GET", variable + ".json");

  xhr.onload = function () {
    const censusData = JSON.parse(xhr.responseText) as any;

    censusData.shift(); // the first row contains column names
    censusData.forEach((row: string) => {
      const censusVariable = parseFloat(row[0]);
      const stateId = row[1];

      // keep track of min and max values
      if (censusVariable < censusMin) {
        censusMin = censusVariable;
      }

      if (censusVariable > censusMax) {
        censusMax = censusVariable;
      }

      const state = map.data.getFeatureById(stateId);

      // update the existing row with the new data
      if (state) {
        state.setProperty("census_variable", censusVariable);
      }
    });

    // update and display the legend
    (document.getElementById("census-min") as HTMLElement).textContent =
      censusMin.toLocaleString();
    (document.getElementById("census-max") as HTMLElement).textContent =
      censusMax.toLocaleString();
  };

  xhr.send();
}

/** Removes census data from each shape on the map and resets the UI. */
function clearCensusData() {
  censusMin = Number.MAX_VALUE;
  censusMax = -Number.MAX_VALUE;
  map.data.forEach((row) => {
    row.setProperty("census_variable", undefined);
  });
  (document.getElementById("data-box") as HTMLElement).style.display = "none";
  (document.getElementById("data-caret") as HTMLElement).style.display = "none";
}

/**
 * Applies a gradient style based on the 'census_variable' column.
 * This is the callback passed to data.setStyle() and is called for each row in
 * the data set.  Check out the docs for Data.StylingFunction.
 *
 * @param {google.maps.Data.Feature} feature
 */
function styleFeature(feature: google.maps.Data.Feature) {
  const low = [5, 69, 54]; // color of smallest datum
  const high = [151, 83, 34]; // color of largest datum

  let censusVariable = feature.getProperty("census_variable") as number;

  // delta represents where the value sits between the min and max
  const delta =
    (censusVariable - censusMin) /
    (censusMax - censusMin);

  const color: number[] = [];

  for (let i = 0; i < 3; i++) {
    // calculate an integer color based on the delta
    color.push((high[i] - low[i]) * delta + low[i]);
  }

  // determine whether to show this shape or not
  let showRow = true;

  if (
    censusVariable == null ||
    isNaN(censusVariable)
  ) {
    showRow = false;
  }

  let outlineWeight = 0.5,
    zIndex = 1;

  if (feature.getProperty("state") === "hover") {
    outlineWeight = zIndex = 2;
  }

  return {
    strokeWeight: outlineWeight,
    strokeColor: "#fff",
    zIndex: zIndex,
    fillColor: "hsl(" + color[0] + "," + color[1] + "%," + color[2] + "%)",
    fillOpacity: 0.75,
    visible: showRow,
  };
}

/**
 * Responds to the mouse-in event on a map shape (state).
 *
 * @param {?google.maps.MapMouseEvent} e
 */
function mouseInToRegion(e: any) {
  // set the hover state so the setStyle function can change the border
  e.feature.setProperty("state", "hover");

  const percent =
    ((e.feature.getProperty("census_variable") - censusMin) /
      (censusMax - censusMin)) *
    100;

  // update the label
  (document.getElementById("data-label") as HTMLElement).textContent =
    e.feature.getProperty("NAME");
  (document.getElementById("data-value") as HTMLElement).textContent = e.feature
    .getProperty("census_variable")
    .toLocaleString();
  (document.getElementById("data-box") as HTMLElement).style.display = "block";
  (document.getElementById("data-caret") as HTMLElement).style.display =
    "block";
  (document.getElementById("data-caret") as HTMLElement).style.paddingLeft =
    percent + "%";
}

/**
 * Responds to the mouse-out event on a map shape (state).
 *
 */
function mouseOutOfRegion(e: any) {
  // reset the hover state, returning the border to normal
  e.feature.setProperty("state", "normal");
}

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

JavaScript

const mapStyle = [
  {
    stylers: [{ visibility: "off" }],
  },
  {
    featureType: "landscape",
    elementType: "geometry",
    stylers: [{ visibility: "on" }, { color: "#fcfcfc" }],
  },
  {
    featureType: "water",
    elementType: "geometry",
    stylers: [{ visibility: "on" }, { color: "#bfd4ff" }],
  },
];
let map;
let censusMin = Number.MAX_VALUE,
  censusMax = -Number.MAX_VALUE;

function initMap() {
  // load the map
  map = new google.maps.Map(document.getElementById("map"), {
    center: { lat: 40, lng: -100 },
    zoom: 4,
    styles: mapStyle,
  });
  // set up the style rules and events for google.maps.Data
  map.data.setStyle(styleFeature);
  map.data.addListener("mouseover", mouseInToRegion);
  map.data.addListener("mouseout", mouseOutOfRegion);

  // wire up the button
  const selectBox = document.getElementById("census-variable");

  google.maps.event.addDomListener(selectBox, "change", () => {
    clearCensusData();
    loadCensusData(selectBox.options[selectBox.selectedIndex].value);
  });
  // state polygons only need to be loaded once, do them now
  loadMapShapes();
}

/** Loads the state boundary polygons from a GeoJSON source. */
function loadMapShapes() {
  // load US state outline polygons from a GeoJson file
  map.data.loadGeoJson(
    "https://storage.googleapis.com/mapsdevsite/json/states.js",
    { idPropertyName: "STATE" },
  );
  // wait for the request to complete by listening for the first feature to be
  // added
  google.maps.event.addListenerOnce(map.data, "addfeature", () => {
    google.maps.event.trigger(
      document.getElementById("census-variable"),
      "change",
    );
  });
}

/**
 * Loads the census data from a simulated API call to the US Census API.
 *
 * @param {string} variable
 */
function loadCensusData(variable) {
  // load the requested variable from the census API (using local copies)
  const xhr = new XMLHttpRequest();

  xhr.open("GET", variable + ".json");
  xhr.onload = function () {
    const censusData = JSON.parse(xhr.responseText);

    censusData.shift(); // the first row contains column names
    censusData.forEach((row) => {
      const censusVariable = parseFloat(row[0]);
      const stateId = row[1];

      // keep track of min and max values
      if (censusVariable < censusMin) {
        censusMin = censusVariable;
      }

      if (censusVariable > censusMax) {
        censusMax = censusVariable;
      }

      const state = map.data.getFeatureById(stateId);

      // update the existing row with the new data
      if (state) {
        state.setProperty("census_variable", censusVariable);
      }
    });
    // update and display the legend
    document.getElementById("census-min").textContent =
      censusMin.toLocaleString();
    document.getElementById("census-max").textContent =
      censusMax.toLocaleString();
  };

  xhr.send();
}

/** Removes census data from each shape on the map and resets the UI. */
function clearCensusData() {
  censusMin = Number.MAX_VALUE;
  censusMax = -Number.MAX_VALUE;
  map.data.forEach((row) => {
    row.setProperty("census_variable", undefined);
  });
  document.getElementById("data-box").style.display = "none";
  document.getElementById("data-caret").style.display = "none";
}

/**
 * Applies a gradient style based on the 'census_variable' column.
 * This is the callback passed to data.setStyle() and is called for each row in
 * the data set.  Check out the docs for Data.StylingFunction.
 *
 * @param {google.maps.Data.Feature} feature
 */
function styleFeature(feature) {
  const low = [5, 69, 54]; // color of smallest datum
  const high = [151, 83, 34]; // color of largest datum
  let censusVariable = feature.getProperty("census_variable");
  // delta represents where the value sits between the min and max
  const delta = (censusVariable - censusMin) / (censusMax - censusMin);
  const color = [];

  for (let i = 0; i < 3; i++) {
    // calculate an integer color based on the delta
    color.push((high[i] - low[i]) * delta + low[i]);
  }

  // determine whether to show this shape or not
  let showRow = true;

  if (censusVariable == null || isNaN(censusVariable)) {
    showRow = false;
  }

  let outlineWeight = 0.5,
    zIndex = 1;

  if (feature.getProperty("state") === "hover") {
    outlineWeight = zIndex = 2;
  }
  return {
    strokeWeight: outlineWeight,
    strokeColor: "#fff",
    zIndex: zIndex,
    fillColor: "hsl(" + color[0] + "," + color[1] + "%," + color[2] + "%)",
    fillOpacity: 0.75,
    visible: showRow,
  };
}

/**
 * Responds to the mouse-in event on a map shape (state).
 *
 * @param {?google.maps.MapMouseEvent} e
 */
function mouseInToRegion(e) {
  // set the hover state so the setStyle function can change the border
  e.feature.setProperty("state", "hover");

  const percent =
    ((e.feature.getProperty("census_variable") - censusMin) /
      (censusMax - censusMin)) *
    100;

  // update the label
  document.getElementById("data-label").textContent =
    e.feature.getProperty("NAME");
  document.getElementById("data-value").textContent = e.feature
    .getProperty("census_variable")
    .toLocaleString();
  document.getElementById("data-box").style.display = "block";
  document.getElementById("data-caret").style.display = "block";
  document.getElementById("data-caret").style.paddingLeft = percent + "%";
}

/**
 * Responds to the mouse-out event on a map shape (state).
 *
 */
function mouseOutOfRegion(e) {
  // reset the hover state, returning the border to normal
  e.feature.setProperty("state", "normal");
}

window.initMap = initMap;

CSS

html,
body,
#map {
  height: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.nicebox {
  position: absolute;
  text-align: center;
  font-family: "Roboto", "Arial", sans-serif;
  font-size: 13px;
  z-index: 5;
  box-shadow: 0 4px 6px -4px #333;
  padding: 5px 10px;
  background: rgb(255, 255, 255);
  background: linear-gradient(to bottom, rgb(255, 255, 255) 0%, rgb(245, 245, 245) 100%);
  border: rgb(229, 229, 229) 1px solid;
}

#controls {
  top: 10px;
  left: 110px;
  width: 360px;
  height: 45px;
}

#data-box {
  top: 10px;
  left: 500px;
  height: 45px;
  line-height: 45px;
  display: none;
}

#census-variable {
  width: 360px;
  height: 20px;
}

#legend {
  display: flex;
  display: -webkit-box;
  padding-top: 7px;
}

.color-key {
  background: linear-gradient(to right, hsl(5, 69%, 54%) 0%, hsl(29, 71%, 51%) 17%, hsl(54, 74%, 47%) 33%, hsl(78, 76%, 44%) 50%, hsl(102, 78%, 41%) 67%, hsl(127, 81%, 37%) 83%, hsl(151, 83%, 34%) 100%);
  flex: 1;
  -webkit-box-flex: 1;
  margin: 0 5px;
  text-align: left;
  font-size: 1em;
  line-height: 1em;
}

#data-value {
  font-size: 2em;
  font-weight: bold;
}

#data-label {
  font-size: 2em;
  font-weight: normal;
  padding-right: 10px;
}

#data-label:after {
  content: ":";
}

#data-caret {
  margin-left: -5px;
  display: none;
  font-size: 14px;
  width: 14px;
}

HTML

<html>
  <head>
    <title>Mashups with google.maps.Data</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="controls" class="nicebox">
      <div>
        <select id="census-variable">
          <option
            value="https://storage.googleapis.com/mapsdevsite/json/DP02_0066PE"
          >
            Percent of population over 25 that completed high school
          </option>
          <option
            value="https://storage.googleapis.com/mapsdevsite/json/DP05_0017E"
          >
            Median age
          </option>
          <option
            value="https://storage.googleapis.com/mapsdevsite/json/DP05_0001E"
          >
            Total population
          </option>
          <option
            value="https://storage.googleapis.com/mapsdevsite/json/DP02_0016E"
          >
            Average family size
          </option>
          <option
            value="https://storage.googleapis.com/mapsdevsite/json/DP03_0088E"
          >
            Per-capita income
          </option>
        </select>
      </div>
      <div id="legend">
        <div id="census-min">min</div>
        <div class="color-key"><span id="data-caret">&#x25c6;</span></div>
        <div id="census-max">max</div>
      </div>
    </div>
    <div id="data-box" class="nicebox">
      <label id="data-label" for="data-value"></label>
      <span id="data-value"></span>
    </div>
    <div id="map"></div>

    <!-- 
      The `defer` attribute causes the script to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises. See
      https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>

Prueba la muestra

Primeros pasos

Puedes desarrollar tu propia versión de este mapa de coropletas con el código que se indica en este instructivo. Para comenzar, crea un archivo nuevo en un editor de texto y guárdalo como index.html.

Lee las secciones que se incluyen a continuación para comprender el código que puedes agregar a este archivo.

Cómo crear un mapa básico

En esta sección, se explica el código con el que se puede configurar un mapa básico. Posiblemente sea similar al que usaste para crear mapas cuando comenzaste a usar la API de Maps JavaScript.

Copia el siguiente código en tu archivo index.html. Este código carga la API de Maps JavaScript y permite visualizar el mapa en pantalla completa.

<!DOCTYPE html>
<html>
  <head>
  <meta charset="utf-8">
      <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
      <title>Mashups with google.maps.Data</title>
      <style>
        #map {
          height: 100%;
        }
        /* Optional: Makes the sample page fill the window. */
        html, body {
          height: 100%;
          margin: 0;
          padding: 0;
        }
      </style>
  </head>
  <body>
    <div id="map"></div>
    <script>
      function initMap() {

        // load the map
        map = new google.maps.Map(document.getElementById('map'), {
          center: {lat: 40, lng: -100},
          zoom: 4,
          styles: mapStyle
        });

        var mapStyle = [{
          'featureType': 'all',
          'elementType': 'all',
          'stylers': [{'visibility': 'off'}]
        }, {
          'featureType': 'landscape',
          'elementType': 'geometry',
          'stylers': [{'visibility': 'on'}, {'color': '#fcfcfc'}]
        }, {
          'featureType': 'water',
          'elementType': 'labels',
          'stylers': [{'visibility': 'off'}]
        }, {
          'featureType': 'water',
          'elementType': 'geometry',
          'stylers': [{'visibility': 'on'}, {'hue': '#5f94ff'}, {'lightness': 60}]
        }];
      }

    </script>
    <script defer
        src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
    </script>
  </body>
</html>

El código de la primera etiqueta de la secuencia de comandos es el punto de partida que ejecuta el programa mediante la creación de una función llamada initMap que inicializa el objeto de mapa.

Los parámetros de diseño del código anterior desactivan la visibilidad de todos los featureTypes del mapa, como rutas, lugares de interés, paisajes, áreas administrativas y todos sus elementTypes. Si deseas obtener una lista de todos los valores disponibles para featureType y elementType, consulta la referencia de diseño JSON.

Haz clic en YOUR_API_KEY en la muestra de código o sigue las instrucciones para obtener una clave de API. Reemplaza YOUR_API_KEY por la clave de API de tu aplicación. Una vez que la API está completamente cargada, el parámetro de devolución de llamada de la etiqueta de la secuencia de comandos que aparece a continuación ejecuta la función initMap() en el archivo HTML.

<script> defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"
</script>

Cómo crear controles del mapa y definir su diseño

El código que se incluye a continuación crea los siguientes controles en el mapa:

  • Un control con un menú desplegable que tiene 5 opciones de datos diferentes
  • Una leyenda del mapa
  • Un cuadro de datos que muestra datos específicos del estado que aparece cuando colocas el cursor sobre un polígono
<div id="controls" class="nicebox">
  <div>
  <select id="census-variable">
    <option value="https://storage.googleapis.com/mapsdevsite/json/DP02_0066PE">Percent of population over 25 that completed high
    school</option>
    <option value="https://storage.googleapis.com/mapsdevsite/json/DP05_0017E">Median age</option>
    <option value="https://storage.googleapis.com/mapsdevsite/json/DP05_0001E">Total population</option>
    <option value="https://storage.googleapis.com/mapsdevsite/json/DP02_0016E">Average family size</option>
    <option value="https://storage.googleapis.com/mapsdevsite/json/DP03_0088E">Per-capita income</option>
  </select>
  </div>
  <div id="legend">
    <div id="census-min">min</div>
    <div class="color-key"><span id="data-caret">&#x25c6;</span></div>
    <div id="census-max">max</div>
  </div>
</div>
<div id="data-box" class="nicebox">
  <label id="data-label" for="data-value"></label>
  <span id="data-value"></span>
</div>

Usa el siguiente código en las etiquetas style para definir el diseño de los controles del mapa.

<style>
  html, body, #map { height: 100%; margin: 0; padding: 0; overflow: hidden; }
    .nicebox {
      position: absolute;
      text-align: center;
      font-family: "Roboto", "Arial", sans-serif;
      font-size: 13px;
      z-index: 5;
      box-shadow: 0 4px 6px -4px #333;
      padding: 5px 10px;
      background: rgb(255,255,255);
      background: linear-gradient(to bottom,rgba(255,255,255,1) 0%,rgba(245,245,245,1) 100%);
      border: rgb(229, 229, 229) 1px solid;
    }
    #controls {
      top: 10px;
      left: 110px;
      width: 360px;
      height: 45px;
    }
    #data-box {
      top: 10px;
      left: 500px;
      height: 45px;
      line-height: 45px;
      display: none;
    }
    #census-variable {
      width: 360px;
      height: 20px;
    }
    #legend { display: flex; display: -webkit-box; padding-top: 7px }
    .color-key {
      background: linear-gradient(to right,
        hsl(5, 69%, 54%) 0%,
        hsl(29, 71%, 51%) 17%,
        hsl(54, 74%, 47%) 33%,
        hsl(78, 76%, 44%) 50%,
        hsl(102, 78%, 41%) 67%,
        hsl(127, 81%, 37%) 83%,
        hsl(151, 83%, 34%) 100%);
      flex: 1;
      -webkit-box-flex: 1;
      margin: 0 5px;
      text-align: left;
      font-size: 1.0em;
      line-height: 1.0em;
    }
    #data-value { font-size: 2.0em; font-weight: bold }
    #data-label { font-size: 2.0em; font-weight: normal; padding-right: 10px; }
    #data-label:after { content: ':' }
    #data-caret { margin-left: -5px; display: none; font-size: 14px; width: 14px}
</style>

Cómo importar datos de la API del censo de EE.UU.

El siguiente código envía una consulta a la Oficina del Censo de EE.UU. para obtener los datos del censo más reciente de todos los estados del país, los cuales recibe en formato JSON.

function loadCensusData(variable) {
// load the requested variable from the census API
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://api.census.gov/data/2012/acs5/profile?get=' +
  variable + '&for=state:*&key=YOUR_API_KEY');
        xhr.onload = function() {
          var censusData = JSON.parse(xhr.responseText);
          censusData.shift(); // the first row contains column names
          censusData.forEach(function(row) {
            var censusVariable = parseFloat(row[0]);
            var stateId = row[1];

            // keep track of min and max values
            if (censusVariable < censusMin) {
              censusMin = censusVariable;
            }
            if (censusVariable > censusMax) {
              censusMax = censusVariable;
            }

            // update the existing row with the new data
            map.data
              .getFeatureById(stateId)
              .setProperty('census_variable', censusVariable);
          });

          // update and display the legend
          document.getElementById('census-min').textContent =
              censusMin.toLocaleString();
          document.getElementById('census-max').textContent =
              censusMax.toLocaleString();
        };
        xhr.send();
}

Cómo definir el diseño de los datos

El siguiente código crea el mapa de coropletas mediante la aplicación de un gradiente a cada polígono del conjunto de datos, según el valor de los datos del censo. Puedes definir el diseño de los datos con un objeto Data.StyleOptions o una función que muestre un objeto Data.StyleOptions.

// set up the style rules and events for google.maps.Data
map.data.setStyle(styleFeature);

      function styleFeature(feature) {
        var low = [5, 69, 54];  // color of smallest datum
        var high = [151, 83, 34];   // color of largest datum

        // delta represents where the value sits between the min and max
        var delta = (feature.getProperty('census_variable') - censusMin) /
            (censusMax - censusMin);

        var color = [];
        for (var i = 0; i < 3; i++) {
          // calculate an integer color based on the delta
          color[i] = (high[i] - low[i]) * delta + low[i];
        }

        // determine whether to show this shape or not
        var showRow = true;
        if (feature.getProperty('census_variable') == null ||
            isNaN(feature.getProperty('census_variable'))) {
          showRow = false;
        }

        var outlineWeight = 0.5, zIndex = 1;
        if (feature.getProperty('state') === 'hover') {
          outlineWeight = zIndex = 2;
        }

        return {
          strokeWeight: outlineWeight,
          strokeColor: '#fff',
          zIndex: zIndex,
          fillColor: 'hsl(' + color[0] + ',' + color[1] + '%,' + color[2] + '%)',
          fillOpacity: 0.75,
          visible: showRow
        };
      }

Además de colorear los polígonos, el siguiente código crea un elemento interactivo agregando eventos que responden a la actividad del mouse. Cuando se coloca el cursor sobre un polígono, se destaca la frontera del estado y, al mismo tiempo, se actualiza el control del cuadro de datos en el mapa.

// set up the style rules and events for google.maps.Data
map.data.addListener('mouseover', mouseInToRegion);
map.data.addListener('mouseout', mouseOutOfRegion);

      /**
       * Responds to the mouse-in event on a map shape (state).
       *
       * @param {?google.maps.MapMouseEvent} e
       */
      function mouseInToRegion(e) {
        // set the hover state so the setStyle function can change the border
        e.feature.setProperty('state', 'hover');

        var percent = (e.feature.getProperty('census_variable') - censusMin) /
            (censusMax - censusMin) * 100;

        // update the label
        document.getElementById('data-label').textContent =
            e.feature.getProperty('NAME');
        document.getElementById('data-value').textContent =
            e.feature.getProperty('census_variable').toLocaleString();
        document.getElementById('data-box').style.display = 'block';
        document.getElementById('data-caret').style.display = 'block';
        document.getElementById('data-caret').style.paddingLeft = percent + '%';
      }

      /**
       * Responds to the mouse-out event on a map shape (state).
       *
       * @param {?google.maps.MapMouseEvent} e
       */
      function mouseOutOfRegion(e) {
        // reset the hover state, returning the border to normal
        e.feature.setProperty('state', 'normal');
      }

Cómo cargar los polígonos de límites de estados

Agrega el siguiente código después de toda la función initMap. La función loadMapShapes carga los polígonos de los límites de los estados de EE.UU. desde un archivo GeoJSON mediante el método loadGeoJson.

/** Loads the state boundary polygons from a GeoJSON source. */
function loadMapShapes() {
  // load US state outline polygons from a GeoJSON file
  map.data.loadGeoJson('https://storage.googleapis.com/mapsdevsite/json/states.js', { idPropertyName: 'STATE' });

Agrega la siguiente línea al final de la función initMap.

  // state polygons only need to be loaded once, do them now
  loadMapShapes();

Al seleccionar una opción de fuente de datos en el menú desplegable del control del mapa, el mapa consulta la API de datos del censo de EE.UU. para obtener la variable especificada. Para conectar los datos del censo con los datos de la forma, el código establece idPropertyName como "STATE", que es una clave común tanto en los datos del censo como en las propiedades de GeoJSON.

Más información

Esta demostración usa la API de datos de la Oficina del Censo, pero no está avalada ni certificada por dicho organismo.