0

I've been cobbling together various bits of code from around the internet (including StackOverflow) and I've got a working map (almost) which geocodes postcodes from an array and creates infowindows for each one.

Two problems:

1) my info windows, which should take their text from another array, always use the last array value

2) i can't get the map to center automatically. I'm using a bit of code which has worked in other circumstances, but it doesn't in my code.

The code is fairly self-explanatory:

var geocoder = new google.maps.Geocoder();

var map = new google.maps.Map(document.getElementById('map'), {
  //zoom: 10,
  //center: new google.maps.LatLng(-33.92, 151.25),
  mapTypeId: google.maps.MapTypeId.ROADMAP
});

var postcodes = [
    "EH14 1PR",
    "KY7 4TP",
    "IV6 7UP"   
];

var descriptions = [
    "Slateford",
    "Cortachy",
    "Marybank"
];

var markersArray = [];

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

var marker, i, address, description;

for(var i = 0; i < postcodes.length; i++) {
    address = postcodes[i];
    description = descriptions[i];
    geocoder.geocode(
        {
            'address': address,
            'region' : 'uk'
        }, 
        function(results, status){
            if (status == google.maps.GeocoderStatus.OK) {
                marker = new google.maps.Marker({
                    position: results[0].geometry.location,
                    map: map
                });
                markersArray[i] = marker;
                console.log(markersArray[i]);
                google.maps.event.addListener(marker, 'click', (function(marker, i) {
                    return function() {
                        infowindow.setContent(description);
                        infowindow.open(map, marker);
                    }
                })(marker, i));
            } else {
                alert("Geocode was not successful for the following reason: " + status);
                return false;
            }
        }
    );

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

    $.each(markersArray, function (index, marker) {
        bounds.extend(marker.position);
    });

    map.fitBounds(bounds);
    console.log(bounds);
}

Any thoughts? The issue seems to be with the value of the counter i inside the geocode function.

Any help much appreciated!

Bryan Weaver
  • 4,455
  • 1
  • 29
  • 39
melat0nin
  • 860
  • 1
  • 16
  • 37

2 Answers2

1

1) my info windows, which should take their text from another array, always use the last array value

2) i can't get the map to center automatically. I'm using a bit of code which has worked in other circumstances, but it doesn't in my code.

1) Yes this is a closure issue. This is how I get around it.

I create an object to store all of the properties I will be using. In your example I am going to use the postcode and the description.

function location(postalcode, desc){
  this.PostalCode = postalcode;
  this.Description = desc;
}

Now do a quick loop to add all the location objects to an array.

var locations = [];
for(var i = 0; i < postcodes.length; i++) {
     locations.push(new location(postcodes[i], descriptions[i]));
}

Extract the geocode functionality into its own function with a parameter to take a location object. Then you can loop through the location object array and geocode each individually. So now both the post code and description are in scope when the request is built and sent.

function GeoCode(singleLocation){
     geocoder.geocode(
        {
            'address': singleLocation.PostalCode,
            'region' : 'uk'
        }, 
        function(results, status){
            if (status == google.maps.GeocoderStatus.OK) {
               var marker = new google.maps.Marker({
                    position: results[0].geometry.location,
                    map: map
                });

                //quick and dirty way
                bounds.extend(marker.position);
                map.fitBounds(bounds);                    

                markersArray[i] = marker;
                console.log(markersArray[i]);

                google.maps.event.addListener(marker, 'click', function() {
                        infowindow.setContent(singleLocation.Description);
                        infowindow.open(map, this); //this refers to the marker
                });

            } else {
                alert("Geocode was not successful for the following reason: " 
                      + status);
                return false;
            }
        }
    );
} 

2) As you can see above the quick an dirty way to do this is extend and fit the bounds inside of the callback function for the geocode. This causes the fitBounds function to be called multiple times and isnt really a big deal if you only have a few markers, but will cause problems if you have hundreds or thousands of markers. In that case the right-way to do this is to create an async loop function. You can see an example of it on one of my previous answers.

Here is a functioning example of the code based on your example.

Community
  • 1
  • 1
Bryan Weaver
  • 4,455
  • 1
  • 29
  • 39
  • Thanks :) I managed it myself by extracting out the various parts (loop, geocode, attach events) into separate functions, but I've not got enough rep to answer my own Q before 8 hours are up! I'll try your solution for the bounds calculation, because I wasn't able to make that work. Thanks! – melat0nin Jan 04 '12 at 22:40
0

Two problems:

1) my info windows, which should take their text from another array, always use the last array value

2) i can't get the map to center automatically. I'm using a bit of code which has worked in other circumstances, but it doesn't in my code.

Answers:

1) This is because most likely you have a closure issue here.

2) center will define the center point of your map, but in your code you have commented this //center: new google.maps.LatLng(-33.92, 151.25), removing the comment for this line will center to map to latitude of -33.92 and longitude of 151.25.
Use below:

var map = new google.maps.Map(document.getElementById('map'), {
  zoom: 10,
  center: new google.maps.LatLng(-33.92, 151.25),
  mapTypeId: google.maps.MapTypeId.ROADMAP
});
defau1t
  • 10,593
  • 2
  • 35
  • 47
  • I've tried extracting the different stages to separate functions but I'm not having much luck :(. Also, the centre attribute isn't needed (it's commented out on purpose) with that bit of code because it does the centering automagically – melat0nin Jan 04 '12 at 15:32