From d5dd1819da2dfea02dd50c600c870c37139870ee Mon Sep 17 00:00:00 2001
From: William French <wfrench@google.com>
Date: Mon, 18 Sep 2023 09:37:25 -0700
Subject: [PATCH] feat: Updates DDS event handling examples to demo mouseover.
 (#1591)

* feat: Updates DDS event handling examples to demo mouseover.

Change-Id: I7882ccbdc034bc853966a9d857afcae6b6a2bf87

* Update index.ts

* Update index.ts

* Update index.ts

* Update boundaries-click index.ts

* Update index.ts for dds-datasets-polygon-click

* Update index.ts for boundaries-click

removes commented line

* Update index.ts

renames region tag back to old name

* Update index.ts

renames event handler tag to old name
---
 samples/boundaries-click/index.ts           | 178 ++++++++++++--------
 samples/dds-datasets-polygon-click/index.ts | 158 ++++++++++-------
 2 files changed, 205 insertions(+), 131 deletions(-)

diff --git a/samples/boundaries-click/index.ts b/samples/boundaries-click/index.ts
index ad06279873..2ac3fc9d1b 100644
--- a/samples/boundaries-click/index.ts
+++ b/samples/boundaries-click/index.ts
@@ -7,86 +7,126 @@
 // [START maps_boundaries_click_event]
 let map: google.maps.Map;
 let featureLayer;
-let infoWindow: google.maps.InfoWindow;
-async function initMap() {
-    // Request needed libraries.
-    const { Map, InfoWindow } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
-
-    map = new Map(document.getElementById('map') as HTMLElement, {
-        center: { lat: 39.23, lng: -105.73 }, // Park County, CO 
-        zoom: 8,
-        // In the cloud console, configure this Map ID with a style that enables the
-        // "Administrative Area Level 2" Data Driven Styling type.
-        mapId: 'a3efe1c035bad51b', // <YOUR_MAP_ID_HERE>,
-    });
-    //[START maps_boundaries_click_event_add_layer]
-    // Add the feature layer.
-    //@ts-ignore
-    featureLayer = map.getFeatureLayer('ADMINISTRATIVE_AREA_LEVEL_2');
-    // Add the event listener for the feature layer.
-    featureLayer.addListener('click', handlePlaceClick);
-    //[END maps_boundaries_click_event_add_layer]
-    infoWindow = new InfoWindow({});
-    // Apply style on load, to enable clicking.
-    applyStyleToSelected();
-}
+let infoWindow;
+let lastInteractedFeatureIds = [];
+let lastClickedFeatureIds = [];
+
 // [START maps_boundaries_click_event_handler]
-// Handle the click event.
-async function handlePlaceClick(event) {
-    let feature = event.features[0];
-    if (!feature.placeId) return;
-    // Apply the style to the feature layer.
-    applyStyleToSelected(feature.placeId);
-    // Add the info window.
-    const place = await feature.fetchPlace();
-    let content = '<span style="font-size:small">Display name: ' + place.displayName +
-        '<br/> Place ID: ' + feature.placeId +
-        '<br/> Feature type: ' + feature.featureType +
-        '</span>';
-    updateInfoWindow(content, event.latLng);
+function handleClick(/* MouseEvent */ e) {
+  lastClickedFeatureIds = e.features.map(f => f.placeId);
+  lastInteractedFeatureIds = [];
+  featureLayer.style = applyStyle;
+  createInfoWindow(e);
+}
+
+function handleMouseMove(/* MouseEvent */ e) {
+  lastInteractedFeatureIds = e.features.map(f => f.placeId);
+  featureLayer.style = applyStyle;
 }
 // [END maps_boundaries_click_event_handler]
+
+async function initMap() {
+  // Request needed libraries.
+  const { Map, InfoWindow } = await google.maps.importLibrary('maps') as google.maps.MapsLibrary;
+
+  map = new Map(document.getElementById('map') as HTMLElement, {
+    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,
+  });
+
+  //[START maps_boundaries_click_event_add_layer]
+  // 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;
+    }
+  });
+  //[END maps_boundaries_click_event_add_layer]
+
+  // Create the infowindow.
+  infoWindow = new InfoWindow({});
+  // Apply style on load, to enable clicking.
+  featureLayer.style = applyStyle;
+}
+
+// Helper function for the infowindow.
+async function createInfoWindow(event) {
+  let feature = event.features[0];
+  if (!feature.placeId) return;
+
+  // Update the infowindow.
+  const place = await feature.fetchPlace();
+  let content =
+      '<span style="font-size:small">Display name: ' + place.displayName +
+      '<br/> Place ID: ' + feature.placeId +
+      '<br/> Feature type: ' + feature.featureType + '</span>';
+
+  updateInfoWindow(content, event.latLng);
+}
+
 // [START maps_boundaries_click_event_style]
+// Define styles.
 // Stroke and fill with minimum opacity value.
-//@ts-ignore
-const styleDefault: google.maps.FeatureStyleOptions = {
-    strokeColor: '#810FCB',
-    strokeOpacity: 1.0,
-    strokeWeight: 2.0,
-    fillColor: 'white',
-    fillOpacity: 0.1 // Polygons must be visible to receive click events.
+const styleDefault = {
+  strokeColor: '#810FCB',
+  strokeOpacity: 1.0,
+  strokeWeight: 2.0,
+  fillColor: 'white',
+  fillOpacity: 0.1,  // Polygons must be visible to receive events.
 };
-
-// Style for the clicked Administrative Area Level 2 polygon.
-//@ts-ignore
-const styleClicked: google.maps.FeatureStyleOptions = {
-    ...styleDefault,
-    fillColor: '#810FCB',
-    fillOpacity: 0.5
+// Style for the clicked polygon.
+const styleClicked = {
+  ...styleDefault,
+  fillColor: '#810FCB',
+  fillOpacity: 0.5,
 };
-// [END maps_boundaries_click_event_style]
-// Apply styles to the map.
-function applyStyleToSelected(placeid?) {
-    // Apply styles to the feature layer.
-    featureLayer.style = (options) => {
-        // Style fill and stroke for a polygon.
-        if (placeid && options.feature.placeId == placeid) {
-            return styleClicked;
-        }
-        // Style only the stroke for the entire feature type.
-        return styleDefault;
-    };
+// Style for polygon on mouse move.
+const styleMouseMove = {
+  ...styleDefault,
+  strokeWeight: 4.0,
+};
+
+// Apply styles using a feature style function.
+function applyStyle(/* FeatureStyleFunctionOptions */ params) {
+  const placeId = params.feature.placeId;
+  //@ts-ignore
+  if (lastClickedFeatureIds.includes(placeId)) {
+    return styleClicked;
+  }
+  //@ts-ignore
+  if (lastInteractedFeatureIds.includes(placeId)) {
+    return styleMouseMove;
+  }
+  return styleDefault;
 }
+// [END maps_boundaries_click_event_style]
+
 // Helper function to create an info window.
 function updateInfoWindow(content, center) {
-    infoWindow.setContent(content);
-    infoWindow.setPosition(center);
-    infoWindow.open({
-        map,
-        shouldFocus: false,
-    });
+  infoWindow.setContent(content);
+  infoWindow.setPosition(center);
+  infoWindow.open({
+    map,
+    shouldFocus: false,
+  });
 }
 
 initMap();
-// [END maps_boundaries_click_event]
+//  [END maps_boundaries_click_event]
 export { };
diff --git a/samples/dds-datasets-polygon-click/index.ts b/samples/dds-datasets-polygon-click/index.ts
index 5c8b4e7a4c..a0f8fdaf95 100644
--- a/samples/dds-datasets-polygon-click/index.ts
+++ b/samples/dds-datasets-polygon-click/index.ts
@@ -3,90 +3,124 @@
  * Copyright 2019 Google LLC. All Rights Reserved.
  * SPDX-License-Identifier: Apache-2.0
  */
-
 // [START maps_dds_datasets_polygon_click]
-let map;
+let map: google.maps.Map;
+let lastInteractedFeatureIds = [];
 let lastClickedFeatureIds = [];
 let datasetLayer;
 
 // [START maps_dds_datasets_polygon_click_eventhandler]
-function handleClick( /* MouseEvent */ e) {
+// Note, 'globalid' is an attribute in this Dataset.
+function handleClick(/* MouseEvent */ e) {
   if (e.features) {
     lastClickedFeatureIds =
-        // Note, 'globalid' is an attribute in this Dataset.
-        e.features.map(f => f.datasetAttributes['globalid']);
+        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 = setStyle;
+  datasetLayer.style = applyStyle;
 }
 // [END maps_dds_datasets_polygon_click_eventhandler]
 
-// [START maps_dds_datasets_polygon_click_stylefunction]
-function setStyle(/* FeatureStyleFunctionOptions */ params) {
-    const datasetFeature = params.feature;
+async function initMap() {
+  // Request needed libraries.
+  const { Map } = await google.maps.importLibrary('maps') as google.maps.MapsLibrary;
+  const { LatLng } = await google.maps.importLibrary('core') as google.maps.CoreLibrary;
+  const position = new LatLng(40.796675, -73.946275);
+  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
+  // [START maps_dds_datasets_polygon_click_addlistener]
+  datasetLayer = map.getDatasetFeatureLayer(datasetId);
+  datasetLayer.style = applyStyle;
+
+  datasetLayer.addListener('click', handleClick);
+  datasetLayer.addListener('mousemove', handleMouseMove);
 
-    // Note, 'globalid' is an attribute in this dataset.
-    //@ts-ignore
-    if (lastClickedFeatureIds.includes(datasetFeature.datasetAttributes['globalid'])) {
-      return /* FeatureStyleOptions */ {
-        strokeColor: 'blue',
-        strokeWeight: 2,
-        strokeOpacity: 1,
-        fillColor: 'blue',
-        fillOpacity: 0.5,
-      };
+  // 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;
     }
-    return /* FeatureStyleOptions */ {
-      strokeColor: 'green',
-      strokeWeight: 2,
-      strokeOpacity: 1,
-      fillColor: 'green',
-      fillOpacity: 0.3,
-    };
+  });
+  // [END maps_dds_datasets_polygon_click_addlistener]
+  const attributionDiv = document.createElement('div');
+  const attributionControl = createAttribution(map);
+
+  attributionDiv.appendChild(attributionControl);
+  map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(attributionDiv);
 }
-// [END maps_dds_datasets_polygon_click_stylefunction]
 
-async function initMap() {
-    // Request needed libraries.
-    const { Map } = await google.maps.importLibrary("maps") as google.maps.MapsLibrary;
-    const { LatLng } = await google.maps.importLibrary("core") as google.maps.CoreLibrary;
-    
-    const position = new LatLng(40.796675, -73.946275);
-    const map = new Map(document.getElementById('map') as HTMLElement, {
-      zoom: 13,
-      center: position,
-      mapId: 'b98e588c46685dd7',
-      mapTypeControl: false,
-    });
+// [START maps_dds_datasets_polygon_click_stylefunction]
+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,
+};
 
-    // Dataset ID for NYC park data.
-    const datasetId = '6fe13aa9-b900-45e7-b636-3236672c3f4f';
-    //@ts-ignore
-    datasetLayer = map.getDatasetFeatureLayer(datasetId);
-    datasetLayer.style = setStyle;
-    // [START maps_dds_datasets_polygon_click_addlistener]
-    datasetLayer.addListener('click', handleClick);
-    // [END maps_dds_datasets_polygon_click_addlistener]
+const styleMouseMove = {
+   ...styleDefault,
+  strokeWeight: 4.0
+};
 
-    const attributionDiv = document.createElement('div');
-    const attributionControl = createAttribution(map);
-    attributionDiv.appendChild(attributionControl);
-    map.controls[google.maps.ControlPosition.LEFT_BOTTOM].push(attributionDiv);
+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;
 }
+// [END maps_dds_datasets_polygon_click_stylefunction]
 
 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;
+  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();
 // [END maps_dds_datasets_polygon_click]
-export { };
\ No newline at end of file
+export { };