Clickable LabeledMarker

Back 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.

LabeledMarker Click

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…)


44 Responses to “Clickable LabeledMarker”  

  1. 1 Joseph Crawford

    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.

  2. 2 Mike

    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. :)

  3. 3 Ant Burnett

    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?

  4. 4 Mike

    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:

    GMarker.prototype.redraw.apply(this, arguments);

    But thanks for pointing it out! I’ve made the relevant fixes in the source file.

  5. 5 Mike G

    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.

  6. 6 Mike G

    Never mind… I noobed it. Silly typo got me….

  7. 7 Anil

    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?

  8. 8 WolfG

    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.

  9. 9 DarenJ

    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?

  10. 10 Mike

    DarenJ: That’s the MarkerManager at work. There’s some good examples in the official documentation.

  11. 11 Nathan Lambert

    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?

  12. 12 Mike

    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.

  13. 13 Tatlar

    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.

  14. 14 Charles

    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..

  15. 15 Karstyn

    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?

  16. 16 Mike Purvis

    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());

  17. 17 Charles

    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.

  18. 18 Dave

    Thanks for the code. Not immediately sure why you disable dragging. Besides modifying the constructor, the only other change I had to make was to change one line in the redraw function to:
    var p = this.map.fromLatLngToDivPixel(this.getPoint());
    (latlng changed to getPoint())

  19. 19 Swapnil

    Hello

    This is really a very helpful article I am finding exactly what you have mentioned.
    Only Thing I want to ask you that I want to show User the Points on Map which will guide him the points visited Now I just want to give that particular points naming that is sequence like 1,2,3,4,5………….. as per they have been visited.

    Using this article I think I can do it But the problem is The Opts You have mentioned one time that Opts can I reinitailize in array depending upon the Number of positions I am having I hope you have got my point .

    Please reply if you can as its been urgent to me.

    thanks & takecare

    Swapnil S

  20. 20 Peter

    Hi,

    Question about the map_data.php file. I’m having a tough time trying to create that data structure to feed into the api from a database because I have no idea what this is in javascript:

    var markers = [
    {
    ‘abbr’: ‘LES’,
    ‘name’: ‘Lower East Side’,
    ‘latitude’:40.714737,
    ‘longitude’:-73.986912,
    ‘wp’:'http://en.wikipedia.org/wiki/Lower_East_Side%2C_Manhattan’
    },
    {
    ‘abbr’: ‘EV’,
    ‘name’: ‘East Village’,
    ……etc.

    Is that a short hand method for creating an area, or an object? I have successfully retrieved my points data from php/mysql using GXmlHttp (and I’ve iterated through the structure and it’s all there). My question is how do I recreate the above structure in a for loop in javascript once the data has been retrieved. I tried creating an array and pushing elements on it but I don’t think that is the same data structure as above. Any ideas?

  21. 21 Mike Purvis

    Peter: The square brackets create an array, the braces create an object.
    Equivalent code would be like so:

    var markers = new Array();

    var myMarker = new Object();
    myMarker.abbr = “LES”;
    myMarker.name = “Lower East Side”;
    // etc.

    marker.push(myMarker);

  22. 22 Peter

    Hi Mike,

    Thanks for the speedy response! That worked, know I’m able to load my markers using GXmlHttp. I had one follow up question. For awhile I thought it might be a bug with my code, but then I tried confirming it with the Manhattan sample you have linked to the article, and it appears to be true. GIcons do not appear at a zoom level less than 11 (in other words if I set the start zoom level of the map at 10 or less, the icons do not appear). If I zoom into the map, as soon as I hit a zoom level of 11, they appear. Is there a reason for this. My data points are fairly spread out geographically and there is no way to see them all unless you zoom it.

    Other than that, everything seems to work perfectly.

  23. 23 Peter

    Hi again,

    please ignore the last question (I just read a response in this thread that answers it).

    thanks.

  24. 24 Ruud

    Hello,

    I’m using also this script for an school case which you can see here: http://webkrant.redje.net

    Sorry for this noob question but how do i set the map view on hybrid mode standard? I’ll tried some methods but no result at all…

    tnx in advance!

  25. 25 Rob

    Hi Mike

    How do you use the markers on zoom levels smaller than 12? I want to use 9 which I have set in map_functions.js.

    Rob

  26. 26 Rob

    Oops.. Just worked it out… sorry. At the bottom of map_functions.js there is a line:

    manager.addMarkers(batch, 11);

    which can be changed to use markers on different zoom levels.

  27. 27 Rob

    Only problem I still have is that the sidebar links continue to show around 40 additional links with ‘undefined’. Any idea why this might happen?

  28. 28 Rob

    Oops. just a JS conflict with lightbox script. Sorted now.

  29. 29 BigfeetLiu

    I don’t know why, but I think there my be a bug in the LabeledMarker.js.
    U can just reference a german developer’s page:http://www.kreisalarm.de/drkmap/.
    Sometimes, when the LabeledMarker is remove from a map, the icon is removed, but the text stay!

  30. 30 John

    Great example,

    I did have some firefox/explorer incompatibilities but worked them out. I used a modified version with mouse wheel functionality and every thing seems to work great except… after clicking and zooming and adding and removing and some combination there of I get a spurious label left on the map that refuses to go away.

    I’ll post the example at johngresh.com/examples/googleMaps/labeledMarker.

    Thanks again,
    John

  31. 31 Monica

    Thanks for this useful post. I haven’t any knowledge on JavaScript but managed to add my first maps to a website I am creating :

    http://www.triasbali.com

    I was looking for code to make a labelled marker so this post is great although, being new to all this, it will probably take me a while to assimilate and apply !

  32. 32 Larry

    Thank you for this useful article.

    I have one small probem.
    When calling marker.setPoint(point) the marker is moved but the label text does not. Am i missing something? How do i get the label to move with the marker?

    Regards,

    LG

  33. 33 Richard

    Hi Mike

    Thank you for sharing this great example. I was just wondering if there was any way to incorporate the dynamic zoom level and centering features that getBoundsZoomLevel give?

    Any tips would be greatly appreciated.

  34. 34 Doug

    Excellent example, it saved a lot of time, UNTIL I tried the following, grin:

    I’ve recently run into an issue with trying to use setCenter and getBoundsZoomLevel to auto center and show the area containing the markers.

    I’ve gotten other examples to partially work, ran into the issue where you have to have an alert in the code to have the map utilize the bounding info, weird. But still have not had any luck getting it to work with this code.

    Just wondering if anyone might have some insight into a possible solution for doing so using the example code listed here.

    Thx

  35. 35 Mark

    Hi Mike,

    I’m a google maps, javascript, web development novice, but I found this article incredibly useful. I’m now using labeled markers on my site (AccessibilityMapr.com). Thanks.

    Is there any way to get tooltips working with labeled markers? In the area that the label covers, the tooltip won’t pop up.

  36. 36 Jonas Wagner

    Hello Mike,

    this is really neat, thanks for the thorough explanation. I’ll probably extend it a bit so you can place arbitrary content in your markers (not just text). I’ll notify you about the extended version.

    I just wondered about the first line of code in this article:

    this.clickable = options.clickable || true;

    Just how would I create a marker which is not clickable? :)

  37. 37 Mark

    Hi,

    Thanks so much for LabeledMarker.

    Quick question: I want to move my google maps over to the all-in-one AJAX API. How can I use LabeledMarker with this API? Is there an easy way to do it?

    Thanks

  38. 38 tweakmy

    Dear Mike,
    How is it possible to make the div text respond to a RIGHT CLICK? I have been trying for the whole day already. But still one bit close setting event when it is right click. So far, left click is possible.

  39. 39 tweakmy

    i mean I m still not one bit close enough to be able to set right click event for the div text area. thanks.

  40. 40 Nipun

    Hey mike,

    i have read your blog and implement the code for google map.
    my question is these locations are static.or we can find any location through
    postcode for example through map_functions.js

    please help

    thanks

  41. 41 Mischa

    Hi!

    Hey mike! Great work!

    I had a few problems with moving the Labeled_Marker object by setting a new location.

    I found a site (http://codereview.appspot.com/109052/diff/5/1008?context=&column_width=80), where someone made some adjustments. One of them is the following

    old
    var p = this.map.fromLatLngToDivPixel(this.latlng);

    new
    var p = this.map.fromLatLngToDivPixel(this.getLatLng());

    by changing this line the Gmarker be moved properly with its title.

    Thanks a lot!

  42. 42 NEWqasertMAN

    Всем Доброе утро! Заходите и развлекитесь на Сними девочку на ночь в своем городе.

  43. 43 Scott

    Thought you might appreciate this. Used your libraries (and even your icon) for the first release. Thought you might appreciate it.

    Hillsborough County Sheriff’s Office (Tampa, FL)
    http://www.hcso.tampa.fl.us/PublicInquiry/Traffic/TopAccidents

  44. 44 DoniaNainly

    Watch Amateur sex in Slut Wife masterbating while looking at dirty mag - She gets off hard while looking at a porno mag. BBW Wife’s Gangbang - by BBW lover - A wife intends to cheat on her man. Our gangbang home party, four cocks my wife georgina.

    wives


Buy Our Books!

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