GEOG 863
GIS Mashups for Geospatial Professionals

Ajax

PrintPrint

A new web-programming paradigm

For the first decade or so of the World Wide Web's existence, mapping sites like MapQuest were held back by the fact that any time 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 and was encapsulated in 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 wowed the world with in 2005.

A simple illustration

Google Maps developer Mike Williams points out in his API tutorial that the important aspect of this 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. Converting data from a DBMS to one of the formats discussed earlier in the lesson can be quite tedious, particularly if your data are constantly changing. Instead, you can set up a server-side script to query your database and output the data in a form that can be consumed by JavaScript.  This could be XML, JSON or even simply comma-separated text.  Your JavaScript page can then read in the output from this proxy just as it would if the data were actually stored in a flat file.

An example of database-driven mapping

To further illustrate the concept of Ajax programming, let's take a look at a database-driven mashup that I've written.  This solution uses MySQL and PHP to map the locations of students in the PSU online geospatial programs by their zip codes.

Note

You are not expected to come out of this lesson with a complete understanding of how this application works.  My goal here is to give you an appreciation for how an Ajax-oriented (and in this case a database-driven) mapping application works.  If this sort of application seems like something you'd like to learn more about, then I recommend checking out the course's optional database lesson.

 

The page plots the US and Canadian students in our various 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 GIS 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. You could obtain data for other terms by replacing the 201503 part of the URL with 201502, 201501, etc. A detailed explanation of how to work with XML data like this is found in the database lesson.

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., 201503) 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.

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 term in the format 201503 to 'SU-2015'.

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. (This function comes from an external library written by the same Mike Williams cited above and is discussed in detail in the database lesson.)  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 201503 to 201502, the load() function will be called and passed the value 201502.

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 innerHTML property 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 features stored in a database can be retrieved by the user through a responsive application using an Ajax approach. 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 last page of this lesson.