Create marker with custom labels in Google Maps API v3

Took me quite some time to get to the bottom of how to put custom labels on markers (aka “placemarks”) in Google Maps API v3.

I must admit that I am quite puzzled as to why Google hasn’t built in this functionality in their google.Maps.Marker class. You can do a lot with that class like define a title via setTitle (i.e. creating a mouseover-tooltip for markers). Why a setLabel feature is missing… I don’t know. Instead it is necessary to write your own class – or at the very least search for a solution on some developers blog.

Now, finding a code snippet to create marker labels turned out to be more complicated than I thought. I always ended up on pages that dealt with MarkerClusterer, which primarily focusses on creating, well, marker clusters in maps that hold lots of markers. At first I tried to dig through the source code of MarkerClusterer to see how the marker labels were done. But I gave up when I realised that I had stared at the code for an hour without making any progress.

So finally I came across Marc Ridey’s blog post “Label overlay example for Google Maps API v3″. The post has the solution I was looking for, albeit in a bit of a chopped up form as some of the info required to understand what he’s done is actually explained somewhere in the depths of the extensive comments section. Some vital info about how to manipulate the zIndex of the label (to have it on top of the marker) and setting the custom label are also only found in the comments. Furthemore, the code snippet wasn’t styled up which made it a bit tricky to follow the code in the context of the blog post.

After some fiddling I came up with a version that suited my needs – i.e. place marker labels on top of each marker (rather then below) and have a customizable text (rather than the automatic label generation from the markers geographic position. So here it is, the slightly altered Label class:

// Define the overlay, derived from google.maps.OverlayView
function Label(opt_options) {
     // Initialization
     this.setValues(opt_options);
 
     // Here go the label styles
     var span = this.span_ = document.createElement('span');
     span.style.cssText = 'position: relative; left: -50%; top: -10px; ' +
                          'white-space: nowrap;color:#ffffff;' +
                          'padding: 2px;font-family: Arial; font-weight: bold;' +
                          'font-size: 12px;';
 
     var div = this.div_ = document.createElement('div');
     div.appendChild(span);
     div.style.cssText = 'position: absolute; display: none';
};
 
Label.prototype = new google.maps.OverlayView;
 
Label.prototype.onAdd = function() {
     var pane = this.getPanes().overlayImage;
     pane.appendChild(this.div_);
 
     // Ensures the label is redrawn if the text or position is changed.
     var me = this;
     this.listeners_ = [
          google.maps.event.addListener(this, 'position_changed',
               function() { me.draw(); }),
          google.maps.event.addListener(this, 'text_changed',
               function() { me.draw(); }),
          google.maps.event.addListener(this, 'zindex_changed',
               function() { me.draw(); })
     ];
};
 
// Implement onRemove
Label.prototype.onRemove = function() {
     this.div_.parentNode.removeChild(this.div_);
 
     // Label is removed from the map, stop updating its position/text.
     for (var i = 0, I = this.listeners_.length; i < I; ++i) {
          google.maps.event.removeListener(this.listeners_[i]);
     }
};
 
// Implement draw
Label.prototype.draw = function() {
     var projection = this.getProjection();
     var position = projection.fromLatLngToDivPixel(this.get('position'));
     var div = this.div_;
     div.style.left = position.x + 'px';
     div.style.top = position.y + 'px';
     div.style.display = 'block';
     div.style.zIndex = this.get('zIndex'); //ALLOW LABEL TO OVERLAY MARKER
     this.span_.innerHTML = this.get('text').toString();
};

To print labels I used the setMarker functions from the Google Map documentation example “Complex Icons” with the added label functionality:

var beaches = [
     ['Bondi Beach', -33.890542, 151.274856, 4],
     ['Coogee Beach', -33.923036, 151.259052, 5],
     ['Cronulla Beach', -34.028249, 151.157507, 3],
     ['Manly Beach', -33.80010128657071, 151.28747820854187, 2],
     ['Maroubra Beach', -33.950198, 151.259302, 1]
];
 
function setMarkers(map, locations) {
     var image = new google.maps.MarkerImage('images/beachflag.png',
     new google.maps.Size(20, 32),
     new google.maps.Point(0,0),
     new google.maps.Point(0, 32));
     var shadow = new google.maps.MarkerImage('images/beachflag_shadow.png',
          new google.maps.Size(37, 32),
          new google.maps.Point(0,0),
          new google.maps.Point(0, 32));
     var shape = {
          coord: [1, 1, 1, 20, 18, 20, 18 , 1],
          type: 'poly'
     };
     for (var i = 0; i < locations.length; i++) {
          var beach = locations[i];
          var myLatLng = new google.maps.LatLng(beach[1], beach[2]);
          var marker = new google.maps.Marker({
               position: myLatLng,
               map: map,
               shadow: shadow,
               icon: image,
               shape: shape,
               title: beach[0],
              zIndex: beach[3]
          });
          var label = new Label({
               map: map
          });
          label.set('zIndex', 1234);
          label.bindTo('position', marker, 'position');
          label.set('text', beach[0]);
          //label.bindTo('text', marker, 'position');
     }
}

A working example of above code can be found here.

Of course, there’s also an alternative method:

Google Maps only using paper and scissors !

Leave a comment ?

17 Comments.

  1. thanks. good job.
    i m waiting for the solution of removing label when marker is removed.

  2. Excellent! You saved me hours!

  3. Thank you very much.
    A couple of questions.
    1. How do markers with label text remove?
    2. How best to implement a marker with rubber wide (depend on the length of the placed label text)
    3. How do I add to your marker’s listener OnClick (or tap) event

  4. Thank you. Plus, that YouTube video is hilarious!

  5. Hi,

    The code works pretty code, but when i remove the marker using mark.setMap(null); it removes the marker, but doesn’t remove the label.

    Any thoughts on this?

    Thanks.

  6. Hi,
    how can I remove the label when I want to delete the marker?

  7. Thanks! Just what I needed.

  8. Awesome. Thanks so much for reworking the original blog post because this version you made is much better to follow.

    I think it should not be necessary to implement event listeners for static labels, right?

  9. Really nice, worked for me.
    Greetings from Germane :)

  10. Having trouble getting this to work. Your for loop in your onRemove function didn’t translate to < so I fixed that but I am still getting a "label is undefined" error when I run it. Would it be possible to post the output on the page here?

    • Hi Todd. I’ve created a working example here.

      Have you checked whether you’ve intialised the label object correctly (i.e. var label = new Label({ map: map });)? Any confusion with uppercase/lowercase?

  11. Thanks, Nice simple example, note you have a small error in your code, well more of a copy paste issue in the for loop for Label.prototype.onRemove.
    The ‘<’ should be ‘<'
    :smile:

    • Oops. thanks for pointing that out. There was similar c&p error in the setMarker function. Darn HTML entities!

  12. Thank you so much, it works! :D
    Greetings from Holland

  13. brilliant.
    thanks!

  14. Do you have a complete example?

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">