Eventos

Selecciona la plataforma: Android iOS JavaScript

En esta página, se describen los eventos de interfaz de usuario y de error que puedes escuchar y manejar de forma programática.

Eventos de interfaz de usuario

En el navegador, JavaScript se controla mediante eventos, lo que significa que responde a interacciones mediante la generación de eventos y espera que un programa escuche los eventos interesantes. Existen dos tipos de eventos:

  • Los eventos de usuario (como los eventos de "clic" del mouse) se propagan del DOM a la API de Maps JavaScript. Estos eventos son independientes y diferentes de los eventos estándares del DOM.
  • Las notificaciones de cambio de estado de MVC reflejan cambios en los objetos de la API de Maps JavaScript y se nombran mediante una convención property_changed.

Cada objeto de la API de Maps JavaScript exporta una cantidad determinada de eventos con nombre. Los programas interesados en ciertos eventos llaman a addListener() para registrar controladores de evento en el objeto mediante objetos de escucha de JavaScript y ejecutan código cuando tales eventos se reciben.

En el siguiente ejemplo, se muestra cuáles son los eventos que google.maps.Map activa cuando interactúas con el mapa.

Para obtener una lista completa de eventos, consulta la referencia de la API de Maps JavaScript. Los eventos se incluyen en una sección separada para cada objeto que contiene eventos.

Eventos de la IU

Algunos objetos de la API de Maps JavaScript están diseñados para responder a los eventos de los usuarios, como los eventos de mouse o de teclado. Por ejemplo, estos son algunos de los eventos de usuario que un objeto google.maps.marker.AdvancedMarkerElement puede escuchar:

  • 'click'
  • 'drag'
  • 'dragend'
  • 'dragstart'
  • 'gmp-click'

Para ver la lista completa, consulta la clase AdvancedMarkerElement. Estos eventos pueden parecer eventos de DOM estándares, pero en realidad forman parte de la API de Maps JavaScript. Dado que los distintos navegadores implementan diferentes modelos de eventos de DOM, la API de Maps JavaScript proporciona estos mecanismos para escuchar los eventos de DOM y responder a ellos sin necesidad de administrar las diversas peculiaridades de los distintos navegadores. Por lo general, estos eventos, también pasan argumentos dentro del evento en los que se menciona algún estado de IU (como la posición del mouse).

Cambios de estado de MVC

Los objetos de MVC normalmente contienen estados. Cuando cambia la propiedad de un objeto, la API de Maps JavaScript activa un evento que indica que la propiedad cambió. Por ejemplo, la API activará un evento zoom_changed en un mapa cuando cambie el nivel de zoom correspondiente. Puedes interceptar estos cambios de estado llamando a addListener() para registrar también los controladores de eventos en el objeto.

Los eventos de usuario y los cambios de estado de MVC pueden parecerse, pero, por lo general, es conveniente darles un tratamiento diferente en el código. Los eventos de MVC, por ejemplo, no pasan argumentos dentro de su evento. Te recomendamos llamar al método getProperty que corresponda en ese objeto para inspeccionar la propiedad que se modificó a causa de un cambio de estado de MVC.

Cómo controlar eventos

Si deseas registrarte para recibir notificaciones de eventos, usa el controlador de eventos addListener(). Este método establece un evento que debe escucharse y una función a la que se debe llamar cuando ocurre el evento especificado.

Ejemplo: eventos de mapas y marcadores

En el siguiente código, se combinan eventos de usuario y eventos de cambio de estado. Para ello, se adjunta un controlador de eventos a un marcador que aplica zoom al mapa cuando se hace clic sobre él. A su vez, se agrega un controlador de eventos al mapa para realizar cambios en la propiedad center y desplazar el mapa nuevamente al marcador después de 3 segundos de recibir el evento center_changed:

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  const myLatlng = { lat: -25.363, lng: 131.044 };

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: myLatlng,
      mapId: "DEMO_MAP_ID",
    }
  );

  const marker = new google.maps.marker.AdvancedMarkerElement({
    position: myLatlng,
    map,
    title: "Click to zoom",
  });

  map.addListener("center_changed", () => {
    // 3 seconds after the center of the map has changed, pan back to the
    // marker.
    window.setTimeout(() => {
      map.panTo(marker.position as google.maps.LatLng);
    }, 3000);
  });

  marker.addListener("click", () => {
    map.setZoom(8);
    map.setCenter(marker.position as google.maps.LatLng);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const myLatlng = { lat: -25.363, lng: 131.044 };
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: myLatlng,
    mapId: "DEMO_MAP_ID",
  });
  const marker = new google.maps.marker.AdvancedMarkerElement({
    position: myLatlng,
    map,
    title: "Click to zoom",
  });

  map.addListener("center_changed", () => {
    // 3 seconds after the center of the map has changed, pan back to the
    // marker.
    window.setTimeout(() => {
      map.panTo(marker.position);
    }, 3000);
  });
  marker.addListener("click", () => {
    map.setZoom(8);
    map.setCenter(marker.position);
  });
}

initMap();
Ver ejemplo

Prueba la muestra

Sugerencia: Si intentas detectar un cambio en el viewport, asegúrate de usar el evento bounds_changed específico, en lugar de los eventos constitutivos zoom_changed y center_changed. Dado que la API de Maps JavaScript activa estos últimos eventos de forma independiente, es posible que getBounds() no informe resultados útiles hasta después de que el viewport cambie de manera autoritaria. Si deseas usar getBounds() después de un evento de este tipo, asegúrate de escuchar el evento bounds_changed.

Ejemplo: eventos de edición y arrastre de formas

Cuando se edita o se arrastra una forma, se activa un evento al completarse la acción. Para obtener una lista de los eventos y algunos fragmentos de código, consulta Formas.

Aquí puedes ver un ejemplo (rectangle-event.html).

Cómo acceder a los argumentos en los eventos de la IU

Por lo general, los eventos de la IU de la API de Maps JavaScript pasan un argumento de evento, al que puede acceder el objeto de escucha de eventos y detectar el estado de la IU cuando ocurrió el evento. Por ejemplo, un evento 'click' de IU suele pasar un MouseEvent que contiene una propiedad latLng que denota la ubicación en la que se hizo clic en el mapa. Ten en cuenta que este comportamiento es exclusivo de los eventos de la IU. Los cambios de estado de MVC no pasan argumentos en sus eventos.

Puedes acceder a los argumentos del evento dentro de un objeto de escucha de eventos de la misma manera en que accederías a las propiedades un objeto. En el siguiente ejemplo, se agrega un objeto de escucha de eventos para el mapa y se crea un marcador cuando el usuario hace clic en la ubicación seleccionada en el mapa.

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: -25.363882, lng: 131.044922 },
      mapId: "DEMO_MAP_ID",
    }
  );

  map.addListener("click", (e) => {
    placeMarkerAndPanTo(e.latLng, map);
  });
}

function placeMarkerAndPanTo(latLng: google.maps.LatLng, map: google.maps.Map) {
  new google.maps.marker.AdvancedMarkerElement({
    position: latLng,
    map: map,
  });
  map.panTo(latLng);
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement, PinElement } = await google.maps.importLibrary(
    "marker",
  );
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -25.363882, lng: 131.044922 },
    mapId: "DEMO_MAP_ID",
  });

  map.addListener("click", (e) => {
    placeMarkerAndPanTo(e.latLng, map);
  });
}

function placeMarkerAndPanTo(latLng, map) {
  new google.maps.marker.AdvancedMarkerElement({
    position: latLng,
    map: map,
  });
  map.panTo(latLng);
}

initMap();
Ver ejemplo

Prueba la muestra

Cómo usar cierres en los objetos de escucha de eventos

Cuando se ejecuta un objeto de escucha de eventos, suele ser conveniente adjuntar tanto datos privados como persistentes a un objeto. JavaScript no admite los datos de instancias "privados", pero sí admite cierres, los cuales permiten que las funciones internas accedan a variables externas. Los cierres son útiles en los objetos de escucha de eventos, ya que permiten acceder a variables que normalmente no se adjuntan a los objetos en los que ocurren los eventos.

En el siguiente ejemplo, se usa un cierre de función en el objeto de escucha de eventos para asignar un mensaje secreto a un conjunto de marcadores. Al hacer clic en cada marcador, se muestra una parte del mensaje secreto, que no es parte del marcador.

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker") as google.maps.MarkerLibrary;

  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: -25.363882, lng: 131.044922 },
      mapId: "DEMO_MAP_ID",
    }
  );

  const bounds: google.maps.LatLngBoundsLiteral = {
    north: -25.363882,
    south: -31.203405,
    east: 131.044922,
    west: 125.244141,
  };

  // Display the area between the location southWest and northEast.
  map.fitBounds(bounds);

  // Add 5 markers to map at random locations.
  // For each of these markers, give them a title with their index, and when
  // they are clicked they should open an infowindow with text from a secret
  // message.
  const secretMessages = ["This", "is", "the", "secret", "message"];
  const lngSpan = bounds.east - bounds.west;
  const latSpan = bounds.north - bounds.south;

  for (let i = 0; i < secretMessages.length; ++i) {
    const marker = new google.maps.marker.AdvancedMarkerElement({
      position: {
        lat: bounds.south + latSpan * Math.random(),
        lng: bounds.west + lngSpan * Math.random(),
      },
      map: map,
    });

    attachSecretMessage(marker, secretMessages[i]);
  }
}

// Attaches an info window to a marker with the provided message. When the
// marker is clicked, the info window will open with the secret message.
function attachSecretMessage(
  marker: google.maps.marker.AdvancedMarkerElement,
  secretMessage: string
) {
  const infowindow = new google.maps.InfoWindow({
    content: secretMessage,
  });

  marker.addListener("click", () => {
    infowindow.open(marker.map, marker);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const { AdvancedMarkerElement } = await google.maps.importLibrary("marker");
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: -25.363882, lng: 131.044922 },
    mapId: "DEMO_MAP_ID",
  });
  const bounds = {
    north: -25.363882,
    south: -31.203405,
    east: 131.044922,
    west: 125.244141,
  };

  // Display the area between the location southWest and northEast.
  map.fitBounds(bounds);

  // Add 5 markers to map at random locations.
  // For each of these markers, give them a title with their index, and when
  // they are clicked they should open an infowindow with text from a secret
  // message.
  const secretMessages = ["This", "is", "the", "secret", "message"];
  const lngSpan = bounds.east - bounds.west;
  const latSpan = bounds.north - bounds.south;

  for (let i = 0; i < secretMessages.length; ++i) {
    const marker = new google.maps.marker.AdvancedMarkerElement({
      position: {
        lat: bounds.south + latSpan * Math.random(),
        lng: bounds.west + lngSpan * Math.random(),
      },
      map: map,
    });

    attachSecretMessage(marker, secretMessages[i]);
  }
}

// Attaches an info window to a marker with the provided message. When the
// marker is clicked, the info window will open with the secret message.
function attachSecretMessage(marker, secretMessage) {
  const infowindow = new google.maps.InfoWindow({
    content: secretMessage,
  });

  marker.addListener("click", () => {
    infowindow.open(marker.map, marker);
  });
}

initMap();
Ver ejemplo

Prueba la muestra

Cómo obtener y configurar propiedades en los controladores de eventos

Ninguno de los eventos de cambio de estado de MVC que corresponden al sistema de eventos de la API de Maps JavaScript pasa argumentos cuando se activa el evento. (Los eventos de usuario sí pasan argumentos que pueden inspeccionarse). Si necesitas inspeccionar una propiedad en un cambio de estado de MVC, debes llamar explícitamente al método getProperty() correcto en ese objeto. Esta inspección siempre recupera el estado actual del objeto MVC, que puede ser diferente del estado vigente cuando se activó el evento por primera vez.

Nota: Configurar explícitamente una propiedad dentro de un controlador de eventos que responde a un cambio de estado de esa propiedad en particular puede generar un comportamiento impredecible o no deseado. La configuración de dicha propiedad activará un nuevo evento, por ejemplo, y si siempre configuras una propiedad dentro de este controlador de eventos, podrías generar un bucle infinito.

En el siguiente ejemplo, se configura un controlador de eventos para responder a eventos de zoom mediante la aparición de una ventana de información en la que se muestra el nivel.

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;

  const originalMapCenter = new google.maps.LatLng(-25.363882, 131.044922);
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: originalMapCenter,
    }
  );

  const infowindow = new google.maps.InfoWindow({
    content: "Change the zoom level",
    position: originalMapCenter,
  });

  infowindow.open(map);

  map.addListener("zoom_changed", () => {
    infowindow.setContent("Zoom: " + map.getZoom()!);
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const originalMapCenter = new google.maps.LatLng(-25.363882, 131.044922);
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: originalMapCenter,
  });
  const infowindow = new google.maps.InfoWindow({
    content: "Change the zoom level",
    position: originalMapCenter,
  });

  infowindow.open(map);
  map.addListener("zoom_changed", () => {
    infowindow.setContent("Zoom: " + map.getZoom());
  });
}

initMap();
Ver ejemplo

Prueba la muestra

Cómo escuchar eventos del DOM

El modelo de eventos de la API de Maps JavaScript crea y administra sus propios eventos personalizados. Sin embargo, el DOM (Modelo de objetos del documento) del navegador también crea y despacha sus propios eventos según el modelo de eventos del navegador en uso. Si deseas capturar esos eventos y responder a ellos, la API de Maps JavaScript proporciona el método estático addDomListener() para escuchar eventos de DOM y vincularse a ellos.

Este método práctico tiene una firma, como se muestra a continuación:

addDomListener(instance:Object, eventName:string, handler:Function)

En el ejemplo anterior, instance puede ser cualquier elemento de DOM admitido por el navegador, incluidos los siguientes:

  • Miembros jerárquicos del DOM, como window o document.body.myform
  • Elementos con nombre, como document.getElementById("foo")

Ten en cuenta que addDomListener() pasa el evento indicado al navegador, el cual lo administra según el modelo de eventos de DOM del navegador. Sin embargo, casi todos los navegadores actualizados admiten al menos el nivel de DOM 2. (Para obtener más información sobre eventos de nivel de DOM, consulta la referencia de Niveles de DOM de Mozilla).

TypeScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;

  const mapDiv = document.getElementById("map") as HTMLElement;
  const map = new google.maps.Map(mapDiv, {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
  });

  // We add a DOM event here to show an alert if the DIV containing the
  // map is clicked.
  google.maps.event.addDomListener(mapDiv, "click", () => {
    window.alert("Map was clicked!");
  });
}

initMap();

JavaScript

async function initMap() {
  // Request needed libraries.
  const { Map } = await google.maps.importLibrary("maps");
  const mapDiv = document.getElementById("map");
  const map = new google.maps.Map(mapDiv, {
    zoom: 8,
    center: new google.maps.LatLng(-34.397, 150.644),
  });

  // We add a DOM event here to show an alert if the DIV containing the
  // map is clicked.
  google.maps.event.addDomListener(mapDiv, "click", () => {
    window.alert("Map was clicked!");
  });
}

initMap();

HTML

<html>
  <head>
    <title>Listening to DOM Events</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- prettier-ignore -->
    <script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
        ({key: "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", v: "weekly"});</script>
  </body>
</html>
Ver ejemplo

Prueba la muestra

Si bien el código anterior es el código de la API de Maps JavaScript, el método addDomListener() establece un enlace con el objeto window del navegador y permite que la API se comunique con objetos externos a su dominio normal.

Cómo quitar objetos de escucha de eventos

Para quitar un objeto de escucha de eventos específico, este debe estar asignado a una variable. Luego, puedes llamar a removeListener() y pasar el nombre de la variable a la que se asignó el objeto de escucha.

var listener1 = marker.addListener('click', aFunction);

google.maps.event.removeListener(listener1);

Para quitar todos los objetos de escucha de una instancia en particular, llama a clearInstanceListeners() y pasa el nombre de la instancia.

var listener1 = marker.addListener('click', aFunction);
var listener2 = marker.addListener('mouseover', bFunction);

// Remove listener1 and listener2 from marker instance.
google.maps.event.clearInstanceListeners(marker);

Para quitar todos los objetos de escucha de un tipo de evento específico correspondientes a una instancia específica, llama a clearListeners() y pasa el nombre de la instancia y el nombre del evento.

marker.addListener('click', aFunction);
marker.addListener('click', bFunction);
marker.addListener('click', cFunction);

// Remove all click listeners from marker instance.
google.maps.event.clearListeners(marker, 'click');

Si deseas obtener más información, consulta la documentación de referencia sobre el espacio de nombres google.maps.event.

Cómo detectar errores de autenticación

Si deseas detectar una autenticación no exitosa de forma programática (por ejemplo, para que se envíe una baliza automáticamente), puedes preparar una función de devolución de llamada. Si se define la siguiente función de forma global, se la llamará cuando falle la autenticación. function gm_authFailure() { /* Code */ };