GEOG 863
GIS Mashups for Geospatial Professionals

Ajax

PrintPrint

For the first decade or so of the World Wide Web's existence, mapping sites like Mapquest were held back by the fact that anytime the user wanted to zoom in/out or even just pan a bit in some direction, the whole page needed to be re-loaded. While these sites were still useful, their lack of responsiveness caused by the delay in waiting for data to stream from the server to the client machine clearly limited their effectiveness and frustrated users.

A major advancement in web application development occurred in early 2005 with the publication of an article by Jesse James Garrett entitled, Ajax: A New Approach to Web Applications. Ajax (shorthand for Asynchronous JavaScript and XML) is a programming technique that uses a number of web technologies (JavaScript, the DOM, XML, and HTML/XHTML, most notably) to provide a much more responsive user experience. While Garrett and his team were certainly not the first to employ the Ajax technique (in fact, Google Maps was released prior to Garrett's article), his article was the first to provide a name for the technique and to explain its conceptual framework to a wide audience.

The Google Maps API is made possible by the use of Ajax programming. When a user views a Google Maps page, tiles of map data are passed from the Google server as XML and translated into imagery on the user's machine. As the user pans around the map, the tiles that are just outside of the visible portion of the map are downloaded behind the scenes. This is what allows the seamless panning that Google Maps is probably best known for.

Google Maps developer Mike Williams points out in this API tutorial that the important aspect of this new web programming paradigm is not really the use of JavaScript or XML per se. Rather, the important aspect of Ajax is its basic philosophy of loading the static parts of a web page once and loading the dynamic parts quickly through the use of small asynchronous exchanges of data that go on behind the scenes without the user's knowledge.

Be sure to test Mike's page to see the Ajax technique at work. His page makes it possible to view three separate sets of markers by clicking on the A, B, and C buttons just below the map. Note how quickly the markers and sidebar text are updated when one of the buttons is clicked. This responsiveness is achieved because the page is only requesting the data required to plot the new points and update the sidebar. A non-Ajax page would ask the server to send back all of the HTML required to display the desired page - even the parts that are not changing - and would not load as quickly. (While Mike's example is written for V2 of the API, you should still be able to follow its use of Ajax.)

Mike's example calls upon a script written in the PHP language to return different sets of markers depending on an input parameter passed to the script. This brings up an important concept that we haven't discussed yet — the difference between client-side and server-side scripting languages. JavaScript is an example of a client-side scripting language. When you embed JavaScript in a web page, that code gets downloaded to and executed on the browser's machine. In contrast, code written in a server-side scripting language like PHP, ASP, or Perl is never downloaded to nor executed on the browser's machine. It is instead executed on the web server that hosts the program and the output of the program (if any) is sent to the browser's machine.

One reason you may want to incorporate a server-side script into your application is that JavaScript is limited to reading files that are stored in the same domain (i.e., on the same machine) as the page containing the JavaScript. Thus, if you were aware of a website that published data that you'd like to integrate into a mapping mashup, you would not be able to accomplish the task with JavaScript alone. You would need to use a server-side script (known as a proxy) to read the data and pass it to your JavaScript page.

Another reason to use a server-side script as part of a mashup solution is its ability to extract information from a DBMS like Oracle, SQL Server, or MySQL. If you had to manually convert your data to XML as outlined earlier in the lesson, you would find such a process to be quite tedious, particularly if your data were constantly changing. Instead, you can set up a server-side script to query your database and create an XML representation of the data. Your JavaScript page can then download the XML from this proxy just as it would if the data were actually stored in an XML file.

To further illustrate the concept of Ajax programming, let's take a look at a database-driven mashup that I've written. If you choose to complete the optional Lesson 6, you'll learn how to build your own database-driven mashup through the use of MySQL and PHP. My example uses these technologies to map the locations of students in the PSU online GIS (Certificate and Master's) programs by their zip codes.

The page plots the US and Canadian students in our various online geospatial programs in different colors. Clicking on a student's hometown will zoom to that location and open the associated info window. By default, the map will display all of the students enrolled in the most recently completed term. However, any term going back to the launch of the Certificate Program in Winter 1999 can be selected from the drop-down list just above the map.

The data for this map are stored in a MySQL database. A PHP script is used to query the database and feed the query results to the JavaScript page in XML format. To see how this application works under the hood, start by viewing the XML output from the PHP script. The XML happens to be in the alternate form that is more difficult to process with JavaScript, but that's not important for this discussion. You could obtain data for other terms by replacing the 201303 part of the URL with 201302, 201301, etc. In the wcgis_students.html page, I simply plug this URL in as the first argument to the downloadUrl() function rather than a static XML file.

Without going into too many details on the syntax of PHP, let's have a look at the PHP script to give you a sense of how it works. (This is a version of the script saved in plain text format so that you're able to view its source code. If I hadn't posted this plain text version, you would only be able to see the script's output and not its source code. This is one of the big differences between client-side and server-side scripts.)

Note that all PHP variables begin with the dollar sign character ($). The first three lines of the script open a connection to the MySQL database. The $term statement retrieves the value that was passed to the script through the URL (e.g., 201303) and stores it in a local variable. That variable is then plugged into the WHERE clause of a long SQL SELECT statement that brings together the desired data from three tables. That query string is then used as the argument to a function that executes the query. A for loop is eventually used to process the query results one row at a time, but first an important line known as a response header is added to indicate the type of data that will be returned by the script:

header("Content-type: text/xml");

The script's output is created using a series of echo statements. The start tag for the root <students>element is echoed before the loop and its end tag is echoed after the loop. Within the loop itself, the various XML start and end tags are echoed with the appropriate values from the current row inserted in between. Note that the concatenation character in PHP is the period. Don't worry if you had trouble following what's going on in the PHP script. You can learn more about it in Lesson 6.

Now, have a look at the source of the wcgis_students.html page. Within the <head> section of the document are a number of required JavaScript functions, the most important of which is the load() function. This function requires that the desired term be supplied as an input parameter. The first thing the function does is set the main heading of the page to display the term being mapped using the DOM. Note that a call is made to the getTermName() function to convert the quarter in the format 201303 to 'SU-2013'.

The next bit of code removes all of the markers from the map (if there are any) and empties the markers array. These statements are necessary because this function is going to be called each time the user selects a different term from the drop-down list. Without them, markers from previously selected terms would remain on the map each time a new term is selected.

Next, note how the PHP script is plugged into the call to the downloadUrl() function. The complete URL is created by appending the term value originally passed into the function to the static beginning of the URL. The rest of the code in the load()function is written much like the Jen and Barry's example from earlier in the lesson.

Skipping down to the page's <body> section, recall that the div with id "heading" has its text set by the load() function.

Next, two <table>s are used to arrange the information below the headings. The first is used to show a key to the marker symbols, the term drop-down list, and a count of the number of students being mapped. The second table contains the sidebar and the map.

Note that the third cell in the first table contains an HTML <form> element and within that form element is a <div>. This div will have its innerHTML property set to a <select> element (the drop-down list) by code found in the init()function.

The drop-down is constructed dynamically in init() by obtaining the current year and month using JavaScript's built-in Date functions. These values allow me to determine the last term for which records are available in the database. This information is needed to initialize the map when the page is first loaded and also to have a starting point for constructing the list of options in the drop-down list.

After the setting of the last_term variable comes a critical statement. A variable called drop_down is created to hold the HTML for the drop-down list. The critical part of this statement is the setting of the onchange attribute to execute the load() function. The DOM is used to specify that the text of the option selected by the user should be passed to the load() function. Thus, if the user changes the selected option in the drop-down list from 201303 to 201302, the load() function will be called and passed the value 201302.

After that initial bit of HTML defining the <select> element, two loops are used to create the options associated with that element. The first loop adds all terms that have been completed in the current year. The second loop adds all terms for every year going back to 1999. This code is complicated by the fact that we switched from 4 terms per year to 5 terms per year in 2013.

After the loops, the HTML required to close the <select> element is appended to the drop_down variable. That variable is then finally used to set the innerHTMLproperty of the appropriate <div>.

The next statement adds the map and sets its center and map type.

The last line of the script makes the initial call to the load() function, passing it the most recently completed term, as computed from the current year and month.

This section demonstrated how to go beyond simply reading local XML files to extracting data from a DBMS using a server-side script and packaging it as XML that can be consumed by JavaScript. But what if you don't have the latitude/longitude coordinates of the locations you wish to map? If you have some kind of locational information such as a full postal address, city/state, or zip code, you can pass this information to Google's geocoder and ask it to give you the associated coordinates. That's the topic of the next section.