Search code examples
javascriptgoogle-mapsgoogle-maps-markersinfowindowmarkerclusterer

Close InfoWindow on markers if user zooms out and marker is absorbed into MarkerClusterer cluster


I am using markerclustererplus with Google Maps. I have multiple markers and I have set it so that only one InfoWindow displays at a time. If the user clicks on a marker, an InfoWindow appears. If the user zooms out and the marker is absorbed into a cluster, the InfoWindow disappears. This is fine. If the user immediately zooms in, and the marker is separated from the cluster and becomes visible, the InfoWindow appears again. I would like it so that if the user zooms out and the marker is absorbed into a cluster, then the InfoWindow is actually closed / removed, and a specific user-defined function to be called.

I have tried many things, including the suggestion in this StackOverflow link. The InfoWindow does not close. The answer in the link is relatively old, so I am wondering if there is an alternate solution currently.

Edit: Sorry about the previously incomplete code. I am using MarkerClustererPlus v1.2.7.

Here is a JSfiddle.

<!DOCTYPE html>
<html>
<head>
  <title>Google Maps Marker Example</title>

<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY" async defer></script>
<script src="https://unpkg.com/@googlemaps/markerclustererplus/dist/index.min.js"></script>
<script type="text/javascript" src="mark.js"></script>

  <style>
    #map {
      width: 500px;
      height: 500px;
      border: thin solid black;
    }
  </style>
</head>
<body onload="loadMap();">
  <h1>Google Maps Marker Example</h1>
  <div id="map"></div>
</body>
</html>


var map;

function loadMap() {

    map = new google.maps.Map(document.getElementById('map'), {
        center: {
            lat: -41.75,
            lng: 172.75
        },
        zoom: 4
    });
    
    addMarkers();
}
var WeatherStations = [{
        "stn": 719460,
        "wban": 99999,
        "StationName": "FORT SIMPSON",
        "FIPS": "CA",
        "Latitude": 61.759998322,
        "Longitude": -121.2369995,
        "Elevation_m": 169,
        "NOAAReadings": 14952
    }, {
        "stn": 935970,
        "wban": 99999,
        "StationName": "CAPE CAMPBELL AWS",
        "FIPS": "NZ",
        "Latitude": -41.71699905,
        "Longitude": 174.26699829,
        "Elevation_m": 32,
        "NOAAReadings": 12174
    },
    {
        "stn": 934360,
        "wban": 99999,
        "StationName": "WELLINGTON INTL",
        "FIPS": "NZ",
        "Latitude": -41.32699966,
        "Longitude": 174.80499268,
        "Elevation_m": 12,
        "NOAAReadings": 9914
    }, {
        "stn": 937090,
        "wban": 99999,
        "StationName": "HAAST AWS",
        "FIPS": "NZ",
        "Latitude": -43.86700058,
        "Longitude": 169,
        "Elevation_m": 5,
        "NOAAReadings": 14371
    },
    {
        "stn": 935270,
        "wban": 99999,
        "StationName": "FAREWELL SPIT AWS",
        "FIPS": "NZ",
        "Latitude": -40.54999924,
        "Longitude": 173,
        "Elevation_m": 3,
        "NOAAReadings": 11575
    }, {
        "stn": 935460,
        "wban": 99999,
        "StationName": "NELSON AERODROME AWS",
        "FIPS": "NZ",
        "Latitude": -41.29999924,
        "Longitude": 173.19999695,
        "Elevation_m": 6,
        "NOAAReadings": 10557
    },
    {
        "stn": 937800,
        "wban": 99999,
        "StationName": "CHRISTCHURCH INTL",
        "FIPS": "NZ",
        "Latitude": -43.48899841,
        "Longitude": 172.53199768,
        "Elevation_m": 38,
        "NOAAReadings": 14933
    }, {
        "stn": 938050,
        "wban": 99999,
        "StationName": "PUYSEGUR POINT AWS",
        "FIPS": "NZ",
        "Latitude": -46.15000153,
        "Longitude": 166.6000061,
        "Elevation_m": 44,
        "NOAAReadings": 10493
    },
    {
        "stn": 939940,
        "wban": 99999,
        "StationName": "RAOUL ISLAND AWS",
        "FIPS": "NZ",
        "Latitude": -29.25,
        "Longitude": -177.9329987,
        "Elevation_m": 50,
        "NOAAReadings": 11001
    }
];

var styles = [
    [{
        url: "https://i.imgur.com/4dzjY47.png",
        height: 47,
        width: 48,
        anchorText: [14, 0],
        textColor: '#fff',
        textSize: 11
    }, {
        url: 'https://i.imgur.com/My5Cgpd.png',
        height: 47,
        width: 48,
        anchorText: [14, 0],
        textColor: '#fff',
        textSize: 11
    }, {
        url: 'https://i.imgur.com/t7SvOax.png',
        height: 47,
        width: 48,
        anchorText: [14, 0],
        textColor: '#fff',
        textSize: 11
    }]
];

var prev_infowindow = false; // to close previously-opened infowindows
var dataSourceType = 0; // 0 = grid; 1 = weatherstation
var gStn;
var gWban;
var gMarkerLat;
var gMarkerLng;
var gMarkerName;
var iw;
var iwClosed = false;
var curMark;
var infowindow;

function addMarkers() 
{
    infowindow = new google.maps.InfoWindow();

    var markers = [];

    for (var i = 0; i < WeatherStations.length; i++) {
        var latLng = new google.maps.LatLng(WeatherStations[i].Latitude, WeatherStations[i].Longitude)

        var marker = new google.maps.Marker({
            position: latLng,
            map: map,
            visible: true,
            zIndex: 10,

        });

        var content = "<div id='" + WeatherStations[i].stn + " '> <div class='scrollfix'><b>" + WeatherStations[i].StationName + "</b>";

        google.maps.event.addListener(marker, 'click', (function(marker, content, infowindow) {
            return function() {
                curMark = this;
                // Close already-opened InfoWindow
                if (prev_infowindow) {
                    prev_infowindow.close();
                }

                prev_infowindow = infowindow;

                infowindow.setContent(content);
                infowindow.open(map, marker);
            };
        })(marker, content, infowindow));


        google.maps.event.addListener(marker, 'map_changed', function() {

            var clusters = markerClusterer.getClusters(); // use the get clusters method which returns an array of objects

            for (let i = 0, l = clusters.length; i < l; i++) {
                const markers = clusters[i].getMarkers();
                for (const m of markers) {
                    if (m === curMark && markers.length > 1) {


                        try {
                            if (infowindow !== null) {

                                infowindow.close();
                                infowindow = null;
                            }
                            if (prev_infowindow) {
                                prev_infowindow.close();
                            }

                        } catch (ee) {}
                    }
                }
            }
        });

        markers.push(marker);
    }

    var zoom = null;
    var size = null;
    var style = 0;

    markerClusterer = new MarkerClusterer(map, markers, {
        maxZoom: zoom,
        gridSize: size,
        styles: styles[style]
    });
}

function clearClusters() {
    markerClusterer.clearMarkers();
}

Solution

  • When you open the InfoWindow using the syntax infowindow.open(map, marker);, it seems to use the map associated with the marker to hide/show the infowindow. Changing that code to:

    infowindow.setContent(content);
    infowindow.setOptions({
      pixelOffset: new google.maps.Size(0, -42)
    })
    infowindow.setPosition(marker.getPosition())
    infowindow.open(map);
    

    removes that dependency.

    proof of concept fiddle

    code snippet:

    var map;
    
    function loadMap() {
    
      map = new google.maps.Map(document.getElementById('map'), {
        center: {
          lat: -41.75,
          lng: 172.75
        },
        zoom: 4
      });
    
      addMarkers();
    }
    var WeatherStations = [{
        "stn": 719460,
        "wban": 99999,
        "StationName": "FORT SIMPSON",
        "FIPS": "CA",
        "Latitude": 61.759998322,
        "Longitude": -121.2369995,
        "Elevation_m": 169,
        "NOAAReadings": 14952
      }, {
        "stn": 935970,
        "wban": 99999,
        "StationName": "CAPE CAMPBELL AWS",
        "FIPS": "NZ",
        "Latitude": -41.71699905,
        "Longitude": 174.26699829,
        "Elevation_m": 32,
        "NOAAReadings": 12174
      },
      {
        "stn": 934360,
        "wban": 99999,
        "StationName": "WELLINGTON INTL",
        "FIPS": "NZ",
        "Latitude": -41.32699966,
        "Longitude": 174.80499268,
        "Elevation_m": 12,
        "NOAAReadings": 9914
      }, {
        "stn": 937090,
        "wban": 99999,
        "StationName": "HAAST AWS",
        "FIPS": "NZ",
        "Latitude": -43.86700058,
        "Longitude": 169,
        "Elevation_m": 5,
        "NOAAReadings": 14371
      },
      {
        "stn": 935270,
        "wban": 99999,
        "StationName": "FAREWELL SPIT AWS",
        "FIPS": "NZ",
        "Latitude": -40.54999924,
        "Longitude": 173,
        "Elevation_m": 3,
        "NOAAReadings": 11575
      }, {
        "stn": 935460,
        "wban": 99999,
        "StationName": "NELSON AERODROME AWS",
        "FIPS": "NZ",
        "Latitude": -41.29999924,
        "Longitude": 173.19999695,
        "Elevation_m": 6,
        "NOAAReadings": 10557
      },
      {
        "stn": 937800,
        "wban": 99999,
        "StationName": "CHRISTCHURCH INTL",
        "FIPS": "NZ",
        "Latitude": -43.48899841,
        "Longitude": 172.53199768,
        "Elevation_m": 38,
        "NOAAReadings": 14933
      }, {
        "stn": 938050,
        "wban": 99999,
        "StationName": "PUYSEGUR POINT AWS",
        "FIPS": "NZ",
        "Latitude": -46.15000153,
        "Longitude": 166.6000061,
        "Elevation_m": 44,
        "NOAAReadings": 10493
      },
      {
        "stn": 939940,
        "wban": 99999,
        "StationName": "RAOUL ISLAND AWS",
        "FIPS": "NZ",
        "Latitude": -29.25,
        "Longitude": -177.9329987,
        "Elevation_m": 50,
        "NOAAReadings": 11001
      }
    ];
    
    var styles = [
      [{
        url: "https://i.imgur.com/4dzjY47.png",
        height: 47,
        width: 48,
        anchorText: [14, 0],
        textColor: '#fff',
        textSize: 11
      }, {
        url: 'https://i.imgur.com/My5Cgpd.png',
        height: 47,
        width: 48,
        anchorText: [14, 0],
        textColor: '#fff',
        textSize: 11
      }, {
        url: 'https://i.imgur.com/t7SvOax.png',
        height: 47,
        width: 48,
        anchorText: [14, 0],
        textColor: '#fff',
        textSize: 11
      }]
    ];
    
    var prev_infowindow = false; // to close previously-opened infowindows
    var dataSourceType = 0; // 0 = grid; 1 = weatherstation
    var gStn;
    var gWban;
    var gMarkerLat;
    var gMarkerLng;
    var gMarkerName;
    var iw;
    var iwClosed = false;
    var curMark;
    var infowindow;
    
    function addMarkers() {
      infowindow = new google.maps.InfoWindow();
    
      var markers = [];
    
      for (var i = 0; i < WeatherStations.length; i++) {
        var latLng = new google.maps.LatLng(WeatherStations[i].Latitude, WeatherStations[i].Longitude)
    
        var marker = new google.maps.Marker({
          position: latLng,
          map: map,
          visible: true,
          zIndex: 10,
    
        });
    
        var content = "<div id='" + WeatherStations[i].stn + " '> <div class='scrollfix'><b>" + WeatherStations[i].StationName + "</b>";
    
        google.maps.event.addListener(marker, 'click', (function(marker, content, infowindow) {
          return function() {
            curMark = this;
            // Close already-opened InfoWindow
            if (prev_infowindow) {
              prev_infowindow.close();
            }
    
            prev_infowindow = infowindow;
    
            infowindow.setContent(content);
            infowindow.setOptions({
              pixelOffset: new google.maps.Size(0, -42)
            })
            infowindow.setPosition(marker.getPosition())
            infowindow.open(map, /* marker */ );
          };
        })(marker, content, infowindow));
    
    
        google.maps.event.addListener(marker, 'map_changed', function() {
    
          var clusters = markerClusterer.getClusters(); // use the get clusters method which returns an array of objects
    
          for (let i = 0, l = clusters.length; i < l; i++) {
            const markers = clusters[i].getMarkers();
            for (const m of markers) {
              if (m === curMark && markers.length > 1) {
    
    
                try {
                  if (infowindow !== null) {
    
                    infowindow.close();
                    infowindow = null;
                  }
                  if (prev_infowindow) {
                    prev_infowindow.close();
                  }
    
                } catch (ee) {}
              }
            }
          }
        });
    
        markers.push(marker);
      }
    
      var zoom = null;
      var size = null;
      var style = 0;
    
      markerClusterer = new MarkerClusterer(map, markers, {
        maxZoom: zoom,
        gridSize: size,
        styles: styles[style]
      });
    }
    
    function clearClusters() {
      markerClusterer.clearMarkers();
    }
    <!DOCTYPE html>
    <html>
    <head>
      <title>Google Maps Marker Example</title>
    
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk" async defer></script>
            <script src="https://unpkg.com/@googlemaps/markerclustererplus/dist/index.min.js"></script>
       <script type="text/javascript" src="mark.js"></script>
      <script>
      
        
      </script>
      <style>
        #map {
          width: 500px;
          height: 500px;
          border: thin solid black;
        }
      </style>
    </head>
    <body onload="loadMap();">
      <h1>Google Maps Marker Example</h1>
      <div id="map"></div>
    </body>
    </html>