Wednesday, April 28, 2010

GeoMap Project Report (Apr 22 - Apr 28)

During this week, I mostly worked on implementing the different mode of GeoMap gadget. Also I spent some time on creating icons and some error handling (e.g. No source is visible on the map). Here is the latest code for GeoMap Gadget.

Here are some screen shots:
Interface when gadget first loaded:


If the mode is consumer or generator:


Summary:
Right now GeoMap gadget will calculate the level thresholds dynamically and change the source icon according the source's latest sensordata. However, it requires a lot of HttpRequest to be sent and processed, which makes the loading kind of slow. I have asked Robert see if he can implement a function that retrieves all sources latest sensor data. If so, I think it will cut the time significantly. For next week, I will work on the subsource link for virtual source and maybe some error handling.

Retrieve data using multiple XMLHttpRequest

Sometimes, one XMLHttpRequest can not retrieve all the required data to perform certain task. For example: I need to display some information of the power plant which generate the most power among 20 power plants. However, the server, which contains those information, only allows me to retrieve the information for one power plant a time. In this case, in order to find the highest power generation power plant, I need to retrieve the information for all 20 power plants first.

Since there are 20 power plants, it is better to use a loop to send XMLHttpRequest. However, once you send an XMLHttpRequest, the code will jump to the callback function to handle the response and it is not going back to the caller. Because of this, the callback function has to be the caller function. So the JavaScript Code may look like this:

var counter = 0; //loop counter
var url = [] //array of url for different source

//Send XmlHttpRequest
function loadXml(url){
....
....
....
}

//Handle the response
function handleResponse(){
....
....
counter++;//ready for next source
requestData();//go back to the caller
}

//loop through all the sources
function requestData(){
if (counter < url.length) {
....//store the data in somewhere
....//for example push it into an Array
loadXml(url[counter]);//send request
}
else {
processData();//handle the data and quit loop
}
}

//process the data
function processData(){
....
....
}


In this way, we define a global counter and a global array to perform the loop manually. It can solve the problem for processing multiple XmlHttpRequest, but still it is not the optimal solution. The reason is that retrieving data by creating a big query from the server side is much faster than send the request over and over again.
So the optimal solution is to implement some function in the server side that can get all the requiring data.

Wednesday, April 21, 2010

Project Report (Apr 15 - Apr 21)

During this week, I mostly worked on implementing the source selection page. Also I spent some time on re-factoring the code and doing some research on Google Visualization tabs. Here is the latest code for GeoMap Gadget.

Here are some screen shots:
Interface when gadget first loaded:


Interface for source selection:


Select some source:


After click save:


Summary:
I was trying to use the Google Visualization tab for the source selection page. However, I couldn't load Google Map Object in there. So I didn't use this method. Also, I just noticed that not all the sources are listed in the source selection page. I will take a look at that. For next week, I will work on different modes for GeoMap Gadget.

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.