If you’ve gone through my site, you probably know that I work as a contractor a good part of the time. Because of that I’m exposed to a lot of different technology / libraries. The most recent library has been Google Mapping API. I’ve learned about Markers, Polygons, Points and had the chance to play with some Javascript again. Good times.
My current gig involves working with a large client that has a wide variety of small, and not-so-small, projects. The diversity has been tremendous. I’ve worked on a Windows 8 “Welcome” kiosk application that runs on a touch-screen computer in the visitor’s lobby, the company’s public facing website which had a major update recently, and the company’s reporting intranet site which seems to be focused on internal reporting. I say “seems to be” because I’ve only been on this project for eight weeks and have been concentrated on a tiny part of the site. There are many areas of the site to which I’ve yet to be exposed.
But for the last two weeks, I’ve been working with Google Maps API to generate (what else?) maps! Without giving away too much, this client is a food processor. A LARGE food processor working with fruit in California’s Central Valley.
Currently, they have a lot of data that gets reported on traditional spreadsheet-friendly text-based reports. But some of the data just screams out to be displayed on a map. For example, fruit quality is expressed as a numerical value and is tracked geographically (by county, by grower, by field, etc). So a forward-thinking person has suggested displaying this information on a map. The client has already located (mapped) fields, and farms using Google Maps API and so extending this to display reported information is not that much of a leap.
The first thing I did, was get familiar with Google Maps API. Unless you’re someone like Lewis and Clark, we’ve all used Google Maps (they probably would have used it too, had it been available). I’d used it sparingly in the past, but have not become “one” with the API. Just to be clear, I’m still not “one” with the API, but I now know enough about Markers and Polygons to be able to write you a small mapping application.
Based on my client’s needs, I needed to be able to display polygons to represent areas of interest (fields, farms, counties, etc). So I spent a day going over the basics of displaying polygons. At the end of the day, I was able to render a polygon for every field that I wanted to display and I was able to color-code it based on the reportable value from the database report.
A Google Polygon is comprised of a series of points that make up a Path. Actually, the path is comprised of a MVC Array of LatLng objects. Nonetheless, a path defines the outline of the polygon.
Learning how to add points to a polygon in response to user input (via mouse clicks) was one of the first challenges. This example helped A LOT. So, now I could create a polygon and allow the user to update the definition of the polygon by adding vertices as needed. It turns out that feature would not be needed in the final product, but still, it was good knowing how to accomplish this (knowledge is power!)
So now, I was able to display a set of polygons, and color as needed based on information returned from a database query. Excellent!
But, then I realized that a bunch of colored polygons don’t provide a lot of information on their own. I decided that it would be more useful to present a InfoWindow when a user clicks on a polygon. That way, a user sees some polygons, color coded to give some very basic grouping information, sees one he/she likes, clicks the polygon and voila! a window containing a more detailed report about that particular field/farm/county would pop up and give the user extra context about the visual report.
Google’s example on InfoWindow uses a hard-coded InfoWindow to display information in response to a mouse click. This works for a single point and a single InfoWindow. However, depending on the criteria entered into the application, there could be several thousand polygons on display. This would very quickly lead to a “out of memory” error on the end user’s computer. Not the ideal situation.
The solution for this was simple enough: create and show the InfoWindow using information from a RESTful web service. A little scripting and a new web service later, I was able to display my InfoWindow using real-time data from my new web service. This had the effect of allowing the user to get the additional information they were after, without testing the limits of the end user’s computer resources.
So a little debugging and I check in my code for the client to review.
Two days later, I get a “looks great, but…” email.
“Look on the bright side,” I tell myself. “More billable hours.” Ah, the life of a consultant. You get paid for every hour you work. The downside is that sometime, you don’t have enough billable hours!
The problem was that the data represented was scattered over the entire state of California. In person, a 40-acre plot of land is HUGE. Who could eat that much? But on a large-scale map, 40 acres is a tiny, almost imperceptible speck of black on a Google map. Not very useful in this situation.
I mentioned that the client had started some of the Google Maps work. That experience by the client quickly led them to suggest “Maker Clusters” in an effort to make the large scale maps work better.
The basic concept is that when two items are shown close together on the screen, these two items will be aggregated and displayed as a single object representing the two smaller independent objects. As you zoom out, this aggregation continues until at a large enough scale, your thousands of objects are represented by a single object representing all the individual items. One icon, represents my 2200 fields, for example.
So I downloaded the MarkerClusterer library and got busy learning how to use it. This had a bit of a steep learning curve, but I was able to get the basics working in about one day.
There were only a handful of items that I had to customize to get my “finished” application working (“finished” because this is all still in a “proof-of-concept” stage and my end up dying in-place).
First, I had to change the text displayed. By default, the clusters show you the count of child markers. So if there are ten items in the cluster “10” is the text displayed by default. But in my case, the value of interest for a field could be a number such as “24” for field A and “36” for field B. So a cluster that contains fields A and B would be more informative if it displayed “30” instead of “2”.
Fortunately, the MarkerClusterer library allows you to use your own function to perform the calculation that provides the displayed text. Here is an example that illustrates how to use a custom calculator function. In addition to the displayed text, the calculator function also returns an index that can be used to specify CSS properties for the cluster. In essence, you can customize the look and the content of your clusters.
So having cobbled together all the knowledge from the links above, I was finally able to render a page that looks like this (initially)
and transforms in to this when zoomed-in:
I haven’t included any code snippets here since this is a project that is still very rough, and my main purpose was to provide some quick links to some resources that you may find useful.
If there is enough demand, I may put a small demo project together here on this site.
A polite request and a beer would go a long way toward that end.