UPDATE The client has recently replaced their entire custom RoR web application for an Adobe product. Subsequently, my map work is no longer there.
I worked on the team at Fine Design that recently launched the beautiful new Kimpton Hotels website. I had the pleasure of making the dynamic and static maps based on the Google Maps API. The experience was enlightening, and I wanted to share it with the world. Some of the map development process was easier than you might expect (thanks to some useful tools), some of it was way more complex than it should be, and some parts were even interesting.
What was useful?
There are a multitude of map platforms and libraries available on the interwebs. For this project we found the following to be most useful:
- Google Maps API – The 500-pound gorilla in the room. No introduction is really needed. The reference tables alone print to 111 pages! It’s a little like reading a Soviet-era submarine manual.
- Google Maps for Rails – A flexible gem that helps make developing maps for large sites easier. All the map objects created with this gem have customizable models and builder methods. This gem can be easily integrated with other JS libraries, and best of all, it works well with Rails controllers and views.
- Geocoder – A gem that adds geocoding, reverse geocoding, and distance queries as Rails methods. Integrates well with the Google Maps for Rails (Gmaps4Rails) gem. We used this gem to create latitude and longitude data for all our destinations using street addresses. Lat. and long. data are the lifeblood of any map.
- Infobox.js – An InfoBox behaves like a google.maps.InfoWindow, but it supports several additional properties, which allow for some fancy styling~!
- Marker Clusterer Plus – This library creates and manages clusters for large amounts of markers, and adds lots o’ functionality and events to google.maps.Cluster objects.
- Styled Map Wizard – Allows you to import and modify existing map styles in a wizard rather than needing to rebuild them from scratch each time. (Thanks Google for not including this feature out of the box ;)… )
Each of the libraries above seemed stable and fairly widely used as evidenced by the latest update date of the repository, or the number of related Stack Overlow questions. For this project we also made extensive use of jQuery and Underscore.js. Gmaps4Rails was by far the most useful gem. It helped to tie together all the libraries above, provided a helpful backbone to structure all of our maps’ related code, and brought with it an existing ecosystem with lots of map developers.
What was more complex than it should be?
“Maps codify the miracle of existence.”
~Nicholas Crane, Mercator: The Man Who Mapped the Planet
Because of the mixture of the software libraries and languages, I felt like I was an archaeologist uncovering some ancient forgotten text.
The hardest part of creating these maps was knowing the name of the objects in a given context (see the crazy objects chains in the function below for an example). This made it harder to surface and integrate the most advanced features we wanted to use in these libraries.
At one point the Project Developer said, “So basically it’s like converting Russian and French into Latin, so they can speak to each other.” To which I replied, “Yeah, and then into Esperanto so the end user can view them in their browser.” Because of this, turning a comp or a deliverable into reality was also occasionally way more complex than one might expect.
1
2
3
4
5
6
7
8
9
10
11
12
function myClick(id) {
if (markers[id] !== undefined && cluster_markers !== {}) {
if(markers[id].getServiceObject() && !(cluster_markers[markers[id].getServiceObject().position.lat()])) {
google.maps.event.trigger(markers[id].getServiceObject(), 'mouseover');
} else if(cluster_markers[markers[id].getServiceObject().position.lat()] && (handler.map.getServiceObject().getZoom() == 4)) {
cluster_trigger = cluster_markers[markers[id].getServiceObject().position.lat()];
google.maps.event.trigger(handler.clusterer.getServiceObject(), 'mouseover', cluster_trigger);
} else if(handler.map.getServiceObject().getBounds().contains(markers[id].getServiceObject().getPosition())) {
google.maps.event.trigger(markers[id].getServiceObject(), 'mouseover');
};
}
};
Once a feature was unveiled, new feature requests were also often uncovered (see the next section). This usually required extension of some obscure functionality onto a different object and a visit to the deepest depths of the api catacombs (Eeek, it’s freaky down there!).
What was interesting?
During the build, there was a feature request to create an Infowindow for markers. Once this was in place, it looked great. This lead to a request for clusters to act and look just like those for regular map markers. Simple right? Surprise, it was a total-pain-in-the-butt! Documentation and Stack Overflow tickets were pretty sparse in this area.
I built a custom solution byte-by-byte that ended up being about 85 lines of code (which I have since refactored down to 64). However, I genuinely enjoyed the process of figuring out which components to use and welding them all together. I had a deep feeling of accomplishment when I pulled it all off, and someone else might even find my work to be useful in the future (be still, my nerdy heart)!
Lastly, because of the GMaps4Rails gem, I had the opportunity to use Coffeescript. I found out that I actually really enjoy using Coffeescript, and I don’t feel guilty about saying it anymore! It was fun, concise, and it compiled into something that was often more efficient than the regular ol’ JS that I write. Check out Brian Mann’s recent presentation on overcoming the fear of it.
What if I want to make maps too?
If you’re creating Google Maps in Rails you should definitely consider using the tools above. Finding the tools and learning the ‘language’ each of them uses was half the battle. Learning where their gaps are and programming in them was the other half. There are a million other tools out there for Google maps, and you should take your time to check them out too (one of my other favorites is: SnazzyMaps).
Expect browser incompatibility issues to happen. For example, it took a while to figure out why svg marker’s weren’t showing up in Firefox (but were in Safari, Chrome, or IE 9-11). If you want to ensure cross browser compatibility, build ample troubleshooting and testing time into your project estimates. Stackoverflow is also your best friend in this process.
Last and perhaps most importantly, work with the designer while they are creating their maps. Before a project starts, try to steep yourself in all the libraries above. Tease out what functionality is implicitly/explicitly contained in their comps. Then figure out if that exists already in an existing library or needs to be custom made. This can help to uncover and avoid hidden pitfalls, which might make developing maps easier.