Tuesday 15 May 2012

Update to the chromosome component

Hello people,

I know the previous post was quite technical, but this one in contrast is even more technical :-p Not really, I think i have to put this technical details here. So take this as a warning and if you are not into HTML5 programming, you might want to skip this port, and just check this link to see what im working on, I promise other posts no so techy!

So for those few that made it here this post to show you how I used the AreaSelector component to interact with the Chromosome one, so read those post if you haven't yet!

Firstly, the selector is optional for the chromosome component, so there is a new option in the constructor called includeSelector (true by default) and when all the bands have been loaded the selector is added. Then, every time the selector changes, the chromosome listen that event, refresh the corresponding coordinates and generates its own event telling the outside world that the selection have change. The last part of the code below is to insure that if the container DIV changes its size or position, the changes get propagated to the selector. So here is that piece of code:


//Setting up the selector in case is included
if (self.opt.includeSelector){
  //The selector just allows horizontal interaction and is preseted in the first band
  self.opt.selector = new Biojs.AreaSelector({
    target: self.opt.target+'_chr',
    resize_top: false,
    resize_bottom: false,
    area:[0,-5,$('#'+firstid).width(),20]
  });
  //Creating attributes in the object to save chromosome coordinates where is visible, starting in the first band   self.opt.selector.from = 0;    self.opt.selector.to = firstW;    self.opt.selector.fromWatcher=false;
  //When the selector change its position the chromosome coordinates have to be updated   self.opt.selector.onRegionChanged(function( objEvent ) {     if (!self.opt.selector.fromWatcher){       self.opt.selector.from = self._getCoordinateFromLeft(objEvent.region[0]);       self.opt.selector.to = self._getCoordinateFromLeft(objEvent.region[2]);       self.raiseEvent('onSelectorChanged', {         chromosome_id : self.opt.model.id,         selector_start: self.opt.selector.from,         selector_stop: self.opt.selector.to       });     }   });
  //if the div containing the chromosome is resized or moved the selector is modified with   $("#"+self.opt.target).watch("left,top,width,height,display", function() {     self.opt.selector.fromWatcher=true;     if (self.opt.selector.from!=null && self.opt.selector.to!=null )       self.moveSelectorToCoordinates(self.opt.selector.from,self.opt.selector.to);     self.opt.selector.fromWatcher=false;   }, 100, "_containerMove");
}


Other methods were implemented, mostly to handle conversion between the DIV coordinates and its coresponding chromosome coordinate. A method to directly change the position of the selector was added, so other components can interact with the chromosome view. Lastly 3 more events are associated with this component:  onModelLoaded to indicate that the DAS model has been succesfully loaded, onDASLoadFail in  the case the DAS source have any problem to be loaded, and onSelectorChanged for any position change on the selector.

The final result looks like the image below, and the code is now in the biojs registry here so you can play with it and use it whenever you want.

14 - Chromosome + AreaSelector component


Another part I worked on, came from a comment of a friend in this blog, and is that when displaying all the chromosomes, they were draw in the same size, which is not a good representation, each chromosome have a different number of nucleotides, and therefore its dimension vary.

The component was developed to auto-adjust to the assigned size of the container DIV, meaning that if we create DIV that are proportional to the size of the chromosomes, the representation will be more accurate.

The only problem is that a to be abe to calculate the proportions i need to know the size of all the chromosome, and because the info is geting asynchronous, is not something that we can just loop.

So what I did was to use the event onModelLoaded, to know when the component has finished loading the model, and in this way externally capture the size of that component, to adjust the width of the DIVs every time another chromosome is completed.
The DIV sizes, are then calculated with respect of the longest chromosome represented, this one has a width of 100% and all the other percentages are just proportion of it... Wow, thats a lot of words for just this piece of code:


  inst[i].onModelLoaded(function( objEvent ) {
    $("#holder_"+objEvent.model.id).data("size",1*objEvent.model.stop);
    adjustSizes(1*objEvent.model.stop)
  }); 

...

var maxSize=0;
var adjustSizes= function(size){   if (maxSize<size)     maxSize=size;   for (var i in chromosomes){     var chr=chromosomes[i];     if($("#holder_"+chr).data("size") != undefined){       var size = $("#holder_" + chr).data("size");       $("#holder_"+chr).width( (size/maxSize)*100 +"%");     }   } }


Below you can find a screenshot of this running, but if you want is to watch it in your browser just go to this LINK.

15 - Chromosome X and Y in proportion.

And that's me for now... Thanks for reading this, and please give me some feedback about it, I would like to know if someone is reading this and if is making any sense.

Hasta la vista!!!

No comments:

Post a Comment