In usability we trust

Dynamically Toggle Markers in Google Maps

This article explains how to dynamically toggle the visibility of markers in Google Maps as well as how to deal with an annoying bug that occurs when trying to do this while using an utility library, like the MarkerManager.

Using the MarkerManager

The MarkerManager is a very useful Open Source Utility Library for Google Maps with the sole purpose to manage larger amounts of Markers. If you add markers with the MarkerManager you can control at which zoom-levels they will appear. And you can also hide and show them dynamically.

If you want to learn more about the MarkerManager and other libraries out there that deals with markers, read my article Handling Large Amounts of Markers in Google Maps.

Adding markers with the MarkerManager

Now the most effective way to add markers to the MarkerManager is to first add them to an array that you then add to the MarkerManager with the addMarkers() method. The code to do this would be something like this.

// Init the MarkerManager
var mgr = new MarkerManager();
//Defining the array that will contain all markers
var markers = [];
// Creating a marker
var marker = new GMarker(new GLatLng(57.8, 14.0));
// Add marker to the array
markers.push(marker);
// Add the array to the MarkerManager
mgr.addMarkers(markers, 1);
mgr.refresh();

Obviously it’s kind of useless to add only one marker this way. It would only be useful if you had at least a few of them, but I think you get the point.

Hiding and showing markers

In the Google Maps API there are two handy methods to toggle the visibility of markers. These are GMarker.show() and GMarker.hide(). They both work as expected, you call hide() and the markers disappears and then you call show() and the marker is displayed again.

So to hide all markers in this example you simply do this:

// Loop through all markers and hide each of them
for (var i = 0; i < markers.length; i++) {
  var marker = markers[i];
  marker.hide();
}

A bug

There is however one caveat and that is when you zoom the map the markers will magically appear again. This is an annoying bug that only appears when you use it on markers added with an utility library.

bug_description

Click the image to enlarge

The solution

So far I've only found one solution for this and that is to extend the hide method and tweak the code to place the marker outside the map, thereby making it sort of invisible.

// Saving the position of the marker and then place it outside the map
GMarker.prototype.hide = function() {
  if (this.getPoint().lat() < 90) {
    try {
        this.savePoint = this.getPoint();
        this.setPoint(new GLatLng(90, 0));
    } catch (e) { }
  }
}

Subsequently you need to prototype the show method as well so that it moves the marker into the correct position again.

// Restoring the position of the marker
GMarker.prototype.show = function() {
  if (this.getPoint().lat() == 90) {
    if (this.savePoint) {
      try {
        this.setPoint(this.savePoint);
        this.savePoint = null;
      } catch (e) { }
    }
  }
}

It's a dirty solution I know, but so far it's the best solution I've found and it works really well.

Note: I haven't come up with this solution myself but haven't been able to find where I saw it. So if you know who did come up with it, please tell me so I can give credit where credit is due.

isHidden()

The Google Maps API also offers a method to determain if a marker is hidden or not, GMarker.isHidden(). If you want to be able to use that you have to prototype it as well.

GMarker.prototype.isHidden = function() {
  if (this.getPoint().lat() == 90) {
    return true;
  } else {
    return false;
  }
}

Live examples

I've put together a few examples of different scenarios using this, so that you will see the problem as well as the solution to it.

Other libraries

There are several other libraries for dealing with markers out there, and in at least one of them, Clusterer, I've noticed the same bug as in MarkerManager. The fix proposed in this article will work just fine on that one as well and possibly on other libraries where you might also find this bug.

If you've encountered this problem in other libraries please let me know. It would also be interesting to see other, and possibly more elegant solutions to this problem.

My Google Maps book

If you found this article useful you might be interested in my book Beginning Google Maps API 3. It covers everything you need to know to create awesome maps on your web sites. Buy it on Amazon.com

Share this article

  • del.icio.us
  • Twitter
  • Facebook
  • LinkedIn
  • Digg
  • StumbleUpon
  • Google Bookmarks
  • Mixx
  • Print

Comments

RSS feed for comments on this post

1. October 12th, 2009 at 21.21 by Holger

Thank you for sharing that. The same problem occurs with MarkerClusterer by Xiaoxi Wu.

2. October 13th, 2009 at 21.53 by Gabriel Svennerberg | Author comment

Ok, I suspected that it would occur in other libraries as well. Thanks for letting me know!

3. January 23rd, 2010 at 16.25 by Pär Lindholm

Thank you so much! I was getting pretty frustrated before stumbeling on your solution. Works just perfect.

/Pär

4. April 12th, 2010 at 15.05 by NSairam

Hi,

I have found an easy solution for this issue and hope it may help. I also tested thoroughly. The fix is given below.

private var mgr:MarkerManager;

if(mgr==null)
{
mgr = new MarkerManager(map,{});
}else
{
map.clearOverlays()
mgr.clearMarkers();
map.clearOverlays()
}

NOTE: I have pasted below the complete code for viewing a sample example implemented with the fix for markermanager utitlity bug.

//*****************************************************

<![CDATA[
import mx.controls.Alert;
import com.google.maps.MapEvent;
import com.google.maps.Map;
import com.google.maps.overlays.Marker;
import com.google.maps.MapType;
import com.google.maps.LatLng;
import com.google.maps.LatLngBounds;
import com.google.maps.extras.markermanager.MarkerManager;

public var markerArr:Array = [];
private var mgr:MarkerManager;

private function createMarkers():void
{

var bounds:LatLngBounds = map.getLatLngBounds();
var southWest:LatLng = bounds.getSouthWest();
var northEast:LatLng = bounds.getNorthEast();
var lngSpan:Number = northEast.lng() – southWest.lng();
var latSpan:Number = northEast.lat() – southWest.lat();
markerArr=[]
for (var i:int = 0; i

//*****************************************************

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>