Austin Marathon Mashup with Google Maps, USGS Elevation Data, and ESRI Elevation Service
I’m training for the upcoming Austin Marathon and Half Marathon and thought it would be cool to put together a simple mashup showing elevation information for the course. The terrain for this particular race can be pretty challenging. So, what I’ve done is put together a quick mashup using a variety of resources including the Google Maps API, the USGS Elevation Query Web Services, an elevation profile REST service from ESRI, and Dojo to tie everything together. It’s nothing fancy, but you can see the final product here.
In this post I’ll detail how I quickly put together this mashup.
Google Maps API
Obviously the base map for this mashup is Google Maps so we reference the API to create our map and then add the marathon mile markers and route. I’m not going to go into much detail on creating the base map. If you need basic information on the Google Maps API you can download a free copy of our Introduction to the Google Maps API e-learning course. I will point out that we are reading in the mile markers for the marathon from an XML file as seen in the code example below. For more information on reading XML files from Google Maps please review a previous article on the subject.
We follow a similar process for adding the marathon route wherein we create a new instance of GPolyline by feeding in an array of GLatLng objects that define the route.
Next, we need a reference to the ProfileService.
The ‘Get Elevation Profile’ button triggers a call to the ‘generateProfile()’ function seen below.
Task parameters include the instance of FeatureSet that we created from our GPolyline object along with parameters to define the output image width and height of the profile and a boolean value indicating whether or not we want the segments of the route to be displayed in the elevation profile. We do not in this case because the large number of points that define the route will simply clutter the output terrain profile. Our last line of code in this function calls the execute() method against profile task. Note that we feed in our task parameters, a second parameter that indicates whether or not we want the results to be returned as KML in the form of a GGeoXml object, and finally a callback function that will execute when the task has finished. ProfileService is a synchronous task meaning that the application will wait until the results have been returned to continue functioning. In this case, the function profileCallback() will be run against the results of the service.
A FeatureSet object is returned from the task. In this case, the FeatureSet contains a Feature which represents the marathon route. A Feature can contain both the geometry of the feature as well as attribute information. In this case we aren’t concerned with the geometry since we already know the marathon route. The attributes though contain the terrain profile information including a path to the URL where the output terrain profile image was placed along with some additional information that describes the profile. Finally, as is indicated in the highlighted section of the profileCallback function above we define an HTML snippet in the form of a <div> tag that contains a pointer to the URL of the terrain profile image along with the profile description. This HTML is then placed inside a Google Maps API info window and displayed at the center point of the route.
USGS Elevation Query Service
We are going to wrap everything inside a Google Maps event listener which ‘listens’ for a click on the map. You can see this in the first line of code above. Events in Google Maps are registered with the GEvent object and the addListener() method. The addListener() method takes three parameters. The first is the object (an instance of GMap2 in this case), the second is the event to listen for on the object, and the final parameter is a function that will run in response to the event. So in general terms we are setting up a function that will execute anytime the user clicks the map. We need this event listener to detect when the user clicks on a mile marker or a point along the route. Inside the function is where all the work takes place to respond to the event. I’ll draw your attention to a few pertinent lines. We need a reference to the USGS Elevation Query and we provide that in the first line that I have highlighted above. However, this provides only the base URL. We also need to append the latitude and longitude where the user clicked to the URL and this is accomplished in the second line that I have highlighted above. Now, in this case we are only providing the elevation for a mile marker or a point along the route rather than any point the user clicks on the map. The ‘click‘ event on GMap2 passes different arguments based on the context of the click, and whether or not the click occurred on a clickable overlay. You can see this in the event listener below.
If the click does not occur on a clickable overlay (this would be GMarker, GPolygon, GPolyline, or GInfoWindow), the overlay argument is null and the latlng argument contains the geographical coordinates of the point that was clicked. If the user clicks on an overlay that is clickable (GMarker or GPolyline in our case), the overlay argument contains the overlay object, while the overlaylatlng argument contains the coordinates of the clicked overlay.
So for our application we only want to call the USGS Elevation Query if the use has clicked on a mile marker (GMarker) or a point along the route (GPolyline). That accounts for our ‘if’ statements on ‘overlay’ and ‘overlayLatLng’ as seen in the code example above.
That was a bit of a lengthy description about a small subject in the overall scheme of the application, but it was necessary to fully describe the GMap2.click event.
So there you have it. A simple, but useful mashup for obtaining elevation information related to the upcoming Austin marathon.