Overview
Make a feature layer respond tomousemove
andclick
events, and use
them to return information about the boundary that was clicked. This information
includes ID, display name, and feature type. The following example map shows the
boundaries for Administrative Area Level 2, and has event handling code that
styles polygons based on user interaction (mousemove
changes the border
thickness,click
shades the background color and causes an info window to
display).
Enable feature layer events
Take the following steps to enable events on a feature layer:
Register a feature layer for event notifications by calling the
addListener()
function on the feature layer for each event you want to register. In this example the map also gets a listener.TypeScript
// Add the feature layer. //@ts-ignore featureLayer=map.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2'); // Add the event listeners for the feature layer. featureLayer.addListener('click',handleClick); featureLayer.addListener('mousemove',handleMouseMove); // Map event listener. map.addListener('mousemove',()=>{ // If the map gets a mousemove, that means there are no feature layers // with listeners registered under the mouse, so we clear the last // interacted feature ids. if(lastInteractedFeatureIds?.length){ lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; } });
JavaScript
// Add the feature layer. //@ts-ignore featureLayer=map.getFeatureLayer("ADMINISTRATIVE_AREA_LEVEL_2"); // Add the event listeners for the feature layer. featureLayer.addListener("click",handleClick); featureLayer.addListener("mousemove",handleMouseMove); // Map event listener. map.addListener("mousemove",()=>{ // If the map gets a mousemove, that means there are no feature layers // with listeners registered under the mouse, so we clear the last // interacted feature ids. if(lastInteractedFeatureIds?.length){ lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; } });
Add event handler code to style the selected polygon based on the type of interaction.
TypeScript
functionhandleClick(/* MouseEvent */e){ lastClickedFeatureIds=e.features.map(f=>f.placeId); lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; createInfoWindow(e); } functionhandleMouseMove(/* MouseEvent */e){ lastInteractedFeatureIds=e.features.map(f=>f.placeId); featureLayer.style=applyStyle; }
JavaScript
functionhandleClick(/* MouseEvent */e){ lastClickedFeatureIds=e.features.map((f)=>f.placeId); lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; createInfoWindow(e); } functionhandleMouseMove(/* MouseEvent */e){ lastInteractedFeatureIds=e.features.map((f)=>f.placeId); featureLayer.style=applyStyle; }
Use a feature style function to apply styles. The feature style function shown here conditionally applies style based on the type of interaction. Three styles are defined here: one to make the border bold on
mousemove
,one to change the background and show an info window onclick
,and a default style.TypeScript
// Define styles. // Stroke and fill with minimum opacity value. conststyleDefault={ strokeColor:'#810FCB', strokeOpacity:1.0, strokeWeight:2.0, fillColor:'white', fillOpacity:0.1,// Polygons must be visible to receive events. }; // Style for the clicked polygon. conststyleClicked={ ...styleDefault, fillColor:'#810FCB', fillOpacity:0.5, }; // Style for polygon on mouse move. conststyleMouseMove={ ...styleDefault, strokeWeight:4.0, }; // Apply styles using a feature style function. functionapplyStyle(/* FeatureStyleFunctionOptions */params){ constplaceId=params.feature.placeId; //@ts-ignore if(lastClickedFeatureIds.includes(placeId)){ returnstyleClicked; } //@ts-ignore if(lastInteractedFeatureIds.includes(placeId)){ returnstyleMouseMove; } returnstyleDefault; }
JavaScript
// Define styles. // Stroke and fill with minimum opacity value. conststyleDefault={ strokeColor:"#810FCB", strokeOpacity:1.0, strokeWeight:2.0, fillColor:"white", fillOpacity:0.1,// Polygons must be visible to receive events. }; // Style for the clicked polygon. conststyleClicked={ ...styleDefault, fillColor:"#810FCB", fillOpacity:0.5, }; // Style for polygon on mouse move. conststyleMouseMove={ ...styleDefault, strokeWeight:4.0, }; // Apply styles using a feature style function. functionapplyStyle(/* FeatureStyleFunctionOptions */params){ constplaceId=params.feature.placeId; //@ts-ignore if(lastClickedFeatureIds.includes(placeId)){ returnstyleClicked; } //@ts-ignore if(lastInteractedFeatureIds.includes(placeId)){ returnstyleMouseMove; } returnstyleDefault; }
Complete example code
TypeScript
letmap:google.maps.Map; letfeatureLayer; letinfoWindow; letlastInteractedFeatureIds=[]; letlastClickedFeatureIds=[]; functionhandleClick(/* MouseEvent */e){ lastClickedFeatureIds=e.features.map(f=>f.placeId); lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; createInfoWindow(e); } functionhandleMouseMove(/* MouseEvent */e){ lastInteractedFeatureIds=e.features.map(f=>f.placeId); featureLayer.style=applyStyle; } asyncfunctioninitMap(){ // Request needed libraries. const{Map,InfoWindow}=awaitgoogle.maps.importLibrary('maps')asgoogle.maps.MapsLibrary; map=newMap(document.getElementById('map')asHTMLElement,{ center:{lat:39.23,lng:-105.73}, zoom:8, // In the cloud console, configure your Map ID with a style that enables the // 'Administrative Area Level 2' Data Driven Styling type. mapId:'a3efe1c035bad51b',// Substitute your own map ID. mapTypeControl:false, }); // Add the feature layer. //@ts-ignore featureLayer=map.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2'); // Add the event listeners for the feature layer. featureLayer.addListener('click',handleClick); featureLayer.addListener('mousemove',handleMouseMove); // Map event listener. map.addListener('mousemove',()=>{ // If the map gets a mousemove, that means there are no feature layers // with listeners registered under the mouse, so we clear the last // interacted feature ids. if(lastInteractedFeatureIds?.length){ lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; } }); // Create the infowindow. infoWindow=newInfoWindow({}); // Apply style on load, to enable clicking. featureLayer.style=applyStyle; } // Helper function for the infowindow. asyncfunctioncreateInfoWindow(event){ letfeature=event.features[0]; if(!feature.placeId)return; // Update the infowindow. constplace=awaitfeature.fetchPlace(); letcontent= '<spanstyle="font-size:small ">Displayname:'+place.displayName+ '<br/>PlaceID:'+feature.placeId+ '<br/>Featuretype:'+feature.featureType+'</span>'; updateInfoWindow(content,event.latLng); } // Define styles. // Stroke and fill with minimum opacity value. conststyleDefault={ strokeColor:'#810FCB', strokeOpacity:1.0, strokeWeight:2.0, fillColor:'white', fillOpacity:0.1,// Polygons must be visible to receive events. }; // Style for the clicked polygon. conststyleClicked={ ...styleDefault, fillColor:'#810FCB', fillOpacity:0.5, }; // Style for polygon on mouse move. conststyleMouseMove={ ...styleDefault, strokeWeight:4.0, }; // Apply styles using a feature style function. functionapplyStyle(/* FeatureStyleFunctionOptions */params){ constplaceId=params.feature.placeId; //@ts-ignore if(lastClickedFeatureIds.includes(placeId)){ returnstyleClicked; } //@ts-ignore if(lastInteractedFeatureIds.includes(placeId)){ returnstyleMouseMove; } returnstyleDefault; } // Helper function to create an info window. functionupdateInfoWindow(content,center){ infoWindow.setContent(content); infoWindow.setPosition(center); infoWindow.open({ map, shouldFocus:false, }); } initMap();
JavaScript
letmap; letfeatureLayer; letinfoWindow; letlastInteractedFeatureIds=[]; letlastClickedFeatureIds=[]; functionhandleClick(/* MouseEvent */e){ lastClickedFeatureIds=e.features.map((f)=>f.placeId); lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; createInfoWindow(e); } functionhandleMouseMove(/* MouseEvent */e){ lastInteractedFeatureIds=e.features.map((f)=>f.placeId); featureLayer.style=applyStyle; } asyncfunctioninitMap(){ // Request needed libraries. const{Map,InfoWindow}=awaitgoogle.maps.importLibrary("maps"); map=newMap(document.getElementById("map"),{ center:{lat:39.23,lng:-105.73}, zoom:8, // In the cloud console, configure your Map ID with a style that enables the // 'Administrative Area Level 2' Data Driven Styling type. mapId:"a3efe1c035bad51b",// Substitute your own map ID. mapTypeControl:false, }); // Add the feature layer. //@ts-ignore featureLayer=map.getFeatureLayer("ADMINISTRATIVE_AREA_LEVEL_2"); // Add the event listeners for the feature layer. featureLayer.addListener("click",handleClick); featureLayer.addListener("mousemove",handleMouseMove); // Map event listener. map.addListener("mousemove",()=>{ // If the map gets a mousemove, that means there are no feature layers // with listeners registered under the mouse, so we clear the last // interacted feature ids. if(lastInteractedFeatureIds?.length){ lastInteractedFeatureIds=[]; featureLayer.style=applyStyle; } }); // Create the infowindow. infoWindow=newInfoWindow({}); // Apply style on load, to enable clicking. featureLayer.style=applyStyle; } // Helper function for the infowindow. asyncfunctioncreateInfoWindow(event){ letfeature=event.features[0]; if(!feature.placeId)return; // Update the infowindow. constplace=awaitfeature.fetchPlace(); letcontent= '<spanstyle="font-size:small ">Displayname:'+ place.displayName+ "<br/>PlaceID:"+ feature.placeId+ "<br/>Featuretype:"+ feature.featureType+ "</span> "; updateInfoWindow(content,event.latLng); } // Define styles. // Stroke and fill with minimum opacity value. conststyleDefault={ strokeColor:"#810FCB", strokeOpacity:1.0, strokeWeight:2.0, fillColor:"white", fillOpacity:0.1,// Polygons must be visible to receive events. }; // Style for the clicked polygon. conststyleClicked={ ...styleDefault, fillColor:"#810FCB", fillOpacity:0.5, }; // Style for polygon on mouse move. conststyleMouseMove={ ...styleDefault, strokeWeight:4.0, }; // Apply styles using a feature style function. functionapplyStyle(/* FeatureStyleFunctionOptions */params){ constplaceId=params.feature.placeId; //@ts-ignore if(lastClickedFeatureIds.includes(placeId)){ returnstyleClicked; } //@ts-ignore if(lastInteractedFeatureIds.includes(placeId)){ returnstyleMouseMove; } returnstyleDefault; } // Helper function to create an info window. functionupdateInfoWindow(content,center){ infoWindow.setContent(content); infoWindow.setPosition(center); infoWindow.open({ map, shouldFocus:false, }); } initMap();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #map{ height:100%; } /* * Optional: Makes the sample page fill the window. */ html, body{ height:100%; margin:0; padding:0; }
HTML
<html> <head> <title>Handle Region Boundary Click Event</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 /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>