Search code examples
javascriptgoogle-mapseventsgoogle-maps-api-3google-maps-markers

Trigger google Marker click listener on marker label click


I have a Google Maps application that displays some markers with custom labels. I want to trigger the marker click listener when the user clicks on the label, not only on the marker icon. However, I can't find a way to do that with the Google Maps API. Is there a way to achieve this functionality?

Here is the code I use to create the markers and the labels:

// Map initialization 
function initMap(mapId, centerLatitude, centerLongitude, mapZoomLevel) {
    // Generate and set google maps
    mapCenter = { lat: centerLatitude, lng: centerLongitude };
    mapZoom = mapZoomLevel;
    map = new google.maps.Map(document.getElementById(mapId), {
        center: mapCenter,
        ...MAP_OPTIONS, // Spread '...' constant map options
        zoom: mapZoom,
    });
}

// The method i use to generate all the markers starting from a json
async function loadData(serializedData) {
    // Convert serialized data to a JavaScript object
    data = JSON.parse(serializedData);

    // Iterate on each object in the dataset using map
    markers = await Promise.all(
        data.map(async (object) => {
            // Wait for the promise returned by createMarker and return it
            return await createMarker(object);
        })
    );
    initClusterer();
}

// How i create the marker
async function createMarker(object) {
    // Create marker
    const marker = new google.maps.Marker({
        position: object.Position,
        map,
        icon: getIcon(object.Direction),
        label: generateMarkerLabel(object.Name)
    });
    // Add listener
    marker.addListener("click", function () {
        focusOn(marker);
        ShowMarkerRouteViewBtn.click();
    });

    // Returns the marker created
    return marker;
}

// How i create the label
function generateMarkerLabel(markerName) {
    return {
        text: markerName,
        fontSize: "10px",
        className: "marker-label"
    };
}

// How i create the icon
function generateMarkerIcon(direction) {
    // Generate the icon svg
    let iconSvg = `
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:vectornator="http://vectornator.io" stroke-miterlimit="10" style="fill-rule:nonzero;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round" viewBox="0 0 36 36" xml:space="preserve" >
          ...[the svg paths]...
        </svg>
    `;

    // Generate and return the marker icon literal object
    return {
        url: "data:image/svg+xml;charset=UTF-8," + encodeURIComponent(iconSvg),
        scaledSize: new google.maps.Size(36,36),
        anchor: new google.maps.Point(18, 18)
    };
}

// How i init the clusterer
function initClusterer() {
    clusterer = new markerClusterer.MarkerClusterer({
        markers: markers,
        map: map,
    });
}

The problem is that the label is not part of the marker, but a separate overlay on the map. So, clicking on the label does not trigger the marker click listener. How can I make the label clickable and trigger the marker click listener? Any help would be appreciated. Thanks.


Solution

  • Edit:

    The MarkerLabel interface you're using places the labels onto a pane that cannot accept pointer events (e.g. clicks).

    Quick hack: increase the marker icon SVG height so it covers the label. That way, the click on the transparent top part of the SVG will act as an "artificial click" on the label itself.

    Another option: check out the js-markerwithlabel package.

    Otherwise, have a look at Advanced Markers. That's the recommended way to implement markers (+ labels) in 2023 and beyond. Here's a disambiguation.


    Original answer:

    Your generateMarkerLabel function returns a JavaScript object and it's not immediately clear how you attach it to the DOM.

    But once you've got the .marker-label element, you can bind a click event to it and delegate the marker's click event from where:

    // ideally attached shortly after the label element has been attached to the DOM 
    const mLabel = document.querySelector('.marker-label');
    
    mLabel.addEventListener('click', (evt => {
       google.maps.event.trigger(marker, 'click');
    }));