このページでは、プログラムでリッスンして処理できるユーザー インターフェース イベントとエラーイベントについて説明します。
ユーザー インターフェース イベント
ブラウザ内の JavaScript は「イベント駆動型」です。つまり、JavaScript はイベントを生成することで操作に応答し、プログラムは目的のイベントを「リッスン」します。イベントには、以下の 2 つのタイプがあります。
- ユーザー イベント(マウスの「クリック」イベントなど)。DOM から Maps JavaScript API に伝達されます。このイベントは、標準の DOM イベントとは異なる無関係のイベントです。
- MVC の状態変化の通知は、Maps API オブジェクトの変化を反映しており、これには
property_changed
規則に基づいて名前が付けられています。
各 Maps JavaScript API オブジェクトは、多くの名前付きイベントをエクスポートします。プログラムが特定のイベントに関心がある場合、それらのイベントを受信できるように JavaScript のイベント リスナーを登録します。そして、オブジェクトで addListener()
を呼び出してイベント ハンドラを登録することで、これらのイベントを受信したときにコードが実行されるようにします。
以下のサンプルは、地図を操作すると google.maps.Map
によってどのイベントがトリガーされるのかを示します。
すべてのイベントの一覧については、Maps JavaScript API リファレンスをご覧ください。イベントの一覧は、イベントが属しているオブジェクトごとに収録されています。
UI イベント
Maps JavaScript API 内の一部のオブジェクトは、マウスイベントやキーボード イベントなどのユーザー イベントに応答するように設計されています。たとえば、google.maps.marker.AdvancedMarkerElement
オブジェクトがリッスンできるユーザー イベントの一例は次のとおりです。
'click'
'drag'
'dragend'
'dragstart'
'gmp-click'
すべてのリストについては、AdvancedMarkerElement クラスをご覧ください。これらのイベントは標準の DOM イベントに似ていますが、実際は Maps JavaScript API の一部です。ブラウザごとに実装している DOM イベントモデルは違うため、さまざまなクロスブラウザ特性に対応しなくても、DOM イベントをリスニングしたり、応答したりできる仕組みが Maps JavaScript API には備わっています。また、通常、これらのイベントは、UI 状態(マウスの位置など)を通知するイベントの中で引数を渡します。
MVC の状態変化
通常、MVC オブジェクトは状態を持ちます。オブジェクトのプロパティが変化すると、Maps JavaScript API はプロパティが変化したというイベントを呼び出します。たとえば、地図のズームレベルが変化すると、API は zoom_changed
イベントを呼び出します。これらの状態変化をインターセプトするには、オブジェクトで addListener()
を呼び出してイベント ハンドラを登録します。
ユーザー イベントと MVC 状態変化イベントは似ていますが、コード内では別々に扱うのが一般的です。たとえば、MVC イベント内では引数を渡しません。MVC の状態変化で変化したプロパティは、そのオブジェクトの適切な getProperty
メソッドを呼び出すことによって確認します。
イベントの処理
イベント通知の登録には、addListener()
イベント ハンドラを使用します。このメソッドは引数として、リスニングするイベントと、指定のイベントが発生した際に呼び出す関数を取ります。
例: 地図とマーカー イベント
次のコードには、ユーザー イベントと状態変化イベントの両方が含まれています。クリック時に地図をズームするマーカーに対して、イベント ハンドラをアタッチします。また、center
プロパティの変更に関するイベント ハンドラを地図に追加し、center_changed
イベントを受信したら 3 秒後に地図をパン表示してマーカーに戻します。
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();
サンプルを試す
ヒント: ビューポートの変更を検出したい場合は、指定の bounds_changed
イベントを使用してください。その構成要素である zoom_changed
や center_changed
イベントは使用しないでください。Maps JavaScript API は後者の 2 つのイベントを独立して発生させるので、ビューポートが正しく変更されるまで、getBounds()
は有用な結果を報告しない可能性があります。このようなイベントの後に getBounds()
を実行する場合は、代わりに bounds_changed
イベントをリッスンしてください。
例: シェイプの編集とドラッグ イベント
シェイプが編集されたり、ドラッグされたりすると、アクションの完了時にイベントが発行されます。シェイプの一覧とサンプルコードについては、シェイプをご覧ください。
UI イベントの引数へのアクセス
通常、Maps JavaScript API の UI イベントではイベント引数が渡されます。このイベント引数にイベント リスナーがアクセスし、イベント発生時の UI の状態を確認できます。たとえば、一般に UI の 'click'
イベントは、クリックされた地図上の位置を示す·latLng
プロパティを含む MouseEvent
を渡します。この動作は UI イベントに固有で、MVC の状態変化では引数をイベントで渡さないことに注意してください。
イベント リスナー内にあるイベントの引数にアクセスする方法は、オブジェクトのプロパティにアクセスする方法と同じです。以下の例は、地図にイベント リスナーを追加して、ユーザーが地図をクリックすると、その位置にマーカーを作成します。
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();
サンプルを試す
イベント リスナーでのクロージャの使用
イベント リスナーを実行するとき、通常は、オブジェクトにプライベート データと永続データの両方をアタッチするのが有効です。JavaScript は「プライベート」インスタンス データをサポートしませんが、クロージャはサポートしており、これによって内部の関数が外部の変数にアクセスできます。クロージャは、イベントが発生したオブジェクトには通常アタッチされていない変数に、イベント リスナー内でアクセスするのに便利です。
以下の例では、イベント リスナー内で関数クロージャを使用して、マーカーのセットに秘密のメッセージを割り当てています。各マーカーをクリックすると、そのマーカー自体には含まれていない秘密のメッセージの一部が表示されます。
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();
サンプルを試す
イベント ハンドラ内でのプロパティの取得と設定
Maps JavaScript API イベント システムにおける MVC の状態変化イベントのうち、イベントがトリガーされたときに引数を渡すものはありません(ユーザー イベントは検査可能な引数を渡します)。MVC の状態変化のプロパティを検査する必要がある場合は、そのオブジェクトの適切な getProperty()
メソッドを明示的に呼び出す必要があります。この検査で取得されるのは常に MVC オブジェクトの現在の状態であり、イベントが最初に発生したときの状態とは異なる可能性があります。
注: あるプロパティの状態変化に応答するイベント ハンドラ内で、そのプロパティを明示的に設定すると、予測できない動作や望ましくない動作が生じる可能性があります。たとえば、そのようなプロパティを設定すると新しいイベントが発生して、そのイベント ハンドラ内で必ずプロパティを設定していると無限ループに陥ることがあります。
以下の例では、ズームイベントに応答するイベント ハンドラを設定し、そのレベルを情報ウィンドウに表示します。
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();
サンプルを試す
DOM イベントのリッスン
Maps JavaScript API のイベントモデルは、独自のカスタム イベントを作成して管理します。一方、ブラウザ内の DOM(ドキュメント オブジェクト モデル)も、使用している特定のブラウザ イベントモデルに応じて独自のイベントを作成して送信します。このイベントを取得して応答する必要がある場合は、Maps JavaScript API が提供する addDomListener()
静的メソッドを使用すると、DOM イベントをリッスンしてバインドできます。
この便利なメソッドには、以下のシグネチャがあります。
addDomListener(instance:Object, eventName:string, handler:Function)
ここで、instance
は、ブラウザがサポートする任意の DOM 要素で、次のようなものがあります:
window
やdocument.body.myform
などの DOM の階層構造のメンバーdocument.getElementById("foo")
などの名前付き要素
addDomListener()
は、指定されたイベントをブラウザにそのまま渡すだけです。ブラウザはそのイベントをブラウザの DOM イベントモデルに従って処理します。ただし、ほぼすべての最新のブラウザで、少なくとも DOM レベル 2 がサポートされています(DOM レベルのイベントの詳細については、Mozilla DOM レベルのリファレンスをご覧ください)。
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>
サンプルを試す
上のコードは Maps JavaScript API コードですが、addDomListener()
メソッドはブラウザの window
オブジェクトとバインドされており、API の通常のドメイン外でオブジェクトと API がやり取りできます。
イベント リスナーの削除
指定したイベント リスナーを削除するには、変数を割り当てる必要があります。次に removeListener()
を呼び出し、そのリスナーに割り当てられた変数名を渡します。
var listener1 = marker.addListener('click', aFunction); google.maps.event.removeListener(listener1);
特定のインスタンスにあるリスナーをすべて削除するには、clearInstanceListeners()
を呼び出して、そのインスタンス名を渡します。
var listener1 = marker.addListener('click', aFunction); var listener2 = marker.addListener('mouseover', bFunction); // Remove listener1 and listener2 from marker instance. google.maps.event.clearInstanceListeners(marker);
特定のインスタンスで、特定のイベントタイプのリスナーをすべて削除するには、clearListeners()
を呼び出して、そのインスタンス名とイベント名を渡します。
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');
詳しくは、google.maps.event 名前空間のリファレンス ドキュメントをご覧ください。
認証エラーのリッスン
プログラムで認証エラーを検出する場合(ビーコンを自動的に送信するなど)、コールバック関数を作成できます。次のグローバル関数が定義されている場合は、認証エラーが発生すると、その関数が呼び出されます。function gm_authFailure() { /* Code */ };