Adding Google Maps to an App Builder Application

David Cassel
Last updated January 17, 2011

Note: This tutorial is meant to work with MarkLogic 4.2 and 5.0. In MarkLogic 6, you can instead use the map visualization widget.

Using MarkLogic’s Application Builder makes it a snap to put together an application quickly. Whenever I build a search app this way, I feel like I’ve gotten 80% of what I need. This post shows how to take the next step and add a common feature: maps.

To illustrate these steps, I’m going to use an application I put together to track my souvenir pin collection. I wanted to keep track of when and where I got each of the pins, and a map is a natural way to display that. At a high level, here are the steps:

  1. Put some sample data in the database
  2. Use Application Builder to generate the basic application
  3. Add an element where the map will appear
  4. Create a module to return some data points
  5. Write JavaScript to make the display
  6. Include the necessary JavaScript files

Now for the details:

1. Load sample data

I decided to go ahead and put my pin collection out there in the wild, so that you’ll have something concrete to use to work through this tutorial, if you have nothing better. The structure is nothing special, but it will do the job. Set up your database and load up the data. The easiest way is with MarkLogic Server 4.2′s new Information Studio (which you can learn about from a couple tutorials. or the docs). I put an date element range index on acquired-date so that I could have a facet, but it’s not required for this exercise.

2. Use Application Builder

As with Information Studio, I’m just going to give you a quick reference to the learning page on MarkLogic’s developer site, since I want to focus this tutorial on the map aspects. You can take all the defaults while going through the App Builder wizard. When you’re done this step, you should have a standard, out-of-the-box app where you can nose around my pin collection. If you search for “bell”, you should find my Liberty Bell pin.

3. Add a map element

Application Builder puts the generated code into a modules database. You can either use WebDAV to edit it there, or use the Support Package to get a copy to put on the file system and edit that way (in App Builder, click the down arrow next to the application’s name and choose Support Package from the drop menu; make sure you update the application server to point to the directory on the filesystem where you unzip). Either way, we’ll be working mostly in the application/custom/ directory.

Our goal here is to put the map on the first page we see. In an App Builder app, pages are identified by the “view”. Open up application/custom/appfunctions.xqy and find the app:get-content() function. The first thing you’ll notice is probably that it is commented out. When App Builder generates an app, it produces standard and modifiable copies of a bunch of functions that control how the app runs. Close the comment that precedes the function and remove the close-comment marker at the end of it so that this copy of the function will be in effect.

You’ll notice this line at the top of the function:

let $view := $config:CONTEXT/*:view

This identifies the view. We want to add a div element to house the map on the “intro” view. Here’s how the function ends up:

That gives us a place to put our map. Now we need to get some data for it.

4. Return some data points

This XQuery code retrieves the geo points in the database, along with the pin’s URI and name. (The where clause is necessary, because when a pin is added, there might be a description of where it came from without having lat & long.) Save the following to /application/custom/get-points.xqy:

 

Note that this isn’t anything fancy — it’s grabbing all the points. For an application with more data, you’d probably want to restrict the results to the area showing on the map, and perhaps by other criteria. To run good geo queries, you’ll want to add a geospatial index. We’ll leave that for another day and just grab all the data for now.

5. Display the points

I created an /application/custom/js/maps.js file that handles initialization and display of points. Let’s take a look at that, and then we’ll bring it all together by adding the script include statements that we need.

We have an initialize() function that gets called when the page is ready. The initialize() function creates a map in the div element that we created to hold the map in step 3. It then calls loadPoints(), which makes an AJAX call back to the module we created in step 4. The results come back as XML. I use jQuery to parse through the results, create a set of markers, and figure out the correct bounds for the map so that it is zoomed just right to display our data. If you click on one of the markers, that will take you to the detail page for the individual pin (take another look at the get-points.xqy module and you’ll see that set up in the url element).

You may be looking at the code wondering why I made a buildMarkerClickEventHandler() function instead of just creating the listener inline within loadPoints(). In a word, closure. To keep this post focused, I’ll leave a more detailed explanation for another day (if you’re dying to know, say so in the comments, that will make me get to it faster).

You’ll also need to download jQuery, as I’m using that in my script. Put it in /application/custom/js/.

6. Include the JavaScript files

Now to bring it all together. We have the pieces; what’s missing is that they aren’t being used yet. To add the JavaScript includes, let’s return to /custom/appfunctions.xqy and take a look at app:js(). Remove the comment markers so that this function will get used. In this function we can add more includes. We can make them across-the-board or specific to a view. There are three JavaScript files we need: jQuery, Google Maps, and our own maps.js. jQuery is something that will likely get used a lot (at least the way I write), so I add that to the list of includes at the top of the function. After that, we’ll add the Google maps include and maps.js, but only on the intro view. Here’s how the function looks when we’re done:

The inline comments mark what we’re adding. Remember to un-comment the function by moving the close-comment marker from the end to before the function, just after the preceding comment.  When you're done, you'll know where all my pins came from!

 

Map Screen Shot

 

So there you have it. Follow these steps, and you should find yourself with a working map display. Leave me a comment to tell me where more detail is needed or what cool stuff you’ve found to display on your maps. Happy coding!

This tutorial first appeared as a post on David's blog

Comments

  •  i loved this text from you, helped me a lot. i am really grateful.
  • After finishing the demo, I'm receiving the following error: Error: a is null Source File: http://maps.gstatic.com/intl/en_us/mapfiles/api-3/4/7/main.js Line: 28 I'm tried changing the google api version to 3.3 and the JQuery to match the one in the demo but I still receive the above error. Is there anything else I should try.
    • This turned out to be a simple missed step -- specifically, adding the div in step three. The "a" variable in Google Maps' source refers to the div; since it wasn't there, the variable was null. Adding the missing lines from step 3 fixed the problem.
  • After downloading "My Pin Collection" I received the following error when trying to extract it: "the archive is either in unknown format or damaged"
    • It looks like we had a bad zip file. Try again; it should work now. Thanks for alerting us!