Clickable LabeledMarker
Published by Mike March 6th, 2007 in JavaScript, OverlaysBack in January, I demonstrated how to extend GMarker for text-based labels. In the interests of keeping things simple, I ignored any event handling, and just covered the nuts and bolts of how to make a wrapper class in JavaScript, and how to add the basic functionality we wanted.
Well, we had a number of requests by email for an explanation of how to set this up with clickable markers, so here it is. First, I’ve made a new version of the demo, which now features the traditional infoWindow popups, triggered by either marker clicks or selection from the sidebar.

If you just want the source for the new version, it’s right here. There’s a brief discussion of the changes, below the jump.
Constructor
In the original LabeledMarker constructor, there were a handful of or-blocks that could take advantage of the new entities in the GMarkerOptions array. We need to change this slightly, now, so that we can keep track of whether or not we’re supposed to be a clickable marker. Also, since this version still doesn’t support dragging, I’m adding an if-block to specifically disallow it:
this.clickable = options.clickable || true;
if (options.draggable) {
// This version of LabeledMarker doesn't support dragging.
options.draggable = false;
}
Nothing too scary there. Basically, if the programmer tries to instantiate a draggable LabeledMarker, we change it back on them. There are better ways this error could be handled, but this is reasonably graceful and doesn’t waste a lot of bytes.
GEvent Initialization
The real meat of this happens in the initialize method; that’s where all the markup comes into play, and that’s where our event handlers need to take shape. The thing is, though, we’re really not trying to do anything too complicated hereāall we want is for any event that happens on our new div to we passed through to the marker. In fact, it’s as simple as setting up a loop to iterate through known events:
if (this.clickable) {
var eventPassthrus = ['click', 'dblclick', 'mousedown', 'mouseup', 'mouseover', 'mouseout'];
for(var i = 0; i < eventPassthrus.length; i++) {
var name = eventPassthrus[i];
GEvent.addDomListener(div, name, newEventPassthru(this, name));
}
// Mouseover behaviour for the cursor.
div.style.cursor = "pointer";
}
The newEventPassthru function just returns a simple handler:
function newEventPassthru(obj, event) {
return function() {
GEvent.trigger(obj, event);
};
}
This code doesn’t pass through any arguments of the event, but none of the GMarker events have arguments anyways, so this is no loss. If the spec were to change, and onclick (for example) began returning a coordinate pair for where it was clicked, this implementation would have to be revisited.
Clean Up
The remove function now has an extra line, to zap all those extra event handlers, when the marker gets deleted. We could have saved all the listener handlers ourselves, but why bother, when this sweet automatic method does all the work for us?
GEvent.clearInstanceListeners(this.div);
Cleaning up like this may seem like a big deal over nothing, but it’s really important in order that code like the Marker Manager may function properly; the Manager depends on being able to reliably add and remove markers from a map, and not have memory leaked all over the place when it does so.
The Files Involved
You can see that labeled_marker.js now has the Apache License boilerplate on it. This is a very general license whose main provision is attribution. That is, you’re welcome to use or redistribute labeled_marker.js in whole or in part, just please always leave my name and copyright notice attached to it. (There’s another reason for choosing this particular license, but for that you’ll have to wait and see…)


Get emailed automatically
Hello,
I wanted to take this time to thank you for keeping this blog up to date with more samples like this. My employer wanted me to create a google maps mashup for them and I had never before used JavaScript. They expensed the cost of your book for me and I must say this is really a great book and well worth the cost. I have learned quite a bit about JavaScript and the Google API just by picking up the book and getting my hands dirty.
Over the last week this is what was created for my employer.
http://www2.ereawards.com/attendee-map/
Thanks again for all of the hard work you put into writing this book, it will be a great reference tool on my bookshelf.
Joseph: That’s a neat map, thanks for sharing. I like the concept of clicking on the zoomed-out marker to see the closer view. Maps itself does something similar for the new Traffic view, but you have to click to bring up the infoWindow, and then click again to zoom to street level…
Anyhow, I’m glad you’re enjoying the book and blog. Let us know if you have any questions or a request for a particular tutorial topic. :)
Nice work Mike,
Firebug throws a message “Element referenced by ID/NAME in the global scope. Use W3C standard document.getElementById() instead.” pointing to
labeled_marker.js (line 84)
I changed line 84 from “GMarker.prototype.redraw.call(this, map);” to “GMarker.prototype.redraw.call(this, document.getElementById(’map’));” and this appears to have fixed it.
Is this a valid improvement?
Ant: That’s actually a sloppy copy & paste error. The correct fix would have been to replace map with force, since we’re just passing through the arguments. However, an even better fix is to just use the apply() function instead of call(), like so:
But thanks for pointing it out! I’ve made the relevant fixes in the source file.
First this is simply great. Been looking around for a way to add labels to the markers for a little while now. I’ve been hacking this into an APEX application and have hit a road block. First I am pretty new to this stuff so I could just be noobing it up. But maybe someone can point me in the right direction on this problem. I’ve got the js scripts added into this. I can get googlemaps to come up with the display world on it. But when it executes the createMarker function it calls the LabeledMarker function. When it does this it blows an error saying LabeledMarker is undefined. However, it being included in the script so it should be there somewhere… Any suggestion on things to look at as to why this would be occuring? I have not modified js scripts except to remove the stuff about the markers arrary and manager since, I am pulling this info from a database. I am populating variable that should be for all intense purposes the same as markers array to pass into the createMarker function. Thanks for your help. Let me know what other info I can provide.
Never mind… I noobed it. Silly typo got me….
this.Me is not a function
http://maps.google.com/mapfiles/maps2.78.api.js
Line 1058
I see that message when I try to implement LabeledMarkers with marker clusters and different zooms. (can you tell I am new…) I’ve been playing with google’s examples:
function setupOfficeMarkers()
{
mgr = new GMarkerManager(map);
for (var i in officeLayer) {
var layer = officeLayer[i];
var markers = [];
for (var j in layer[”places”]) {
var place = layer[”places”][j];
var posn = new GLatLng(place[”posn”][0], place[”posn”][1]);
opts = {
title: place[”name”],
icon: getIcon(place[”name”]), “clickable”: true,
“labelText”: “Test”,
“labelOffset”: new GSize(-4, 8)
};
var marker = new LabeledMarker(posn, opts);
GEvent.addListener(marker, “click”, function() {
marker.openInfoWindowHtml(”Hello world.”);
});
markers.push(marker);
}
mgr.addMarkers(markers, layer[”zoom”][0], layer[”zoom”][1]);
}
mgr.refresh();
}
What am I missing?
The LabeledMarker-Calss is a very nice introduction into “advanced” GoogleMaps (for occasional JS-programmers as me). Not having fully caught the basics of the OO- and prototype-features in JS I got a little problem when trying to apply the LabeleMarkers-functionality in the context of
GEvent.addListener(map, “click”, function( overlay, latlng) { …
The (!overlay)-test always returns TRUE (in IE 6 and 7 at least), when clicking in the TEXT-DIV-Area of the labeled Marker.
So in this cases the MapClick- and MarkerClick - responses overlay.
Does anyone have an idea how to avoid this, because all trials with different G_MAP panes or z-indice for the texts led to nowhere.
Thanks for the wonderful tutorial. I am trying to figure out what part of the code controls the markers disappearing as you zoom out. I would like to use these labeled markers for a more broad map …say zoom 3 or 4. Any clues?
DarenJ: That’s the MarkerManager at work. There’s some good examples in the official documentation.
Mike, I can only add my thanks to the others for your great work on this.
A quick question: you say the labeled markers aren’t draggable — can they be re-positioned with the normal setPoint() function?
Nathan: There are various ways that draggability could be added, but all of them bloat out the source of this. For those who need them draggable, I’m sure it can be added without too much additional effort.
Hi Mike, thanks for a great tutorial - I am developing a similar application for one of my sites using your source. Development page is http://eqinfo.ucsd.edu/~rnewman/howtos/maps/google_multiple_nodes.php
I have a question - is there a way I can dynamically turn on and off the display of labeled markers in the LabeledMarker script? In my script that I wrote, I have ‘nodes’ on a marker, that are dynamically plotted with a GEvent ‘click’ handler. I want to dynamically ‘unload’ them too with a click event. Any pointers would be helpful.
Again - huge thanks for providing a clear and concise tutorial.
This is a create little bit of code, and i’m using and extending it on a new site, thanks!
One big problem I have is that when a marker is clicked on I need to raise the zIndex so that it shows above any overlapping markers. Any clues/ideas on how this might be achieved? Is it something that the underlying maps code would need to support?
I keep finding references to undocumented functions one being marker.setZIndex, but this doesn’t seem to work for me.
Thanks again..
I had this working on both Mac and Win, and still works on Win, but on a system that was just upgraded to OSX Leopard the maps will not load. Have you heard of any problems with Safari 3?
Karstyn: I haven’t tried it myself, but I have a report that it works fine.
Please be sure to use the official version here:
http://code.google.com/p/gmaps-utility-library/
Charles: There isn’t really any shortcut for how to do this… your safest bet
is probably to access the marker’s icon url directly, and add a second
copy of it, with the z-index set appropriately. So basically, do:
var icon_url = my_marker.getIcon().image;
And then add a new element to the G_MAP_MARKER_PANE, with the
css zIndex set to some extremely high value. Find the position using
this function:
var position = map.getProjection().fromLatLngToPixel(my_marker.getLatLng(),
map.getZoom());
Hi Mike,
Just a quick follow up on my question about change the z-index of a live marker. In the end I had to create a array of live markers and manually remove and re-add a marker every time i needed to change its z-index. It works quite well, and after many months the site is pretty much done!
Check it out at http://www.thebandbdirectory.co.uk
Thanks for the help!
Charles.