Javascript arguments by value
December 28, 2008
Filed under Web (PHP, Javascript)
Tags: arguments, execution context, javascript, SIMILE Timeline
Let us consider the following situation: one has several widgets, which have to be loaded onto the page dynamically, but each can take a while to load. A solution is to do the loading asynchronously for each component with a nice progress bar displayed to the user.
For example, SIMILE Timeline uses the asynchronous approach to load the data for historical timelines.
After the timelines have been configured, one has to load the data into them using loadXML function.
var eventSource = new Timeline.DefaultEventSource( 0 );
var timeline = Timeline.create(td, bands, Timeline.HORIZONTAL);
timeline.loadXML( eventSourceURL, function( xml, url ) {
eventSource.loadXML( xml, url );
} );
The setup seen above works perfectly for a single timeline. But what if we have a loop to create a few timeline widgets?
var dataSources = [
"http://andrejserafim.wordpress.com/?data=1",
"http://andrejserafim.wordpress.com/?data=2",
"http://andrejserafim.wordpress.com/?data=3" ];
for( var ds in dataSources ) {
var eventSourceURL = dataSources[ ds ];
var eventSource = new Timeline.DefaultEventSource( 0 );
// associate eventSource with timeline through _bands_ configuration
var timeline = Timeline.create(td, bands, Timeline.HORIZONTAL);
timeline.loadXML( eventSourceURL, function( xml, url ) {
eventSource.loadXML( xml, url );
} );
}
The result is not anything one could predict, all 3 timelines will have the data from the 3rd data source or no data at all. This happens because the data is loaded at some point after the execution of the code presented has finished. When the anonymous function is created it remembers the reference to the eventSource variable in this loop.
For some reason the context of execution in terms of that one variable is the same for all three timelines.
Fortunately, one can supply a default value to function arguments in Javascript. So we could freeze the reference to eventSource in an array and pass a key as a parameter to the function. Let me show you what I mean:
var dataSources = [
"http://andrejserafim.wordpress.com/?data=1",
"http://andrejserafim.wordpress.com/?data=2",
"http://andrejserafim.wordpress.com/?data=3" ];
// we are going to distinguish each eventSource
var eventSources = [];
for( var ds in dataSources ) {
var eventSourceURL = dataSources[ ds ];
// storing all eventSource values for future asynchronous use.
eventSources[ ds ] = new Timeline.DefaultEventSource( 0 );
// associate eventSources[ ds ] with timeline through _bands_ configuration
var timeline = Timeline.create(td, bands, Timeline.HORIZONTAL);
// notice the three arguments and the defaults.
timeline.loadXML( eventSourceURL, function( xml, url, ds ) {
eventSources[ ds ].loadXML( xml, url );
}.defaults( ds ) );
}
Now each anonymous function is associated with its own eventSource. And we get three distinct timelines.
One might notice that the defaults construct is not standard Javascript. It is described in more detail here. And can be added by inserting this code somewhere in the loading section of your page:
Function.prototype.defaults = function()
{
var _f = this;
var _a = Array(_f.length-arguments.length).concat(
Array.prototype.slice.apply(arguments));
return function()
{
return _f.apply(_f, Array.prototype.slice.apply(arguments).concat(
_a.slice(arguments.length, _a.length)));
}
}
Ontology visualisation: jOWL
October 20, 2008
Filed under Web (PHP, Javascript)
Tags: html, javascript, jOWL, ontology, ontology visualisation, visualisation
jOWL is a JQuery based framework visualising .owl files. It is extremely easy to use. And because it is JQuery-based the syntax is very concise.
This is an example of initialising the Javascript side of things:
$(document).ready(function() {
if ($.browser.msie) console = { log : function(msg, rest){$('body').append($('<div/>').text(msg+' '));}};
// gdp code
jOWL.load( "MyFile.owl", function() {
var tree = $('#onttree').owl_treeview({addChildren: true, isStatic: true });
var navbar = $('#ontnav').owl_navbar();
tree.addListener(navbar);
navbar.addListener(tree);
var cc = jOWL.permalink() || jOWL("Entity");
tree.propertyChange(cc);
tree.broadcast(cc);
//switch between treeview & navbar
toggleView($(':radio:checked').val());
$(':radio').change(function(){toggleView($(this).val());});
function toggleView(id){
switch (id)
{
case 'ontnav': $('#ontnav').show(); $('#onttree').hide(); break;
case 'onttree': $('#ontnav').hide(); $('#onttree').show(); break;
}
}
}, {} );
});
All we are doing here loading the MyFile.owl and creating 2 interchangeable views for it: ‘onttree’ and ‘ontnav’. These views will be connected through the listeners. So a change in one is reflected in the other.
Then you need to actually add the HTML elements:
<div id="ontologyPane" class="ontologyPane">
<form id="viewcontrol" action="">
Treeview:
<input type="radio" checked="checked" value="onttree" name="visualisation"/>
Navigation Bar:
<input type="radio" value="ontnav" name="visualisation"/>
</form>
<div id="onttree" class="ontologyTree">
</div>
<div id="ontnav" class="ontologyNav" style="display:none">
</div>
</div>
And you have 2 interchangeable panes displaying the structure of your ontology. There is much more to the jOWL framework. But even this simple demonstration gives a taste of its possibilities.
This example is based on the source of http://jowl.ontologyonline.org/documentation.html.