Wednesday, April 21, 2010

Callback Function in JavaScript

In JavaScript programing, understanding of callback function is very important. Although I have created several Google Gadget with JavaScript, I am still not very clear with how does callback function work. This week, I was doing some experiment and research on the callback function in JavaScript. Hopefully, my experience can help those who have the same wonder on this topic.

The first callback function example I encountered was a Google gadget example on its documentation page. Here is the code for the callback function part:


var gadgetHelper = null;
var table = null;

_IG_RegisterOnloadHandler(loadVisualizationAPI);

// Load the Google Visualization API
function loadVisualizationAPI() {
google.load('visualization', '1', {'packages': ['table']});
google.setOnLoadCallback(sendQuery);
}

// Send a data query.
function sendQuery() {
// Instantiate our Table visualization.
var tableDiv = _gel('tablediv'); // A gadget convenience method for getElementById
tableDiv.style.width = document.body.clientWidth + 'px';
tableDiv.style.height = document.body.clientHeight + 'px';
table = new google.visualization.Table(tableDiv);

// The query src URL is stored in the user prefs.
// This GadgetHelper convenience method loads it into a
// query for you.
gadgetHelper = new google.visualization.GadgetHelper();
var query = gadgetHelper.createQueryFromPrefs(prefs);
query.send(handleQueryResponse);
}

// Get a query response.
function handleQueryResponse(response) {
// Use the visualization GadgetHelper class to validate the data, and
// for error handling.
if (!gadgetHelper.validateResponse(response)) {
// Default error handling was done, just leave.
return;
};
var data = response.getDataTable();

table.draw(data, options);
};



In this piece of code, there are several callback functions. So this JavaScript code runs like this:
1. Run _IG_RegisterOnloadHandler function with a parameter that contains the callback function.
2. Run the callback function loadVisualizationAPI if the onload event is triggered.
3. Run the callback function sendQuery if the Google object onload event is triggered.
4. Run the callback function handleQueryResponse if the Google.query object send event is triggered.

Now the question, which confused me a lot, came up. How is this "response" passed to handleQueryResponse function?

Actually, query.send(handleQueryResponse) is only passing a function pointer, which means handleQueryResponse(response) will be called in query.send function hopefully with a variable that declared inside query object. It is only confusing because we cannot see the code for query.send function. Otherwise we probably can see the declaration of the response variable and call the callback function with this variable as parameter.

The key thing to remember here is that the parameter for a callback function is always the pointer to that function. Eventually, the object that triggered the event will call the function with the correct parameter hopefully.

Wednesday, April 14, 2010

Overcome Same Origin Policy with XMLhttprequest

Same Origin Policy is a browser policy that forbids JavaScript from getting files from another domain. I have never noticed this before because I never tried to get something from another server. However, during the development of my Google Gadget Project, I first encountered the troublesome that brought by Same Origin Policy. I did some research on the web and here is my experience on how to overcome this problem.

First let me describe the problem I need to solve. I need to access some XML file from a known server by using AJAX.

Here are some solution I found from the internet:

1. Set a Proxy on your site
I didn't try it, because I am not familiar with it. However, the concept is easy to understand. The only drawback is that it takes longer time to get the response because the request is not directly sent to the target.

2. Use < script >
I did play with this method. The concept is very straight forward too. < script > has an attribute "src" which allows you to include something from another domain. The most important point is that it is not restricted by the same origin policy. So I created a function that create a "script" object dynamically, and put the URL in the "src" attribute. After I invoke the function, there is a new script object in the header, and it actually contains the content from that external URL! However, this is not working for retrieving XML files, because I cannot actually access the data. But this way works perfectly if the external data is a JavaScript file, since you just need to call some function or get the value of some variable.

3. Modify the server response header
This is the way that I used to overcome the Same Origin Policy. W3C organization is proposing a way to enable Cross-Origin Resource Sharing. One of the feature is that user can specify the trusted domains in the Access-Control-Allowed-Origin in the response header. In this way, those trusted domains can use the regular XMLhttpRequest to perform some http method (GET&POST). Since this modification has to be made on the server side, it means you must be able to modify the server response header or at least know some one can do that for you. Here is a pretty detail example on this topic.

Finally, I contact the Server Manager for the WattDepot Server and all the same-origin-policy problems are gone. If you are not able to modify the response header in the server side, here is a very useful blog post of using other ways to overcome the same origin policy. (It has some Chinese character, but there is English explanation too).

Wednesday, April 7, 2010

How to find the coordinate of a place

This week, I was assigned to an interesting task that searches for the longitude and latitude of some power plants in Oahu. Well, it looks very easy, but actually it is quite tricky. When I was trying to find something, the first thing come to my mind is to Google it. I went through these power plants' home page, but it is not easy to find the exact coordinate of the power plants (Because most of them only have an address for the power plant).
Then, I used Google Map to search the address that I just acquired. However, the longitude and latitude information was still not showing. At this point, I just played around with all the possible tools in the Google Map. Finally, I found a way to get a loose coordinate of a place.

First you need to click on the marker and choose "Move marker" from the "more" drop down list.


Then you may drag the marker to the place that you want to know the coordinate. And then right click on the marker and choose "What's here?".


Then you may notice that the coordinate is displayed in the search box now.


Although it takes some steps to get the coordinate, this is the easiest way I found so far. To make searching coordinate little bit easier, I created a Google Gadget that provides a drag-able marker that shows the coordinate of the marker. However, you need to know a loose coordinate of the place first. Anyway, here is the link for the location finder gadget.

Wednesday, March 31, 2010

Geting start with Google Map API

Recently, I am working on a project called WattDepot GeoMap. This project is a Google gadget that displays the sensor data from WattDepot Server on a Google Map. Since I had no experience of using Google Map API, I decide to do some research on its documentation page. The documentation for Google Map API is very detail, and it provides lots of sample code that help users to understand.

Among all these examples, I think the custom icon example is the most helpful for a beginner. It contains a lot of functions, such as:
- load Google Map API
- create a Map object
- set the map center
- create an icon object
- create markers object
- load marker options
- add some events for the marker
- display markers

These functions are very basic. However, it is good enough to build some nice Google Map gadget with these functions already. Here is a screen shot for the GeoMap 1.0 I made.

Wednesday, March 17, 2010

Protential Visualization for Milestone 3

After the second milestone, we closed down some finished projects (Stoplight gadget, Kukui Cup design) and start up with some new projects (CSS design, Innovation visualization). This time, I was in the Innovation visualization group. Paul and Jarret are still my teammates, and we have Kendyll and Edward joining in.

Our first task for milestone 3 is to think of a potential useful visualization that can be used in Kukui Cup. Professor Johnson provided us a list of possible visualizations, such as:
(1) Annotated timeline.
(2) Bio Heat Map.
(3) Drastic TreeMap
(4) Dygraphs
(5) Gauge
(6) Geomap/Intensity Map
(7) Motion chart.
(8) TermCloud

Among those visualizations, I think Geomap/Intensity Map is very cool. It is also very challenging too. I couldn't think of a way to program a image to update part of it dynamically without re-loading the whole image. Another visualization I am interested in is Bio Heat Map. It can provide lots of information such as the trend of energy usage in a specific time interval. Motion chart is very amazing too. However, right now I don't have any experience in the motion chart API yet.

Anyway those are the top three visualizations I would pick. Hopefully after next meeting, I will actually work on one of them.

Tuesday, March 9, 2010

Done with WattDepot Monitor Gadget

Finally, our second milestone is approaching. However, I have to flight to the main land this Thursday and come back next Monday, which means I cannot accomplish too much during this period. Luckily, we do not have too much work left since last week and it turned out that my teammate did a great job this week. We released the WattDepot Monitor Gadget 1.2 as our final version. Here is the project hosting.

Basically, we have to work on two main things this week:
First, figure out a way to refresh the query instead of reload the entire page. In the beginning, we thought we might need to use AJAX. But Jarret found out that we only need to change a small thing to reach our goal. He uses setTimeOut method which is our current way to do the refresh, however, instead of pushing the windows reload function, he pushed the sendQuery function. The sendQuery function is the main function that talk to the server and retrieve data. In this way, we can refresh the gadget without loading the whole gadget. So we apply this feature for both Stoplight gadget and WattDepot Monitor Gadget. Both of them are much faster in updating now.

Second task is error handling. For our previous version of WattDepot Monitor Gadget, we didn't implement any error handling. This week, Paul implement some basic error handling for WattDepot Monitor Gadget. He checked the user inputs of host URL and Source Name to make sure both fields are not blank. Error handling about the google query can be implemented later.

What I did this week mostly are some utilities. For example I created a help page for our WattDepot Monitor Gadget. Also I fixed some existing bugs in the WattDepot Monitor, such as incorrect column name in the google query.

Anyhow, this is a screen shot for our WattDepot Monitor Gadget 1.2:


For next milestone, our class is going to regroup the student. I have no idea which project I am going to work on, but I had a good time with stoplight group. I made some friends and both Jarret and Paul are very talented people. Hopefully, we can work together later on.

Tuesday, March 2, 2010

Javascript & Date

For this week, our team worked on both Stoplight Gadget and WattDepot Gadget Monitor again. Although we committed our Stoplight 1.5 as our final version, it seems that there is always new requirement. Professor Johnson asked us to use another way to represent the message data. So we decide to let Jarret work on this task. He ran into some small problems, but he finally conquered them and release the new Stoplight Gadget 1.6. Hopefully, it brings an end to this project for now.

On the other hand, I worked on WattDepot Gadget Monitor. This week, we are ready to connect the WattDepot Gadget Monitor to the WattDepot Server (We were using Google Spreadsheet before). I basically follow the WattDepot documentation and modify the data source URL according to the user input. Another thing came up this week is formatting date object in JavaScript. In Google data table, date is formatted as MMM dd, yyyy hh:mm:ss. However, the JavaScript built-in date object does not have a method to convert the month to some string like "Jan" or "Feb". Therefore, I have to make a simple function to convert month number to relative text. Since JavaScript is a very popular language now days, I would say it will be much easier for user if the developers can provide more date conversions.

I am still having difficulties in generating the drop down menu dynamically. I have post my question in the Google Gadget discussion group, but no one replied yet. So we make the source input as a text box instead of a hard-coded drop down menu. Hopefully, some one can response my post and I can generate the source drop down menu dynamically.