Page Summary
-
Learn how to make data features on a Google Maps Platform map clickable and responsive to mouse movements.
-
This guide demonstrates how to change the appearance of a feature (e.g., a park boundary) when a user interacts with it, such as highlighting it on mouse hover or changing its color on click.
-
The provided code examples showcase the implementation for Android, iOS, and JavaScript platforms, enabling you to adapt the functionality to your specific project needs.
-
The functionality involves enabling dataset layer events, adding event handlers to style selected features, and using a feature style function for conditional styling.
Make data features respond to mousemove
and click
events, and use them to
change the appearance of a feature based on user interaction.
Enable dataset layer events
Take the following steps to enable events on a dataset layer:
-
Register a dataset layer for event notifications by calling the
addListener()function on the dataset layer for each event you want to register. In this example the map also gets a listener.TypeScript
datasetLayer = map . getDatasetFeatureLayer ( datasetId ); datasetLayer . style = applyStyle ; datasetLayer . addListener ( 'click' , handleClick ); datasetLayer . 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 = []; datasetLayer . style = applyStyle ; } });
JavaScript
datasetLayer = map . getDatasetFeatureLayer ( datasetId ); datasetLayer . style = applyStyle ; datasetLayer . addListener ( "click" , handleClick ); datasetLayer . 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 = []; datasetLayer . style = applyStyle ; } });
-
Add event handler code to style the selected feature based on the type of interaction.
TypeScript
// Note, 'globalid' is an attribute in this Dataset. function handleClick ( /* MouseEvent */ e ) { if ( e . features ) { lastClickedFeatureIds = e . features . map (( f ) = > f . datasetAttributes [ 'globalid' ]); } //@ts-ignore datasetLayer . style = applyStyle ; } function handleMouseMove ( /* MouseEvent */ e ) { if ( e . features ) { lastInteractedFeatureIds = e . features . map (( f ) = > f . datasetAttributes [ 'globalid' ]); } //@ts-ignore datasetLayer . style = applyStyle ; }
JavaScript
// Note, 'globalid' is an attribute in this Dataset. function handleClick ( /* MouseEvent */ e ) { if ( e . features ) { lastClickedFeatureIds = e . features . map ( ( f ) = > f . datasetAttributes [ "globalid" ], ); } //@ts-ignore datasetLayer . style = applyStyle ; } function handleMouseMove ( /* MouseEvent */ e ) { if ( e . features ) { lastInteractedFeatureIds = e . features . map ( ( f ) = > f . datasetAttributes [ "globalid" ], ); } //@ts-ignore datasetLayer . 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 onclick, and a default style.TypeScript
const styleDefault = { strokeColor : 'green' , strokeWeight : 2.0 , strokeOpacity : 1.0 , fillColor : 'green' , fillOpacity : 0.3 , }; const styleClicked = { ... styleDefault , strokeColor : 'blue' , fillColor : 'blue' , fillOpacity : 0.5 , }; const styleMouseMove = { ... styleDefault , strokeWeight : 4.0 }; function applyStyle ( /* FeatureStyleFunctionOptions */ params ) { const datasetFeature = params . feature ; // Note, 'globalid' is an attribute in this dataset. //@ts-ignore if ( lastClickedFeatureIds . includes ( datasetFeature . datasetAttributes [ 'globalid' ])) { return styleClicked ; } //@ts-ignore if ( lastInteractedFeatureIds . includes ( datasetFeature . datasetAttributes [ 'globalid' ])) { return styleMouseMove ; } return styleDefault ; }
JavaScript
const styleDefault = { strokeColor : "green" , strokeWeight : 2.0 , strokeOpacity : 1.0 , fillColor : "green" , fillOpacity : 0.3 , }; const styleClicked = { ... styleDefault , strokeColor : "blue" , fillColor : "blue" , fillOpacity : 0.5 , }; const styleMouseMove = { ... styleDefault , strokeWeight : 4.0 , }; function applyStyle ( /* FeatureStyleFunctionOptions */ params ) { const datasetFeature = params . feature ; // Note, 'globalid' is an attribute in this dataset. //@ts-ignore if ( lastClickedFeatureIds . includes ( datasetFeature . datasetAttributes [ "globalid" ]) ) { return styleClicked ; } //@ts-ignore if ( lastInteractedFeatureIds . includes ( datasetFeature . datasetAttributes [ "globalid" ], ) ) { return styleMouseMove ; } return styleDefault ; }
Complete example code
TypeScript
let map : google.maps.Map ; let lastInteractedFeatureIds = []; let lastClickedFeatureIds = []; let datasetLayer ; // Note, 'globalid' is an attribute in this Dataset. function handleClick ( /* MouseEvent */ e ) { if ( e . features ) { lastClickedFeatureIds = e . features . map (( f ) = > f . datasetAttributes [ 'globalid' ]); } //@ts-ignore datasetLayer . style = applyStyle ; } function handleMouseMove ( /* MouseEvent */ e ) { if ( e . features ) { lastInteractedFeatureIds = e . features . map (( f ) = > f . datasetAttributes [ 'globalid' ]); } //@ts-ignore datasetLayer . style = applyStyle ; } async function initMap () { // Request needed libraries. const { Map } = await google . maps . importLibrary ( 'maps' ) as google . maps . MapsLibrary ; const position = { lat : 40.780101 , lng : - 73.967780 }; map = new Map ( document . getElementById ( 'map' ) as HTMLElement , { zoom : 13 , center : position , mapId : 'b98e588c46685dd7' , mapTypeControl : false , }); // Dataset ID for NYC park data. const datasetId = '6fe13aa9-b900-45e7-b636-3236672c3f4f' ; //@ts-ignore datasetLayer = map . getDatasetFeatureLayer ( datasetId ); datasetLayer . style = applyStyle ; datasetLayer . addListener ( 'click' , handleClick ); datasetLayer . 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 = []; datasetLayer . style = applyStyle ; } }); const attributionDiv = document . createElement ( 'div' ); const attributionControl = createAttribution ( map ); attributionDiv . appendChild ( attributionControl ); map . controls [ google . maps . ControlPosition . LEFT_BOTTOM ]. push ( attributionDiv ); } const styleDefault = { strokeColor : 'green' , strokeWeight : 2.0 , strokeOpacity : 1.0 , fillColor : 'green' , fillOpacity : 0.3 , }; const styleClicked = { ... styleDefault , strokeColor : 'blue' , fillColor : 'blue' , fillOpacity : 0.5 , }; const styleMouseMove = { ... styleDefault , strokeWeight : 4.0 }; function applyStyle ( /* FeatureStyleFunctionOptions */ params ) { const datasetFeature = params . feature ; // Note, 'globalid' is an attribute in this dataset. //@ts-ignore if ( lastClickedFeatureIds . includes ( datasetFeature . datasetAttributes [ 'globalid' ])) { return styleClicked ; } //@ts-ignore if ( lastInteractedFeatureIds . includes ( datasetFeature . datasetAttributes [ 'globalid' ])) { return styleMouseMove ; } return styleDefault ; } function createAttribution ( map ) { const attributionLabel = document . createElement ( 'div' ); // Define CSS styles. attributionLabel . style . backgroundColor = '#fff' ; attributionLabel . style . opacity = '0.7' ; attributionLabel . style . fontFamily = 'Roboto,Arial,sans-serif' ; attributionLabel . style . fontSize = '10px' ; attributionLabel . style . padding = '2px' ; attributionLabel . style . margin = '2px' ; attributionLabel . textContent = 'Data source: NYC Open Data' ; return attributionLabel ; } initMap ();
JavaScript
let map ; let lastInteractedFeatureIds = []; let lastClickedFeatureIds = []; let datasetLayer ; // Note, 'globalid' is an attribute in this Dataset. function handleClick ( /* MouseEvent */ e ) { if ( e . features ) { lastClickedFeatureIds = e . features . map ( ( f ) = > f . datasetAttributes [ "globalid" ], ); } //@ts-ignore datasetLayer . style = applyStyle ; } function handleMouseMove ( /* MouseEvent */ e ) { if ( e . features ) { lastInteractedFeatureIds = e . features . map ( ( f ) = > f . datasetAttributes [ "globalid" ], ); } //@ts-ignore datasetLayer . style = applyStyle ; } async function initMap () { // Request needed libraries. const { Map } = await google . maps . importLibrary ( "maps" ); const position = { lat : 40.780101 , lng : - 73.96778 }; map = new Map ( document . getElementById ( "map" ), { zoom : 13 , center : position , mapId : "b98e588c46685dd7" , mapTypeControl : false , }); // Dataset ID for NYC park data. const datasetId = "6fe13aa9-b900-45e7-b636-3236672c3f4f" ; //@ts-ignore datasetLayer = map . getDatasetFeatureLayer ( datasetId ); datasetLayer . style = applyStyle ; datasetLayer . addListener ( "click" , handleClick ); datasetLayer . 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 = []; datasetLayer . style = applyStyle ; } }); const attributionDiv = document . createElement ( "div" ); const attributionControl = createAttribution ( map ); attributionDiv . appendChild ( attributionControl ); map . controls [ google . maps . ControlPosition . LEFT_BOTTOM ]. push ( attributionDiv ); } const styleDefault = { strokeColor : "green" , strokeWeight : 2.0 , strokeOpacity : 1.0 , fillColor : "green" , fillOpacity : 0.3 , }; const styleClicked = { ... styleDefault , strokeColor : "blue" , fillColor : "blue" , fillOpacity : 0.5 , }; const styleMouseMove = { ... styleDefault , strokeWeight : 4.0 , }; function applyStyle ( /* FeatureStyleFunctionOptions */ params ) { const datasetFeature = params . feature ; // Note, 'globalid' is an attribute in this dataset. //@ts-ignore if ( lastClickedFeatureIds . includes ( datasetFeature . datasetAttributes [ "globalid" ]) ) { return styleClicked ; } //@ts-ignore if ( lastInteractedFeatureIds . includes ( datasetFeature . datasetAttributes [ "globalid" ], ) ) { return styleMouseMove ; } return styleDefault ; } function createAttribution ( map ) { const attributionLabel = document . createElement ( "div" ); // Define CSS styles. attributionLabel . style . backgroundColor = "#fff" ; attributionLabel . style . opacity = "0.7" ; attributionLabel . style . fontFamily = "Roboto,Arial,sans-serif" ; attributionLabel . style . fontSize = "10px" ; attributionLabel . style . padding = "2px" ; attributionLabel . style . margin = "2px" ; attributionLabel . textContent = "Data source: NYC Open Data" ; return attributionLabel ; } initMap ();

