[GIS] Drop Markers and MarkerCluster together from database

markersMySQL

I've been working on my map which gets it's details from a MySQL database.
I use MarkerCluster Plus to cluster my markers but would like to add the drop animation to it.

I found this thread, but cannot get it to work with my database.
Using Drop Markers and MarkerClusterer together?

Would anyone please be able to help me figuring out how to add the drop animation to my code? My test map is here: http://mymap.mooo.com

Really appreciate any help or pointers.

 var customIcons = {
  BOO: {
    icon: 'http://labs.google.com/ridefinder/images/mm_20_blue.png'        
  },
  CIE: {
    icon: 'http://labs.google.com/ridefinder/images/mm_20_green.png' 
  } 
};

var cluster =[];     
var min = .999;
var max = 1.001;


function load() {
  var map = new google.maps.Map(document.getElementById("map"), {
    center: new google.maps.LatLng(0,28.287167),
    zoom: 3,
    mapTypeId: 'roadmap'
  });

  var infoWindow = new google.maps.InfoWindow;    
  var mcOptions = {gridSize: 20, maxZoom: 19};    
  // this variable will collect the html which will eventually be placed in the side_bar 
  var side_bar_html = ""; 

  // Change this depending on the name of your PHP file
  downloadUrl("phpsqlajax_genxml2.php", function(data) {
    var xml = data.responseXML;
    var markers = xml.documentElement.getElementsByTagName("marker");
    for (var i = 0; i < markers.length; i++) {
      var name = markers[i].getAttribute("assetno");
      var address = markers[i].getAttribute("address");
      var type = markers[i].getAttribute("type");
      var assetdesc = markers[i].getAttribute("assetdesc");
      var location = markers[i].getAttribute("location");
      var point = new google.maps.LatLng(
          parseFloat(markers[i].getAttribute("lat"))* (Math.random() * (max - min) + min) ,
          parseFloat(markers[i].getAttribute("lng"))* (Math.random() * (max - min) + min));
      var html = "<div style='font-family: Arial; font-size: 12px;'><b>" + name + "</b> <br/>" + assetdesc + "<br/>" + location + "</div>";
      var icon = customIcons[type] || {};

      setTimeout(function() {
        var marker = new google.maps.Marker({
            map: map,
            position: point,
            icon: icon.icon,            
            animation: google.maps.Animation.DROP   
        });         
        return marker;

        setTimeout(function () {                
            bindInfoWindow(marker, map, infoWindow, html);       
            cluster.push(marker);   
            // save the info we need to use later for the side_bar
            // add a line to the side_bar html
            side_bar_html += '<a href="javascript:myclick(' + (cluster.length-1) + ')">' + name + ' - ' + assetdesc +'<\/a><br>';   
        }, 1500);
      }, i * 50);

    }                     
    var markerCluster = new MarkerClusterer(map, cluster, mcOptions);   
    // put the assembled side_bar_html contents into the side_bar div
    document.getElementById("side_bar").innerHTML = side_bar_html;        
  });     
}

// This function picks up the click and opens the corresponding info window
function myclick(i) {
    google.maps.event.trigger(cluster[i], "click");
}   

function bindInfoWindow(marker, map, infoWindow, html) {
  google.maps.event.addListener(marker, 'click', function() {
    infoWindow.setContent(html);
    infoWindow.open(map, marker);
  });
}

function downloadUrl(url, callback) {
  var request = window.ActiveXObject ?
      new ActiveXObject('Microsoft.XMLHTTP') :
      new XMLHttpRequest;

  request.onreadystatechange = function() {
    if (request.readyState == 4) {
      request.onreadystatechange = doNothing;
      callback(request, request.status);
    }
  };

  request.open('GET', url, true);
  request.send(null);
}

function doNothing() {}

Best Answer

I think I found the problem with your code. I've highlighted the line below:

setTimeout(function() {
    ...

        icon: icon.icon,            
        animation: google.maps.Animation.DROP   
    });         

    return marker; // <---!!!!!!! This line !!!!!!!!!

    setTimeout(function () {                
        bindInfoWindow(marker, map, infoWindow, html);       
    ...

}, i * 50);

Calling return marker; here exits the downloadUrl function. Anything after the return statement isn't executed, so the second setTimeout is never reached and the marker is never added to the cluster.

Because your code is all in one function, the second setTimeout has access to the marker variable. Removing return marker; will allow the code contained in the second setTimeout to execute. Note that I can't test that this will fix the issue because I don't have access to your data script and link that you provided doesn't match the example code in the question. But I think it should do the trick.

Update (10/15/2012): Reply to Comment

Ok. I see two problems with your demo code.

First, remove the random number generation. I used that in my example to generate random coordinates. You seem to have lat/lng for all of your points, and multiplying them by a random number is not what you want do.

This:

var point = new google.maps.LatLng(
parseFloat(markers[i].getAttribute("lat"))* (Math.random() * (max - min) + min) ,
parseFloat(markers[i].getAttribute("lng"))* (Math.random() * (max - min) + min));

Should be:

var point = new google.maps.LatLng(
    parseFloat(markers[i].getAttribute("lat")),
    parseFloat(markers[i].getAttribute("lng"))
);

Secondly, you need to add the markers to an instance of markerCluster. Right now, they are just being added to the array cluster. Either make cluster a markerClusterer instance, or instantiate another variable to use as your markerClusterer instance. For example: var mc = new MarkerClusterer(map);. Then use mc.addMarker(marker); to add a marker to the cluster in the second setTimeout.

Update (10/16/2012): Reply to 2nd Comment

Sorry--there's still one issue with your code. Because of the way JavaScript works (asynchronously) and the way your code is structured, when the first setTimeout is called, all the variables used to construct the marker (point, type, etc) are actually referencing the last item in your data. You have to break your code into smaller functions (generally a good practice to follow anyway), and use what's called a closure. More on that here: https://stackoverflow.com/questions/111102/how-do-javascript-closures-work. Here is a simplified example how this technique can be used to implement marker animation + markerClusterer: http://jsfiddle.net/WASLk/2/.

Note that I didn't need to do this in my original example because all the data used to build the markers (the random coordinates) was contained within the addMarker function.