Update: Once you’re through with this article, there’s a followup that shows how to also make them clickable.

Many people find the object-oriented aspect of JavaScript to be very confusing. Fortunately, the designers of the Google Maps API have managed to make it extremely accessible—if all you ever did was instantiate their classes and then build scripts around those objects, you could still create very interesting and compelling maps. Creating a cool map is firstly about content, and secondly about technology.

However, there comes a point when you butt up against a limitation of the API, and it’s at that point that you can begin to explore the dynamic flexibility that JavaScript offers. To that end, I’d like to share a simple method of extending GMarker to allow for a text label to sit on each icon, like so:

Labeled Markers

But first, an announcement and disclaimer:

I am now working for Google. My school has a very strong co-op program, and as part of that, I was hired to work as an intern with the Maps Team in New York City for four months. As such, I cannot make any more speculative posts about future API or Maps features. And anything here that could be construed to be an opinion is not one held by my employer.

And with that out of the way, let me show you how to do labeled markers.

Reconnaissance

As we mentioned in the book, everything that goes on a map implements the GOverlay interface. It’s not as scary as it sounds; all this means is that every object you try to add to a map must have three basic functions: initialize, redraw, and remove. The map will call initialize on the overlay to tell it to generate the DOM elements that represent itself, redraw when it wants them moved to the correct position, and remove when it wants it to remove and destroy those same DOM elements.

One option is to create your own class from scratch, implementing this interface. This however, is silly, for two reasons:

  1. The API already helps you out a lot with browser compatibility issues. Transparent PNGs don’t display properly in IE6, for example, and the API’s GMarker class has hacks in place to deal with that. If you implement your own Marker class from scratch, you’ll be reinventing the wheel on this front.
  2. GMarker already has a whole bunch of code in place to handle simple events like clicks and so-on, but also much more complicated things like the draggability. Why throw that all away?

As you can see, the ideal is not to work with GOverlay, but with GMarker. It’s not a lot of functionality we’re adding, and we’d like to just gently bolt it onto what’s already there in the standard class.

JavaScript Inheritance

I’m not going to talk a lot about how to do inheritance in JavaScript. A quick web search will reveal that far too much ink has been spilled on the topic already. I’m just going to use the absolute most basic approach possible, and along the way point out its big drawback.

So, the plan is that I’ll create a new class called LabeledMarker, which inherits everything from GMarker, but responds to three additional parameters in the options array of its constructor. In instead of just draggable and icon and so on, you’ll get these three new choices:

  • labelText will be what to put on the marker, a string.
  • labelClass will be what class to give the marker div, so that it can be targetted with CSS.
  • labelOffset will be a GSize object, indicating where to put the div, relative to the marker’s base.

Now, to make that happen, I have to subclass GMarker, and in the new constructor have code that knows what to do with those three new properties. Then, at the end of the new constructor, I have to call the original GMarker constructor, so that it can handle the rest of the parameters. Unfortunately, the code for calling the original constructor is a little weird, but you can accept it on faith for the moment, and read up later:

function LabeledMarker(latlng, options){
    this.latlng = latlng;
    this.labelText = options.labelText || "";
    this.labelClass = options.labelClass || "markerLabel";
    this.labelOffset = options.labelOffset || new GSize(0, 0);
    GMarker.apply(this, arguments);
}

Now, that handles the constructor, but the real key to JavaScript’s inheritance model is setting an object’s prototype property to be equal to some other object, which lets the one access the other’s methods and properties. In this case, we want LabeledMarker to have GMarker as its prototype, so we try to do this:

LabeledMarker.prototype = GMarker;

Ack, it doesn’t work! Rather than assigning the GMarker function directly like this, we have to assign an instance of it, an object. But we can’t create an instance of a GMarker until we know where on the map we’re putting it, right? Unfortunately, the awkward hack necessary here is that a GMarker must be instantiated with a dummy GLatLng. This GLatLng does nothing other than let GMarker’s constructor execute to completion so that its methods may serve as prototypes for our new class:

LabeledMarker.prototype = new GMarker(new GLatLng(0, 0));

And there, is the basics of JavaScript inheritance. But of course, we’re not done yet—we haven’t actually implemented the rest of LabeledMarker.

Initialization: Putting LabeledMarker on the Map

The initialize function is the one that actually adds DOM elements to the map. You may need to brush up on this, but the main bits you need to know are createElement and appendChild.

If we call the initialize function belonging to GMarker right at the beginning of LabeledMarker’s initialize function, then we’ll know right away that the rest of the elements have already been added correctly. This means the image for the marker itself, its shadow, and whatever other magic goes on in there. All that’s left for us to do is tack on the little text div holding our label message. We need to create it, assign a few properties, and then append it to the correct div which holds marker DOM elements. In the end, it’s pretty straight forward:

LabeledMarker.prototype.initialize = function(map) {
	GMarker.prototype.initialize.call(this, map);

	var div = document.createElement("div");
	div.className = this.labelClass;
	div.innerHTML = this.labelText;
	div.style.position = "absolute";
	map.getPane(G_MAP_MARKER_PANE).appendChild(div);

	this.map = map;
	this.div = div;
}

Again, unfortunately JavaScript is such that the call to the parent initialize method is a little hairy. What’s happening there makes sense, but this is not the place for that explanation.

The other main thing happening here is that the CSS position value of the div is set to absolute. This is necessary to be able to precisely set its pixel position.

And finally, pointers to the div and map are stored as instance variables in the marker, so that other functions may later have access to them.

Redraw: Setting The Position

Thanks to helper functions in the API, setting the position of a LabeledMarker is extremely painless. The redraw function acts primarily as a pass-through to functions exposed in the API:

LabeledMarker.prototype.redraw = function(force) {
	GMarker.prototype.redraw.call(this, map);

	// We only need to do anything if the coordinate system has changed
	if (!force) return;

	var p = this.map.fromLatLngToDivPixel(this.latlng);
	var z = GOverlay.getZIndex(this.latlng.lat());

	this.div.style.left = (p.x + this.labelOffset.width) + "px";
	this.div.style.top = (p.y + this.labelOffset.height) + "px";
	this.div.style.zIndex = z + 1; // Directly in front of the marker image
}

All it does is use fromLatLngToDivPixel to grab pixel coordinate values, and then plug them directly into the Left and Top stylesheet properties.

Responsible Code: Destroying Itself Afterward

The removal function is very simple, it zaps the one div we created, and then passes control to GMarker, to do the cleanup that it needs to do:

LabeledMarker.prototype.remove = function() {
  this.div.parentNode.removeChild(this.div);
  this.div = null;
  GMarker.prototype.remove.call(this);
}

And there you have it. You can run away and see the working demo of this, or you can stick around for a few additional notes, and a full list of source code.

A Word About Events

As you can see in the demo, the new markers do not respond to being clicked on. This is not hard to add, but for simplicity’s sake it’s not something I wanted to cover in this article. The basic principle would be to have the initialization function scoop up a pointer to whatever the element is that GMarker creates, and then have any clicks that hit the text div be passed through to that element.

Additionally, you’d have to add stylesheet properties to reinstate the grabbing-hand mouse pointer.

Update: This followup article explains how to handle events, and provides a fully updated version of the code.

A Word About The Demo

As in the disclaimer, I just moved to New York a few weeks ago. I live in East Village, and I walk to Google’s lovely Chelsea office. But with the vast diversity of neighbourhoods on the island, I thought it would be fun to put together a quick map of them.

Now, the point was mainly to illustrate labeled markers and JavaScript inheritance, not to make a sweet Manhattan mashup. If one were to do that, I would definitely recommend using the awesome new GPolygon stuff to actually outline the road boundaries.

The even cooler thing to do, would be to take advantage of Wikipedia’s article on the topic, and directly harvest out the street boundaries of the different regions, interpreting and geocoding them as necessary. Obviously, this is more difficult than simply entering them by hand, but perhaps it might be possible to create something broad enough that it would work across multiple data sets, like the L.A. and Chicago neighbourhoods.

The purpose of these articles and demos, after all, is to spur your imagination, to toss out ideas for future projects and endeavours.

The Files Involved


34 Responses to “Extending The API To Create Labeled Markers”  

  1. 1 Cam

    Nice work Mike! It’s nice to wake up and see such an in-depth article.

    To anyone who wants to help others find this article, please consider digging it:
    http://digg.com/programming/Extending_the_Google_Maps_API_to_Create_Labelled_Markers

    PS: It’s nice to know that we can finally let people know that you work for Google now. It’s been a hard secret to keep for the last month.

  2. 2 Xchanius

    Excellent example, thanks for posting this.

    Couple of questions:

    1. Will this work with the new ‘Marker Manager’?

    2. Can you show the code snippet of what it would take to get clicks working?

  3. 3 Mike

    Xchanius: Yes, LabeledMarker is perfectly compatible with GMarker, to the point that it works with GMarkerManager. There was a slight problem in the remove() method, but I’ve corrected it in the code and the article now. You can see in the demo that if you zoom out two levels, the marker manager yanks all those markers off the map, including the text overlays we added.

    As to clicks, watch for the next article to get a proper explanation of that.

  4. 4 David Riding

    A VERY good google maps lettered marker API example: http://www.econym.demon.co.uk/googlemaps/examples/map2a.htm

  5. 5 Mike

    David: That’s an okay example if you want to make use of Google’s own pink markers with the single letters on them; the point of this code is to show how to extend the API in a way that easily allows short codes or labels on the markers.

  6. 6 Alina

    Thank you for this article. It solved my problems with my google map.

  7. 7 Adam Risser

    Great extension, though I am having some difficulty with it in IE. I have 90 markers on my custom map which really makes IE take a performance hit (though I think performance starts degrading at around half that amount). Any insider tips on tweaking the performance for IE?

    My map:
    http://muweb.millersville.edu/directions/v3/

    Thanks again for the great extension!

  8. 8 Bill

    MSN I NIIPET
    MSN

  9. 9 Tony Dow

    Hi. Is it possible to click on a map, add a marker at the click point and have a label or infoWindow displaying the Lat/Long

  10. 10 harry

    hi,

    Excellent job, thanks a lot for posting it. I’ve some questions and need your help:

    Can you pls. tell me how to implement same in asp.net 2.0 with c#.
    As this code includes map_data.php file, how can i get its substitute in asp.net?

    Actual task is :

    I’ve to create location names in english for thailand map. and the most important thing is all the postions gets highlighted when we perform search according to hotels, shopping,etc at a particular Location Like for e.g in pattaya(in thailand).

    Its quite urgent.

    Thanks.

  11. 11 DonB

    Thank you for writing an article that explains ‘why’, not just ‘what’ like so many others do. For example, when I read the code snippet with the ‘absolute’ CSS attribute I instantly thought, ‘Why?’ I was pleased to see you address that just two paragraphs later.

  12. 12 Peng Fang

    The extension is very useful. I really appreciate its development.
    I am having trouble to display ‘-’ together with any text, such as ‘-5mm’. the text after ‘-’ will be offset to a new line. I wonder if anybody could help me out on this.
    Thank you in advance.

  13. 13 Edmundo

    Thanks for the help! I’m kind of understanding this javascript/google maps relationship a whole lot better…

    I was wondering if there is any way to just use a GIcon class to change a custom GMarker, though… or do I have to set my icons/shadows through custom images?

  14. 14 ALoughe

    Your labeled marker code is great. I have found it very useful to add a span element to the labelText, thus identifying all of my sites (locations) with a nice CSS embellished label. I can also alter the CSS once a site has been chosen (clicked). I do this with: onClick=”this.className=’pinClicked’, and I use a different set of CSS for ‘pinClicked’ events. When I want to choose a whole new set of sites, I simply click a “reset” button, which returns all of my labels to their original state (quickly re-loads all of the individual sites). Since the sites (locations) I am interested in are labeled nicely using your code and my fancy CSS, I don’t even use an image to show the location of the sitte, I don’t need a “dot” to know where it is, the label tells me quite clearly. When loading many sites (say over 500), I find it much quicker for Google Maps not to have to load any marker images. It’s very fast without the images!

  15. 15 aniket

    Can we make text in labeled Marker bold if yes how?

  16. 16 Daniel

    2 comments:
    - yes you can make the labeled Marker bold in the CSS
    for example you can add in the css section:

    div.LabeledMarker_markerLabel {
    font-size:14px;
    font-weight: bold;
    font-family:tahoma,arial,sans-serif;
    background-color: #d7d7d7;
    }

    - I managed to make it work with draggable markers
    - first remove the reset of the flag in the constructor section
    // if (opt_opts.draggable) {
    // This version of LabeledMarker doesn’t support dragging.
    // opt_opts.draggable = false;
    // }

    then add the following line at the first line of the redraw() function:
    this.latlng_ = this.getLatLng();

    and you’re all set (at least with Firefox, I didn’t test with other browsers but I don’t see why it should make any difference.

    Regards
    Daniel

  17. 17 Ted

    Hi. I read your article and it’s very interesting, though a little over my head in places. I have a basic map page (http://www.infolingua.ie/map.html) which I’d like to develop into quite a large project. I want to translate placenames using labels.

    Before I do that, though, I need to find out how to have markers with text labels which can be visible or not depending on the zoom level.

    I have implemented the Overlay function with my labels but I don’t know how to get this to work with zoom. Kilcormac is a smaller town than Offaly, so on my page I would like it to come in at a higher zoom level than Offaly. In my implementation they both appear together. If I had lots of markers, the map would get very cluttered.

    I found a tutorial ( http://econym.googlepages.com/markermanager.htm ) showing how to use GMarkerManager, which enables disappearance and reappearance of labels depending on zoom level, but the author says it can’t be used with Overlay (”Don’t perform both map.addOverlay() and mm.addMarker() on the same marker.”). In his example there are no text labels, so is it not possible to have labels with markers under GMarkerManager?

    My main question is, how can I get markers *with labels* that can respond to zooming? I’d greatly appreciate any help you can give me.

  18. 18 WyriHaximus

    @aniket It’s a DIV so you can place any HTML in it as you please :).

  19. 19 DS

    Anyone get labeled markers to work correctly in Opera? All the labels have grey backgrounds and black text.

  20. 20 Bassy

    Hi,
    I really really like your example.
    Is there any way to delete all markers and start with a clean map even thogh there are markers all ready on the map? ( I mean with out refreshing the page.)
    If any one can help please let me know.
    Thanks in advance!!

  21. 21 tweakmy

    dear mike,
    Nice post there. I ve been using your example to direct my friends to my wedding location.

    I have incorporated the direction in the googlemap as additional to your exmpale. But my problem is when using GEvent.addListener(map,”singlerightclick”,function(pixel,tile,ovrlay)
    the Label is not being detected by the event listener though it works for the picture. The div area simply does not respond to the event listener. How can i fix this, so that the event listener would also be captured for the div area comprising of the label text? Thank you.

  22. 22 jan

    hi!

    many many thanks for posting this. I was looking for ways to extend google map methods in v2 for days until i found your site! thanks!

  23. 23 jan

    one more question, how do you properly override existing methods in, for example, GMarker, it has openInfoWindowTabsHtml method and i want to override this to accomodate some additional settings of my own??

    thanks in advance!

  24. 24 AbennaSlulsen

    Hi everybody, I just signed up on this marvelous community forum and wanted to say hello there! Have a incredible day!

    AbennaSlulsen

  25. 25 chaise lounge chair cushions

    I would like to thank you for the endeavors you have made in publishing this article. I am trusting the same best work from you in the future as well. In fact your fanciful writing abilities has inspired me to start my own blog now. Genuinely the blogging is spreading its wings rapidly. Your write up is a fine example of it.

  26. 26 Saiven

    Unsure if it’s my Laptop considering I still just had not any time to upgrading and i am continue to making use of internetexplorer 6 but while looking at your web page I’ve witnessed some sort of strange characters everywhere in the page, in case it is very important I merely assumed I’d inform you about. It shows that along with a variety of different txt immediately after it, such as Warning: Cannot change head string … and so forth. It’s a bit weird simply because for me sites like as an example google.com and yahoo.com as well as my very own one young driver car insurance show up good for me.

  27. 27 Gus

    Thanks for sharing your information and source code - much appreciated. I will no doubt purchase this book.

  28. 28 Jaanus

    Hi,

    is there onyone who could help me with google map? Is there any way to create the markes on the google map that the label names will appear constantly near the marker point?

    thanks,
    Jaanus

  29. 29 Ted Conn

    This is excellent, so nice to be able to at least pass an id in to the marker to save reference to the original address!

  30. 30 shadrack

    I’m trying to use your code in a google map that’s using v3 methods. Is this possible, or is there an updated out there to use with google maps api v3?

    Here’s the page…julieshad.com/so_or_ag/agguide_map2.html

    Thanks for any help!

  1. 1 MonALISA Fantastic Team » How to create your own map using Google Map API
  2. 2 Leons Blog » Blog Archive » Create labeled markers in GM by subclassing the GMarker
  3. 3 chipwreck | blog » archive » Google maps customization
  4. 4 JIRA: Iteration Backlog Scrum Team



Buy Our Books!

(Here's Why) PHP book Rails book DOM book mashups book