Creating Dynamic Client-side Maps Mashups with Google Spreadsheets

Friday, March 30, 2007 at 9:34:00 AM



In the past, only those privileged few developers with access to server-side scripting and a database like MySQL were able to create easily updated dynamic maps mashups. With the introduction of the Google Spreadsheets Data API, all of that has changed. Like the other GData APIs, the spreadsheets API has an optional JSON output. If you don't know about JSON, it's a lightweight interchange format that allows for hierarchical nesting as well as various data types. But more importantly, JSON output is native Javascript code itself, and with a callback parameter that wraps the JSON output text in parentheses and a function name of your choosing, it allows you to get around some of the cross-domain security issues you might encounter in typical client side JavaScript.

So if you want the data from a published spreadsheet feed in your page, there's no need to worry about a server-side proxy for cross-domain XMLHttpRequest calls: just create a script tag with the feed in JSON format as the source, and you've got your data. Developers used to writing server-side proxies may not be impressed by this, but I encourage you to give it a whirl - once you go JSON, it's hard to go back.

But let's bring the discussion back to maps. Below is an example of a map based on a JSON feed from a spreadsheet of my favorite Seattle restaurants.

The steps to creating it are as follows:

  • When the page loads, we call a cm_load function that loads in a GMap2 at a default location, and then calls cm_getJSON
  • The cm_getJSON dynamically creates a new script tag and inserts it in the page. The src of the script tag is the (public) spreadsheets feed URL plus additional parameters to specify a function to call when the JSON returns ("&alt=json-in-script&callback=cm_loadMapJSON")
  • In the callback function, cm_loadMapJSON, we iterate through the entries in the JSON feed (the table rows) and create a new marker and sidebar entry for each of them.

Here's the coolest part though - I didn't code this map. My Spreadsheets->Map wizard did. If you've got a spreadsheet of location data and you want a dynamic map based on that spreadsheet, just try out the wizard. It will generate the code that you can embed on your website or upload to your Google Pages account, and if you're an adventurous developer, you can use the code as a starting point.

If you don't want to get a hosting account, check out API developer Esa's quick Spreadsheets mapper. Just put columns named 'lat' & 'lng' in your spreadsheet, put the public key in the URL of his page, and you've got a permalink to your map.

Start playing around, and let us know in the Maps API group or the Spreadsheets API group if you have any questions.

New Open Source Utility Library for the Google Maps API

Wednesday, March 21, 2007 at 5:50:00 PM



The Google Maps API Team is excited to announce our new open source project, the GMaps Utility Library. This project will be hosted on code.google.com and will let the Google engineers for the Maps API work hand-in-hand with the many great developers in the Maps API community. Together, we can extend the core Maps API and ensure that every developer need is met.

Another reason for this open source project is that we've realized that there are many potential extensions for the Google Maps API, but that the common user still needs a reliable and quick-loading API. Adding custom controls/functionality to the core API adds to the file size and forces developers wanting to tweak the code to overwrite obfuscated JS functions. With this open source project, a developer can include the JavaScript file for the particular library they're interested in. They can even download a copy of it and tweak it for their use.

To kick-start things, we've open-sourced the code for the GMarkerManager and added it to the GMaps Utility Library. The obfuscated GMarkerManager will continue to be available in the core Maps API, but the open source MarkerManager version will now be available via the new library. This will be a starting point for developers to create even more useful components. Just point your browser to http://gmaps-utility-library-dev.googlecode.com/svn/trunk/markermanager/ and see it for yourself - the documentation, examples, and the unobfuscated code.

There will be both development and release versions of this open source library. This allows for an open development environment in one project, while users can still point to a stable release version of the library for their deployed applications. (You can get the release version of MarkerManager there.) The development community will be involved in the process for deciding which components and versions are migrated to the release branches.

We're inviting all interested developers to join our development project if they'd like to contribute to the library or work on an existing components in the library, such as the MarkerManager. If you're interested, follow the instructions here.

KML and GeoRSS Support Added to the Google Maps API

at 4:08:00 PM



One of the things I love most about Google Maps and Google Earth is that it's easy for anyone to create and display new geographically referenced content. Whether it's pictures from your vacation, favorite places on the globe, or the hiking trails you like to visit, all you have to do is create a KML file (using Google Earth or any other tool) and load it up. This idea that you can view data from external sources inside Google Maps and Earth is really exciting to us, and I'm pleased to announce two major new features in this area.

To start we now support GeoRSS as a data format for geographic content in Google Maps. We want to enable users to create data in whatever format is most convenient for them, and feel that by supporting both KML and GeoRSS we can enable a wider variety of people and applications to contribute content to Google Maps. We've built support for the Simple, GML, and W3C Geo encodings of GeoRSS -- all you have to do is enter the full URL of a GeoRSS file into the Maps query box to load the file. For example, take a look at SlashGeo's GeoRSS on Google Maps.

Most importantly, we've extended support for displaying geographic data -- both KML and GeoRSS -- into the Google Maps API. Now in addition to programatically adding content to a Maps API site, you can create your content as KML or GeoRSS and load it into the Map with a simple function call. This means that the more than 1 million KML files that are available from all over the web can easily be mashed up with the map on your site. For example, you can add some vacation photos from Japan with the following code:

var gx = new GGeoXml("http://kml.lover.googlepages.com/my-vacation-photos.kml");
map.addOverlay(gx);

This makes it easier for API sites to maintain content in a flexible format that can be accessed via the API or in a number of other tools directly, and makes it simpler to create a rich API site with declarative content, instead of a lot of code.

Below is an example that shows KML and GeoRSS layers rendered on a Google Maps API powered map. You can toggle on and off the sample layers, or feel free to enter a URL to your favorite KML or GeoRSS content and hit the 'Add' button to see it on the map.

More information about how to use these new features can be found in the Maps API documentation. Google Maps currently supports KML files with points, lines, polygons, styles, icons, and network links (without view-based refresh). We plan to add support for ground overlays, screen overlays, folders, and visibility in the near future.

We're eager to hear from the developer community on what you think of this new API, and additions you'd like to see to make it even easier to use KML and GeoRSS content on your site.

Note: Since this is a newly released feature, you must specify v=2.x (instead of v=2) in the script tag for the next 2 weeks for it to be loaded properly.

March Marker Madness: GMarker Events

Friday, March 09, 2007 at 11:33:00 PM



To celebrate the middle of March we've got another playground app. This time, we're letting you experiment with GMarker events. As soon as you select a different action for a particular event, the code below the map will update and that code is run, creating a new marker on the map with the new event listeners. Notice that we're using the marker's setImage method as a possible action, since that's a great effect to combine with marker events. Have fun playing around, and ping us in the forums if you run into problems or have a question.

GMarker.setImage: Australian for 'clock'

Thursday, March 08, 2007 at 4:11:00 PM



Maps API Engineer Bo Majewski brings us a fun example of an animated clock using both GPolyline and the new setImage method of GMarker that was just introduced in v2.75.

Why is this clock centered on Australia? That's where the engineer's from! We leave it up to adventurous developers to combine this with a service like EarthTools to let users move the map and see the clock time reflect the timezone of the new map center.

Update: Maps developer Esa created a similar clock example that changes the clock location and time for various locations using the EarthTools service. Great work, Esa!

If you want to know how it's done, check out the how-to below the map, and ping us if you come up with any fun variations.


Setting up the clock:
  • We declare a global variable to keep track of the last hour/minute/second shown, as well as the polylines used for the hour/minute hands and the markers used for the clock ticks. We also declare global constants for our image strings, clock radius, and slice angle (the angle we need to move each minute, 2*Math.PI/60).
  • After loading the map in setupMap, we plot the markers for the ticks in setupTicks. We first declare a GIcon for each tick type (marker/second). Then we create 60 markers around the circumfrence of the clock, using the minute icon every 5 ticks and the seconds icon for the rest.
Animating the clock:
  • After setting up the initial markers, we call setInterval on the clockTick function with 1000 milliseconds so that it's called once every second, and then we call setTimeout on clockTick with 0 milliseconds to call it immediately.
  • In clockTick, we extract the current time from the javascript Date function into hours, minutes, and seconds variables. If the hour is not the same as the previously displayed hour, we remove the hour hand's GPolyline from the map, re-create it pointing to the new hour, and add the new GPolyline to the map. We do the same for the minutes hand. If the second is not the same as the previously displayed second, we call setImage on the previous marker with the appropriate image (MINUTE_OFF or SECOND_OFF) so that it's no longer highlighted, and we call setImage on the current marker with the appropriate image (MINUTE_ON or SECOND_ON) so that it is highlighted.
Calculating hand/tick placement:
  • The minToLatLng function is used frequently throughout the code to figure out the point at which to place or marker or end a polyline. This function takes in two parameters. The first indicates the minute (0-59), and the second indicates an inner offset from the radius (used for creating hour/minute hands of different lengths). It then calculates the point using basic trig on the known center of the map and the slice angle.

Here's a direct link to the clock, if you want to check out the source code yourself.

API v2 Latest: 2.75
API v2 Default: 2.74

v2.75: GMarker.setImage and a Mole-Whack-Tacular Example

Tuesday, March 06, 2007 at 12:56:00 PM



API v2.75 (2.x) now introduces the setImage method for GMarker, as noted in the forums. In the past, changing the image of a marker usually required creating multiple arrays of markers for each image change and some tricky switching between the arrays. Now changing the image just requires one method call.

To show one way you could exploit GMarker.setImage for all its worth, I've created a simple marker-clicking game, based on the Whack-a-Mole game found in arcades. Try it out, and find out how its done below.


Here's how it works:

In load, I set up the map and call createMarker for each of the points in the moleLocations array, adding each of the returned markers to a global markers array.

In createMarker, I create a marker with the global GIcon iconMole which has the default 'mole_down.png' image for its image property.
Note: I created all the mole images with the same canvas size (36*42px), as calling setImage on GMarker will not resize the GIcon. The new image will just be resized to fit the original GIcon.iconSize.

Still in createMarker, I extend Marker with a whackState property so I can keep track of the state of a mole hole. I also add click, mouseover, and mouseout listeners to the marker. In the click listener, I check if the game is being played and if the current marker is in the up whackState. If so, I increment the global currentScore, call marker.setImage('mole_down.png'), and change the whackState to almostDown. In the mouseover and mouseout listeners, I toggle between 'mole_scared.png' and 'mole_up.png' if the mole is currently in the up whackState.
Fast clickers will barely notice the mouseover state, but it's always nice to have a mouseover state to provide additional feedback to the player.

When the player clicks the start button, I iterate through the markers array, calling marker.setImage('mole_down.png') and setting whackState to 'down'. I also reset the game seconds left and current score, and call setInterval(popMoles, 1000) so that the popMoles function will get called every second.

In popMoles, I iterate through the markers array and pick a random number between 1 and 3 for each. If the marker is in the down whackState and the random number picked is 1, I pop the mole up by calling marker.setImage('mole_up.png') and setting its whackState to up. If the marker is in the almostDown whackState, I set its whackState to down. This intermediary state ensures that markers won't pop up immediately after getting whacked down. I then increment the game seconds and update the score. If the game seconds played equals the game duration (30), I call endGame.

In endGame, I iterate through the markers array, calling marker.setImage('mole_happy.png') for every marker currently in the up whackState. I also clear the timer that was calling popMoles every second.

Here's a direct link to the page, if you want to check out the source code yourself.

March Marker Madness: GMarkerOptions

Thursday, March 01, 2007 at 3:34:00 PM



To celebrate the start of March we've created a "playground" app for you to experiment with GMarkerOptions. As soon as you change one of the options below, the code below the map will update and that code is run, creating a new marker on the map with the changed options. Notice that setting some options will mean we ignore other options - for example, a non-clickable marker can't be dragged, so we don't bother setting bounceGravity. Have fun playing around, and ping us in the forums if you run into problems or have a question.