views:

1465

answers:

2

I have a Google map that is showing a number of markers. When the user moves the map, the markers are redrawn for the new boundaries, using the code below:

GEvent.addListener(map, "moveend", function() { 
    var newBounds = map.getBounds();
    for(var i = 0; i < places_json.places.length ; i++) {
       // if marker is within the new bounds then do...
       var latlng = new GLatLng(places_json.places[i].lat, places_json.places[i].lon);
       var html = "blah";
       var marker = createMarker(latlng, html);
       map.addOverlay(marker);
    }
}); 

My question is simple. If the user has clicked on a marker so that it is showing an open info window, currently when the boundaries are redrawn the info window is closed, because the marker is added again from scratch. How can I prevent this?

It is not ideal, because often the boundaries are redrawn when the user clicks on a marker and the map moves to display the info window - so the info window appears and then disappears again :)

I guess there are a couple of possible ways:

  • remember which marker has an open info window, and open it again when the markers are redrawn
  • don't actually re-add the marker with an open info window, just leave it there

However, both require the marker with an open window to have some kind of ID number, and I don't know that this is actually the case in the Google Maps API. Anyone?

----------UPDATE------------------

I've tried doing it by loading the markers into an initial array, as suggested. This loads OK, but the page crashes after the map is dragged.

<script type="text/javascript" src="{{ MEDIA_URL }}js/markerclusterer.js"></script>
<script type='text/javascript'>

function createMarker(point,html, hideMarker) {
  //alert('createMarker');
  var icon = new GIcon(G_DEFAULT_ICON);
  icon.image = "http://chart.apis.google.com/chart?cht=mm&amp;chs=24x32&amp;chco=FFFFFF,008CFF,000000&amp;ext=.png";
  var tmpMarker = new GMarker(point, {icon: icon, hide: hideMarker});
  GEvent.addListener(tmpMarker, "click", function() {
    tmpMarker.openInfoWindowHtml(html);
  });
  return tmpMarker;
}

var map = new GMap2(document.getElementById("map_canvas"));
map.addControl(new GSmallMapControl());
var mapLatLng = new GLatLng({{ place.lat }}, {{ place.lon }});
map.setCenter(mapLatLng, 12);
map.addOverlay(new GMarker(mapLatLng));

// load initial markers from json array

var markers = [];
var initialBounds = map.getBounds();

for(var i = 0; i < places_json.places.length ; i++) {
      var latlng = new GLatLng(places_json.places[i].lat, places_json.places[i].lon);
      var html = "<strong><a href='/place/" + places_json.places[i].placesidx + "/" + places_json.places[i].area + "'>" + places_json.places[i].area + "</a></strong><br/>" + places_json.places[i].county;
      var hideMarker = true;
      if((initialBounds.getSouthWest().lat() < places_json.places[i].lat) && (places_json.places[i].lat < initialBounds.getNorthEast().lat()) && (initialBounds.getSouthWest().lng() < places_json.places[i].lon) && (places_json.places[i].lon < initialBounds.getNorthEast().lng()) && (places_json.places[i].placesidx != {{ place.placesidx  }})) {
          hideMarker = false;
      }
      var marker = createMarker(latlng, html, hideMarker);
      markers.push(marker);
}

var markerCluster = new MarkerClusterer(map, markers, {maxZoom: 11});

</script>
+2  A: 

You should probably create all your markers at an initial stage with your createMarker() method, and store the returned GMarker objects inside an array. Make sure to set the hide: true property in GMarkerOptions when you create your markers, so that they would be created as hidden by default.

Then instead of iterating through places_json.places, you could iterate through your new GMarker array. You would be able to get the coordinates of each marker with the GMarker.getLatLng() method, with which to check if each marker lies within the bounds.

Finally simply call GMarker.show() for markers that lie within the bounds, or GMarker.hide() to hide them.

You would eliminate the expensive destruction/creation of markers on each map movement. As a positive-side effect, this will also solve your GInfoWindow problem.

Daniel Vassallo
Perhaps - though I have something like 2000 markers in total, which is why I'd avoided doing it this way in the first place. Do you think I can do it the way you suggest without the browser crashing?
AP257
(I suppose another way to ask this is: if I showed 2000 markers on a map it would certainly crash the browser, but if I create 2000 markers in javascript and only show 20 or 30 of them at a time, will this crash or create performance issues?)
AP257
No, 2000 hidden markers should be acceptable. They will take some time to load initially, but it should be much smoother than destroying all the markers on every mouse move and recreating the visible ones. (If you are not destroying your markers, you'll end up with a memory leak.)... You may want to check this article for some benchmarks with a big amount of markers: http://www.svennerberg.com/2009/01/handling-large-amounts-of-markers-in-google-maps/
Daniel Vassallo
Hm, I'm much more concerned about the initial load time than about smoothness if the the map is moved - anyway it looked smooth the way I had it, the only issue was the infowindow bug. I'll experiment with the way you suggested, but if anyone has any other suggestions, that would be great.
AP257
@Daniel, please see my attempt above. This loads okay, but crashes the browser after the map is dragged.
AP257
@AP257: Could it be that it is crashing because you still have the old `GEvent.addListener(map, "moveend", function()...` which is re-creating the markers?... Or is it crashing even without listening to the `moveend` event? ... If not, try commenting out the `markerCluster` to see if that is causing the crash.
Daniel Vassallo
@Daniel - fyi, I have solved the problem by simply loading all the markers on startup, using MarkerClusterer (great piece of code). It's so quick that it doesn't actually matter about displaying them all. Thanks for your assistance :)
AP257
Excellent news. Thanks for sharing this.
Daniel Vassallo
A: 

If you're using that many markers, make sure you use GMarkerManager. It's designed for many markers, with only a few visible at once.

http://mapki.com/wiki/Marker_Optimization_Tips

chichilatte