diff --git a/playground/pages/third-parties/google-maps/overlay-popup.vue b/playground/pages/third-parties/google-maps/overlay-popup.vue new file mode 100644 index 00000000..b6865ea7 --- /dev/null +++ b/playground/pages/third-parties/google-maps/overlay-popup.vue @@ -0,0 +1,69 @@ + + + diff --git a/playground/pages/third-parties/google-maps/styled.vue b/playground/pages/third-parties/google-maps/styled.vue index 062a009f..0e6c33d5 100644 --- a/playground/pages/third-parties/google-maps/styled.vue +++ b/playground/pages/third-parties/google-maps/styled.vue @@ -16,30 +16,5 @@ const mapOptions = { :map-options="mapOptions" /> -
- -
- - diff --git a/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue b/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue index 03f4d3b6..03285307 100644 --- a/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue +++ b/src/runtime/components/GoogleMaps/ScriptGoogleMaps.vue @@ -334,7 +334,18 @@ const googleMaps = { defineExpose(googleMaps) -provide(MAP_INJECTION_KEY, { map, mapsApi }) +// Shared InfoWindow group: only one InfoWindow open at a time within this map +let activeInfoWindow: google.maps.InfoWindow | undefined +provide(MAP_INJECTION_KEY, { + map, + mapsApi, + activateInfoWindow(iw: google.maps.InfoWindow) { + if (activeInfoWindow && activeInfoWindow !== iw) { + activeInfoWindow.close() + } + activeInfoWindow = iw + }, +}) onMounted(() => { watch(ready, (v) => { diff --git a/src/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue b/src/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue index 166b730e..1012f592 100644 --- a/src/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue +++ b/src/runtime/components/GoogleMaps/ScriptGoogleMapsAdvancedMarkerElement.vue @@ -14,32 +14,22 @@ const props = defineProps<{ options?: Omit }>() -const emit = defineEmits<{ - (event: typeof eventsWithoutPayload[number]): void - (event: typeof eventsWithMapMouseEventPayload[number], payload: google.maps.MapMouseEvent): void -}>() - -// AdvancedMarkerElement supported events only -// See https://developers.google.com/maps/documentation/javascript/reference/advanced-markers -const eventsWithoutPayload = [] as const - -const eventsWithMapMouseEventPayload = [ - 'click', - 'drag', - 'dragend', - 'dragstart', -] as const - +const emit = defineEmits(['click', 'drag', 'dragend', 'dragstart']) +const dragEvents = ['drag', 'dragend', 'dragstart'] as const const slots = useSlots() const markerContent = useTemplateRef('marker-content') const markerClustererContext = inject(MARKER_CLUSTERER_INJECTION_KEY, undefined) +// gmp-click handler for cleanup (AdvancedMarkerElement uses DOM gmp-click instead of Maps addListener click) +let gmpClickHandler: ((e: any) => void) | undefined + const advancedMarkerElement = useGoogleMapsResource({ ready: () => !slots.content || !!markerContent.value, async create({ mapsApi, map }) { await mapsApi.importLibrary('marker') const marker = new mapsApi.marker.AdvancedMarkerElement({ ...props.options, + gmpClickable: true, ...(props.position ? { position: props.position } : {}), }) @@ -48,11 +38,6 @@ const advancedMarkerElement = useGoogleMapsResource emit('click', e) + marker.addEventListener('gmp-click', gmpClickHandler) + + // Drag events still use Maps API addListener + bindGoogleMapsEvents(marker, emit, { + withPayload: dragEvents, + }) + return marker }, cleanup(marker, { mapsApi }) { + if (gmpClickHandler) { + marker.removeEventListener('gmp-click', gmpClickHandler) + gmpClickHandler = undefined + } mapsApi.event.clearInstanceListeners(marker) if (markerClustererContext?.markerClusterer.value) { markerClustererContext.markerClusterer.value.removeMarker(marker, true) diff --git a/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue b/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue index 8ac01a23..dd28540f 100644 --- a/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue +++ b/src/runtime/components/GoogleMaps/ScriptGoogleMapsInfoWindow.vue @@ -1,7 +1,7 @@