0

I'm having trouble with pins on a Google Map from street addresses. I'd like to place the pins, set the zoom level to the highest required to show all the pins placed (ie zoomed in on the 3 locations in my example) and have the infoWindows on the pins with the content from my array.

I have an array (locations) of addresses[1], along with the information[0] I'd like to place in an InfoWindow. I have the geocoding working, my pins are placed on the map. The map doesn't zoom in on my pins nor does it display the infoWindows.

This is the code I have:

<div id="map" style="background:#db7093;height:600px;width:auto;"></div>

<script type="text/javascript">
var locations = [
    ["<a href=\"https://example.com/building1/\">Library</a>", " 350 W Georgia St, Vancouver, BC, Canada", 1],
    ["<a href=\"https://example.com/building2/\">City Hall</a>", "453 W 12th Ave, Vancouver, BC, Canada", 2],
    ["<a href=\"https://example.com/building3/\">Art Gallery</a>", "750 Hornby St, Vancouver, BC, Canada", 3]
];
</script>
<script type="text/javascript">
function mapAddress(currentLocation, bounds) {
    var geocoder = new google.maps.Geocoder();
    var marker = new google.maps.Marker();

    var address = currentLocation[1];

    geocoder.geocode({
        "address": address
    }, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            map.setCenter(results[0].geometry.location);
            if (marker)
                marker.setMap(null);
            marker = new google.maps.Marker({
                map: map,
                position: results[0].geometry.location,
                draggable: false
            });

            bounds.extend(marker.position);

            google.maps.event.addListener(marker, "click", (function(marker, i) {
                return function() {
                    infowindow.setContent(currentLocation[0]);
                    infowindow.open(map, marker);
                }
            })(marker, i));
        } else {
            alert("Geocode was not successful for the following reason: " + status);
        }
    });
}

function initMap() {
    window.map = new google.maps.Map(document.getElementById("map"), {
        mapTypeId: google.maps.MapTypeId.ROADMAP
    });

    var infowindow = new google.maps.InfoWindow();

    var bounds = new google.maps.LatLngBounds();

    for (i = 0; i < locations.length; i++) {
        var currentLocation = locations[i];

        mapAddress(currentLocation, bounds);
    }

    map.fitBounds(bounds);
    map.panToBounds(bounds);

    var listener = google.maps.event.addListener(map, "idle", function() {
        map.setZoom(14); // Manually setting zoom level, as fitBounds isn't working
        google.maps.event.removeListener(listener);
    });
}
</script>
<script async defer src="https://maps.googleapis.com/maps/api/js?key=[MyGoogleMapsAPIKeyHasBeenRemoved]&callback=initMap"></script>
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
  • 1
    Did you watch the javascript console for errors? I get `Uncaught ReferenceError: infowindow is not defined` obviously because the `infowindow` variable is declared within the `initMap` function and used in `mapAddress`. – MrUpsidown Feb 24 '21 at 11:16
  • 2
    Fixing the scope issue I mentioned above will fix the issue with infowindows. Also note that the geocoder service is asynchronous so you end up doing the fitbounds before (all) markers are created. You should do it differently. – MrUpsidown Feb 24 '21 at 11:40

1 Answers1

2
  1. Create your infowindow and bounds variables with the right scope. Learn about variables scope in JS.
  2. I have removed the if (marker) marker.setMap(null); portion as I could not think of why you used it.
  3. I have moved the map.fitBounds(bounds) to the geocoder callback as otherwise it is executed before all markers are created (Geocoder is asynchronous), in other words, you were calling fitBounds after the for loop is finished, but at that time, the Geocoder has not finished getting the information from the API and/or creating the markers.
  4. I have removed the closure around the marker listener because it is not needed.
  5. I have removed the map.panToBounds(bounds); which is unnecessary.
  6. I have removed your empty google.maps.Marker declaration which is unnecessary.
  7. I have removed your map idle event which is unnecessary as the appropriate zoom level will be set by the fitBounds method.
  8. You should be aware that the Geocoder has a limit of 50 requests per second, so if your list of locations is bigger than 50, your code - as it is - might well send more than 50 requests per second.

var locations = [
  ["<a href=\"https://example.com/building1/\">Library</a>", " 350 W Georgia St, Vancouver, BC, Canada", 1],
  ["<a href=\"https://example.com/building2/\">City Hall</a>", "453 W 12th Ave, Vancouver, BC, Canada", 2],
  ["<a href=\"https://example.com/building3/\">Art Gallery</a>", "750 Hornby St, Vancouver, BC, Canada", 3]
];

var bounds, infowindow;

function mapAddress(currentLocation, bounds) {
  var geocoder = new google.maps.Geocoder();
  var address = currentLocation[1];

  geocoder.geocode({
    "address": address
  }, function(results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
      map.setCenter(results[0].geometry.location);
      var marker = new google.maps.Marker({
        map: map,
        position: results[0].geometry.location,
        draggable: false
      });

      bounds.extend(marker.position);
      map.fitBounds(bounds);

      google.maps.event.addListener(marker, "click", function() {
        infowindow.setContent(currentLocation[0]);
        infowindow.open(map, marker);
      });
    } else {
      alert("Geocode was not successful for the following reason: " + status);
    }
  });
}

function initMap() {
  window.map = new google.maps.Map(document.getElementById("map-canvas"), {
    mapTypeId: google.maps.MapTypeId.ROADMAP
  });

  infowindow = new google.maps.InfoWindow();
  bounds = new google.maps.LatLngBounds();

  for (i = 0; i < locations.length; i++) {
    var currentLocation = locations[i];
    mapAddress(currentLocation, bounds);
  }
}
#map-canvas {
  height: 180px;
}
<div id="map-canvas"></div>

<!-- Replace the value of the key parameter with your own API key. -->
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap" async defer></script>
MrUpsidown
  • 21,592
  • 15
  • 77
  • 131
  • 1
    Thank you very much, especially for the comments on the changes you made. Very much appreciated. My plan is to store the lat & long values in the db as items are shown on the map, so I'm only looking them up if the coordinates aren't already known. Thank you for the heads up on the 50 per second request limit. – Sandbox Wizard Feb 24 '21 at 14:15