The function called inside the ‘map_changed’ listener of Google Maps is called multiple times

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 is closed.

I use the ‘map_changed’ listener to the markers to check if the marker has been “absorbed” into a cluster. If so, the InfoWindow is closed and I want to call another function one time only. The problem is that in my current code, the function gets called for multiple markers.

How can I either add the ‘map_changed’ listener to the currently-selected marker only? If this is not possible, how can I prevent the function being called multiple times? Do I need to temporarily remove the ‘map_changed’ listener to non-selected markers?

The function I want to call is named “closeMarker()”. Please see the JSfiddle.

JS:

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();
              }
                         closeMarker();
            } 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();
}

function closeMarker()
{
    console.log('x');
}

HTML:

<!DOCTYPE html>
    <html>
    <head>
      <title>Google Maps Marker Example</title>
    
    <script src="https://maps.googleapis.com/maps/api/js" 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>

Answer

One option to address the issue would be to set the variable curMark to null when you close it’s InfoWindow and move the call to closeMark to the code that closes the InfoWindow and sets the curMark variable to null.

Also, not sure why you are setting infowindow to null there, but if you do that, it will only call closeMarker one time.

Updated map_changed listener:

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();
             closeMarker();
             curMark=null;
           }
           if (prev_infowindow) {
             prev_infowindow.close();
           }
         } catch (ee) {}
      }
     }
   }
});

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, 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();
                closeMarker();
                curMark=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();
}

function closeMarker() {
  console.log('x');
}
<!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>
  <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>