Search code examples
javascriptgoogle-mapsgoogle-maps-api-3markermarkerclusterer

GoogleMaps MarkerClusterer InfoWindow Position


I have a problem with the position of the markercluster's infoWindow. It doesn't show up at the marker position. Instead it is positioned on the upper left corner of the map. Here is my code:

<script type="text/javascript">
  function initialize(cities) {
    var mapOptions = {
      center: new google.maps.LatLng(48.220, 15.199),
      zoom: 9,
      mapTypeId: google.maps.MapTypeId.ROADMAP,
    };

    var map = new google.maps.Map(document.getElementById("map"), mapOptions);
    var markers=[];
    var markerCluster = new MarkerClusterer(map, markers, {zoomOnClick: false});

    //markerCluster should be always above the geocoder-->
     geocoder = new google.maps.Geocoder();

     for (var i = 0; i < cities.length; i++) {
      var city = cities[i];
      geocoder.geocode({'address': city.city+" Niederösterreich"}, function(results, status){
       if (status == google.maps.GeocoderStatus.OK) {
        position=results[0].geometry.location;
        var marker = new google.maps.Marker({
         map: map,
         position: position,
         title: "Ort: "+city.city + "\nBeitrag: " + city.title +"\nRed.: "+ city.reporter +"\nDatum: "+ city.storydate,
        });
        // below code alway lies inside the loop
        markers.push(marker);
        markerCluster.addMarker(marker);
       }
      });
     };

      // Listen for a cluster to be clicked
      google.maps.event.addListener(markerCluster, 'clusterclick', function(cluster) {
        var markers = markerCluster.getMarkers();

        var content = '';
        for (var i = 0; i < markers.length; i++) {
          var marker = markers[i];
          content += marker.title;
          content += ("<br>");
        };
        // Convert lat/long from cluster object to a usable MVCObject
        var info = new google.maps.MVCObject;

        var infowindow = new google.maps.InfoWindow();
        // infowindow.setPosition(this.markerCluster.getCenter());
        // infowindow.setPosition(latLng);
        infowindow.close();
        infowindow.setContent(content);
        infowindow.open(map, info);
        google.maps.event.addListener(map, 'zoom_changed', function() { infowindow.close() });
      });

    }
  </script>

Solution

  • Your MVCObject doesn't have any properties. According to the documentation, if you pass the optional anchor argument into the function .open, it must expose a LatLng position property, yours doesn't (as it doesn't have any properties, it can't expose any).

    open(map?:Map|StreetViewPanorama, anchor?:MVCObject)

    Return Value: None

    Opens this InfoWindow on the given map. Optionally, an InfoWindow can be associated with an anchor. In the core API, the only anchor is the Marker class. However, an anchor can be any MVCObject that exposes a LatLng position property and optionally a Point anchorPoint property for calculating the pixelOffset (see InfoWindowOptions). The anchorPoint is the offset from the anchor's position to the tip of the InfoWindow.

    The simplest solution is to not use the anchor argument, set the position of the infowindow directly.

    google.maps.event.addListener(markerCluster, 'clusterclick', function (cluster) {
        var markers = cluster.getMarkers();
    
        var content = '';
        for (var i = 0; i < markers.length; i++) {
            var marker = markers[i];
            content += marker.title;
            content += ("<br>");
        }
        var infowindow = new google.maps.InfoWindow();
        infowindow.setPosition(cluster.getCenter());
        infowindow.setContent(content);
        infowindow.open(map);
        google.maps.event.addListener(map, 'zoom_changed', function () {
            infowindow.close();
        });
    });
    

    proof of concept fiddle

    code snippet:

    var geocoder;
    var markers = [];
    
    function initialize(cities) {
      var mapOptions = {
        center: new google.maps.LatLng(48.220, 15.199),
        zoom: 9,
        mapTypeId: google.maps.MapTypeId.ROADMAP
      };
    
      var map = new google.maps.Map(document.getElementById("map"), mapOptions);
      var markerCluster = new MarkerClusterer(map, markers, {
        zoomOnClick: false,
        imagePath: 'https://cdn.jsdelivr.net/gh/googlemaps/v3-utility-library@07f15d84/markerclustererplus/images/m'
      });
    
      //markerCluster should be always above the geocoder-->
      geocoder = new google.maps.Geocoder();
    
      for (var i = 0; i < cities.length; i++) {
        var city = cities[i];
        geocodeCity(city, markerCluster);
      }
    
      // Listen for a cluster to be clicked
      google.maps.event.addListener(markerCluster, 'clusterclick', function(cluster) {
        var markers = cluster.getMarkers();
    
        var content = '';
        for (var i = 0; i < markers.length; i++) {
          var marker = markers[i];
          content += marker.title;
          content += ("<br>");
        }
        var infowindow = new google.maps.InfoWindow();
        infowindow.setPosition(cluster.getCenter());
        infowindow.close();
        infowindow.setContent(content);
        infowindow.open(map);
        google.maps.event.addListener(map, 'zoom_changed', function() {
          infowindow.close();
        });
      });
    
    }
    
    function geocodeCity(city, markerCluster) {
      geocoder.geocode({
        'address': city.city + " Niederösterreich"
      }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          position = results[0].geometry.location;
          var marker = new google.maps.Marker({
            map: map,
            position: position,
            title: "Ort: " + city.city + "\nBeitrag: " + city.title + "\nRed.: " + city.reporter + "\nDatum: " + city.storydate
          });
          // below code alway lies inside the loop
          markers.push(marker);
          markerCluster.addMarker(marker);
        } else {
          document.getElementById('info').innerHTML += city.city + " status=" + status + "<br>";
        }
      });
    }
    google.maps.event.addDomListener(window, "load", function() {
      initialize(cities);
    });
    
    
    var cities = [{
      city: "Sankt Polten",
      title: "title 0",
      reporter: "reporter 0",
      storydate: "November 25,2015 00:00:00"
    }, {
      city: "Wiener Neustadt",
      title: "title 1",
      reporter: "reporter 1",
      storydate: "November 25, 2015 01:01:01"
    }, {
      city: "Baden",
      title: "title 2",
      reporter: "reporter 2",
      storydate: "November 25,2015 02:02:02"
    }, {
      city: "Klosterneuburg",
      title: "title 3",
      reporter: "reporter 3",
      storydate: "November 25, 2015 03:03:03"
    }, {
      city: "Krems",
      title: "title 4",
      reporter: "reporter 4",
      storydate: "November 25,2015 04:04:04"
    }, {
      city: "Amstetten",
      title: "title 5",
      reporter: "reporter 5",
      storydate: "November 25, 2015 05:05:05"
    }, {
      city: "Modling",
      title: "title 6",
      reporter: "reporter 6",
      storydate: "November 25,2015 06:06:06"
    }, {
      city: "Traiskirchen",
      title: "title 7",
      reporter: "reporter 7",
      storydate: "November 25, 2015 07:07:07"
    }, {
      city: "Schwechat",
      title: "title 8",
      reporter: "reporter 8",
      storydate: "November 25,2015 08:08:08"
    }, {
      city: "Ternitz",
      title: "title 9",
      reporter: "reporter 9",
      storydate: "November 25, 2015 09:09:09"
    }, {
      city: "Stockerau",
      title: "title 10",
      reporter: "reporter 10",
      storydate: "November 25,2015 10:10:10"
    }];
    html,
    body,
    #map {
      height: 100%;
      width: 100%;
      margin: 0px;
      padding: 0px
    }
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
    <script src="https://cdn.jsdelivr.net/gh/googlemaps/v3-utility-library@07f15d84/markerclustererplus/src/markerclusterer.js"></script>
    <div id="info"></div>
    <div id="map"></div>