November 22, 2009, 11:22 am · 7 comments · Filed under: Google, JavaScript, Web Development
Can your web browser do this?
You’ll never get rich digging a ditch, nor building Dashboard widgets.
A Kryptonite™ lock can be defeated in 11 seconds, but you still lock your bike, right?
Gaining Twitter followers is a little like losing weight. You have to try.
Over or under? It’s the age-old question when it comes to the orientation of toilet paper rolls.
I am a web developer, recently returned to the States after 3 years in New Zealand. I’m into my family, photography and frisbee sports.
Nothing will benefit human health and increase chances for survival of life on earth as much as the evolution to a vegetarian diet.
–Albert Einstein
Apple · AppleScript · Business · Coda · CSS · Dashboard · Design · Google · InSTEDD · JavaScript · jQuery · Life · Marketing · Music · New Mexico · New Zealand · Open Source Software · Photography · PHP · Politics · Ruby on Rails · Scree · Subversion (SVN) · Twitter · Usability · Web Development · Widgets
CSS Fast Nav: Because (perception of) speed matters! · Personal Branding for Introverts · Stupid WebKit Tricks · Add an interactive legend to a MarkerManager managed Google Map · Dude. Mikeyy can’t even spell his own name. · Dashboard Widgets for Fun and Profit · Animating your iPhone web application · How-to recover from checksum mismatch errors in SVN · Why Apple can afford to charge so little for Snow Leopard · When is a global variable not a variable?
CSS Fast Nav: Because (perception of) speed matters! · When is a global variable not a variable? · Our misguided culture of cool · InSTEDD: Open Source Software that saves lives · Add an interactive legend to a MarkerManager managed Google Map · Personal Branding for Introverts · Moments of Rangitoto · Some Twitter conventions · Why Apple can afford to charge so little for Snow Leopard · Stupid WebKit Tricks
Twitshirt is a tweet on a shirt. Buy the one below or check out my most recent tweets.
Anyone but me use #666 (the color, not the hashtag), you know, just to tweak the Bible-thumping + source-code-checking crowd? Bueller?
See a random Twitshirt-worthy tweet.
80/20 · 90 Seven Design · Alyson Hurt · Andrew Nimick · Apps & Hats · Ben Young · Brian Arnold · Brian Warren · Carl Bolter · Chris Burgess · Christine Morris · Cristina Stoian · Daniel Lyons · Daniel Schwartz · David Hedges · Hamish Campbell · Jochen Daum · John Visser · Joseph McLaughlin · Joshua Sallach · Julian Pistorius · Justine Sanderson · Kalena Jordan · Katie Graham · Kelly Green · Kevin Potis · Mark Bixby · Matt Henry · Method Arts · Morgan Pyne · Peter Michaux · Philip Tellis · Piers Harding · Rebecca Murphey · Reid Givens · Rey Bango · Rhett Anderson · Richard Paul · Rob Pongsajapan · Robin Taylor · Ryan Park · Shaun Lee · Simon Young · Su Yin Khoo · Toni Barrett · Vaughan Rowsell · Vincent Thomé · Voom Studio
My bias is for references over “cookbooks.” I want to know all of my options, not just one way to do something. Show me the why as well as the how and I am happy.
JavaScript: The Good Parts · Object-Oriented JavaScript: Create scalable, reusable high-quality JavaScript applications and libraries · JavaScript: The Definitive Guide · Designing with Web Standards · CSS: The Definitive Guide · Prioritizing Web Usability · The Elements of User Experience · Web ReDesign: Workflow that Works · Don't Make Me Think: A Common Sense Approach to Web Usability
I’ve hosted this website with pair Networks since 1997. They rock.
This blog is powered by…software I wrote.
Feeling generous? Knock yourself out!
On a recent site, the client specified the (quite reasonable) dual requirements of showing different pins at different zoom levels and having a legend on the map that could be used to toggle pins of different types.
Having used the excellent, open source MarkerManager library before, I immediately thought of it for managing the zoom levels. I hadn’t implemented an interactive legend before, so I went a-Googling and found documentation and examples for adding custom map controls. So far, so good.
I stumbled around a bit about how to get the MarkerManager class to filter pins by both zoom level and type until I buckled down and just read the source of the class. Turns out, the solution was pretty simple (which is always a good sign).
In the end, I created a custom map control (LegendControl) that adds and removes groups of pins to and from the MarkerManager instance’s internal grid. It seems so obvious in hindsight!
In case you’re confused about what problem I’m trying to solve, interact with the map below. Notice how you get different pins by zooming in and out and how you can turn whole classes of pins on and off.
Implementing MarkerManager to show and hide large numbers of pins by zoom level is a snap. And, it’s relatively trivial to write a couple of functions to show/hide individual pins by type. In fact, my client supplied me with functions they’d used before on other sites.
I decided from the outset to build the legend as a proper map control because, well, that’s what it is. I’m glad I did because it enforced separation of concerns. The resulting code is more tidy than if I’d just started hacking away.
I won’t go into detail about creating custom controls. You’re welcome to check out the script yourself to see how it’s done.
If you go to the map in a new window and view source, you’ll see a bunch of stuff that’s typical in a Google Maps implementation. For example, the following is the function I use to set up the map, itself:
function initMap() {
var map, mgr;
// set up your basic map
map = new GMap2(document.getElementById('map'));
map.setCenter(new GLatLng(-36.848, 174.756), 13);
map.addControl(new GLargeMapControl());
map.addControl(new GScaleControl());
map.addControl(new GMapTypeControl());
// create markermanager instance
mgr = new MarkerManager(map);
// add markers to MarkerManager and set up markerGroups
initMarkers(mgr);
// add legend
map.addControl(new LegendControl({
mgr : mgr,
markerGroups : markerGroups,
legendValues : legendValues
}));
}
See that last bit? That creates our legend control. But, I guess you figured that out, right?
Unfortunately, the way it’s currently written, LegendControl requires certain variables to be in the global scope. Yucky, I know. I’m open to feedback about how to tweak things to better encapsulate the control by passing in the necessary objects and options.
The variables that need to be in the global scope are as follows:
mapGMap2mgrMarkerManagerlegendValuestype, description, and pinSrcmarkerGroupsUpdate: I’ve refactored the code to eliminate the need for variables to be in the global scope. Amazing what a good night’s sleep can do!
The other only trickiness required by LegendControl is that your markers (instances of GMarker) must have 2 properties in addition to the ones the class adds by default. These are zoomMin and zoomMax and they correspond to the minimum and maximum zoom levels at which the marker should be displayed.
So, by way of example, my function for creating individual markers looks like the following:
/**
* Create a marker
* @param object obj Object literal specifying marker attributes
* @return GMarker
*/
function createMarker(obj) {
var marker;
marker = new GMarker(new GLatLng(obj.lat, obj.lng), {
title : obj.name,
icon : MapIconMaker.createMarkerIcon({
width : PIN_WIDTH,
height : PIN_HEIGHT,
primaryColor : colors[obj.type]
})
});
marker.zoomMin = obj.zoomMin;
marker.zoomMax = obj.zoomMax;
GEvent.addListener(marker, 'click', function() {
marker.openInfoWindowHtml('' + obj.name + '');
});
return marker;
}
Again, go to the map in a new window and view source to see the full implementation. It will make more sense than me spending another 500 words trying to explain it. :-)
I hope you found this helpful. As I said above, any suggestions for reducing the need for variables in the global scope are appreciated.
Update 9 Feb 2010: There has been a bit of interest in Legend Control, so I have put it up on Google Code under the MIT license. The script is free to use, modify, and distribute in both personal and commercial projects. Enjoy!
Short URL to this article:
Tweet this article!
7 comments
@Dwayne,
I just tested my example on IE7 and it did work. Here’s a direct link to the map page:
http://andrew.hedges.name/e/google-maps/legend.html
The pins are generated from the Google Charts API, so they might just have been experiencing a lag that caused them to time-out. Could you try substituting icon images from a more trusted source and see if you are still unable to see the pins?
This is great. I am wondering if you have ever tried using the mapiconmaker version 1.1 to add text in the center balloon. This would be helpful for color-blind and users that have a hard time differentiating color to determine differences in icons. I am not a big fan of too many custom images for icons as it can make the map very compact.
Nice job. You should think about how to advertise this more, as I have been searching for a while and this is one if not The best approach I’ve seen so far.
I really dig this. The show/hide box could be very useful. Can’t wait to try it!
Hey Andrew, is there any license to use your developed script?
@Dwayne,
The script is liberally licensed, so it’s free to use both personally and commercially. Thanks for reminding me. I’ll add a license statement to that effect to the script when I have a chance.
Keeping the doc block in place for attribution purposes would be appreciated, as would not linking directly to the file on my server.
Glad you find it useful!
In addition to making the markers above, I would like to add a drop down box to re-center, zoom, and remove markers that fall outside that region (e.g., state). Have you seen anything like this before? I only ask, as this is pretty good code that I haven’t seen elsewhere on multiple Google searches. I’m not sure this is actually possible.
BTW… using the mapiconmaker v1.1 you can add the labels that I suggested above (I think). I haven’t had a chance to work on this yet, but will over then next several weeks.
I will also try to integrate the coding using an XML data file, and will send to you when complete (if interested).
I will definitely pull the script off and put it on our server. Thanks for sharing your hard work.
Comments close automatically after 90 days.
Still have something to say? Drop me a line!
Hi,
Your example sounds great, but I am not able to actually see the icons from IE7.
I am looking for a way to create a legend within the map frame with the icon used on the map and the description of the icon.
Currently, we use the MyPane.prototype = new GControl; described in the link above to create a legend. We run our map based on an xml file that is parsed and one of the maps contains references to the icon (A, B, …). It would be great to be able to allow users to add new xml data via form (handled already), but then to just add a new letter C with the information on what C means, then to automatically add a legend without having to modify script. The legend should look something like this.
Legend:
A (icon) 2005
B (icon) 2006
Your thoughts would be great. Seeing your example in action once the code errors (if any) are corrected.
★ Posted by: Dwayne · December 10, 2009, 9:45 am