mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-21 13:50:20 +08:00
trackster: caching works, faster loops, displays exon blocks, passes JSLint
This commit is contained in:
@@ -1 +1 @@
|
||||
var ac_tag_area_id_gen=1;jQuery.fn.autocomplete_tagging=function(c){var e={get_toggle_link_text_fn:function(u){var w="";var v=o(u);if(v!=0){w=v+(v!=0?" Tags":" Tag")}else{w="Add tags"}return w},tag_click_fn:function(u,v){},input_size:20,in_form:false,tags:{},use_toggle_link:true,item_id:"",add_tag_img:"",add_tag_img_rollover:"",delete_tag_img:"",ajax_autocomplete_tag_url:"",ajax_retag_url:"",ajax_delete_tag_url:"",ajax_add_tag_url:""};var p=jQuery.extend(e,c);var k="tag-area-"+(ac_tag_area_id_gen)++;var m=$("<div>").attr("id",k).addClass("tag-area");this.append(m);var o=function(u){if(u.length){return u.length}var v=0;for(element in u){v++}return v};var b=function(){var u=p.get_toggle_link_text_fn(p.tags);var v=$("<a href='/history/tags'>").text(u).addClass("toggle-link");v.click(function(){var w=(m.css("display")=="none");var x;if(w){x=function(){var y=o(p.tags);if(y==0){m.click()}}}else{x=function(){m.blur()}}m.slideToggle("fast",x);return false});return v};var s=b();if(p.use_toggle_link){this.prepend(s)}var t=function(u){var v=new Array();for(key in u){v[v.length]=key+"-->"+u[key]}return"{"+v.join(",")+"}"};var a=function(v,u){return v+((u!=""&&u)?":"+u:"")};var h=function(u){return u.split(":")};var i=function(u){var v=$("<img src='"+p.add_tag_img+"' rollover='"+p.add_tag_img_rollover+"'/>").addClass("add-tag-button");v.click(function(){$(this).hide();m.click();return false});return v};var j=function(u){var v=$("<img src='"+p.delete_tag_img+"'/>").addClass("delete-tag-img");v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)});v.click(function(){var D=$(this).parent();var C=D.find(".tag-name").eq(0);var B=C.text();var z=h(B);var F=z[0];var y=z[1];var E=D.prev();D.remove();delete p.tags[F];var A=p.get_toggle_link_text_fn(p.tags);s.text(A);$.ajax({url:p.ajax_delete_tag_url,data:{tag_name:F},error:function(){p.tags[F]=y;if(E.hasClass("tag-button")){E.after(D)}else{m.prepend(D)}var G=p.get_toggle_link_text_fn(p.tags);alert("Remove tag failed");s.text(G);v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)})},success:function(){}});return true});var w=$("<span>").text(u).addClass("tag-name");w.click(function(){tag_name_and_value=u.split(":");p.tag_click_fn(tag_name_and_value[0],tag_name_and_value[1]);return true});var x=$("<span></span>").addClass("tag-button");x.append(w);x.append(v);return x};var d=function(v){var u;if(p.in_form){u=$("<textarea id='history-tag-input' rows='1' cols='"+p.input_size+"' value='"+escape(v)+"'></textarea>")}else{u=$("<input id='history-tag-input' type='text' size='"+p.input_size+"' value='"+escape(v)+"'></input>")}u.keyup(function(D){if(D.keyCode==27){$(this).trigger("blur")}else{if((D.keyCode==13)||(D.keyCode==188)||(D.keyCode==32)){new_value=this.value;if(return_key_pressed_for_autocomplete==true){return_key_pressed_for_autocomplete=false;return false}if(new_value.indexOf(": ",new_value.length-2)!=-1){this.value=new_value.substring(0,new_value.length-1);return false}if((D.keyCode==188)||(D.keyCode==32)){new_value=new_value.substring(0,new_value.length-1)}new_value=new_value.replace(/^\s+|\s+$/g,"");if(new_value.length<3){return false}this.value="";var A=j(new_value);var z=m.children(".tag-button");if(z.length!=0){var E=z.slice(z.length-1);E.after(A)}else{m.prepend(A)}var y=new_value.split(":");p.tags[y[0]]=y[1];var B=p.get_toggle_link_text_fn(p.tags);s.text(B);var C=$(this);$.ajax({url:p.ajax_add_tag_url,data:{new_tag:new_value},error:function(){A.remove();delete p.tags[y[0]];var F=p.get_toggle_link_text_fn(p.tags);s.text(F);alert("Add tag failed")},success:function(){C.flushCache()}});return false}}});var w=function(A,z,y,C,B){tag_name_and_value=C.split(":");return(tag_name_and_value.length==1?tag_name_and_value[0]:tag_name_and_value[1])};var x={selectFirst:false,formatItem:w,autoFill:false,highlight:false};u.autocomplete(p.ajax_autocomplete_tag_url,x);u.addClass("tag-input");return u};for(tag_name in p.tags){var q=p.tags[tag_name];var l=a(tag_name,q);var g=j(l,s,p.tags);m.append(g)}var n=d("");var f=i(n);m.blur(function(u){r=o(p.tags);if(r!=0){f.show();n.hide();m.removeClass("active-tag-area")}else{}});m.append(f);m.append(n);n.hide();m.click(function(w){var v=$(this).hasClass("active-tag-area");if($(w.target).hasClass("delete-tag-img")&&!v){return false}if($(w.target).hasClass("tag-name")&&!v){return false}$(this).addClass("active-tag-area");f.hide();n.show();n.focus();var u=function(y){var x=m.attr("id");if(($(y.target).attr("id")!=x)&&($(y.target).parents().filter(x).length==0)){m.blur();$(document).unbind("click",u)}};$(window).click(u);return false});if(p.use_toggle_link){m.hide()}else{var r=o(p.tags);if(r==0){f.hide();n.show()}}return this.addClass("tag-element")};
|
||||
var ac_tag_area_id_gen=1;jQuery.fn.autocomplete_tagging=function(c){var e={get_toggle_link_text_fn:function(u){var w="";var v=o(u);if(v!=0){w=v+(v!=0?" Tags":" Tag")}else{w="Add tags"}return w},tag_click_fn:function(u,v){},editable:true,input_size:20,in_form:false,tags:{},use_toggle_link:true,item_id:"",add_tag_img:"",add_tag_img_rollover:"",delete_tag_img:"",ajax_autocomplete_tag_url:"",ajax_retag_url:"",ajax_delete_tag_url:"",ajax_add_tag_url:""};var p=jQuery.extend(e,c);var k="tag-area-"+(ac_tag_area_id_gen)++;var m=$("<div>").attr("id",k).addClass("tag-area");this.append(m);var o=function(u){if(u.length){return u.length}var v=0;for(element in u){v++}return v};var b=function(){var u=p.get_toggle_link_text_fn(p.tags);var v=$("<a href='/history/tags'>").text(u).addClass("toggle-link");v.click(function(){var w=(m.css("display")=="none");var x;if(w){x=function(){var y=o(p.tags);if(y==0){m.click()}}}else{x=function(){m.blur()}}m.slideToggle("fast",x);return false});return v};var s=b();if(p.use_toggle_link){this.prepend(s)}var t=function(u){var v=new Array();for(key in u){v[v.length]=key+"-->"+u[key]}return"{"+v.join(",")+"}"};var a=function(v,u){return v+((u!=""&&u)?":"+u:"")};var h=function(u){return u.split(":")};var i=function(u){var v=$("<img src='"+p.add_tag_img+"' rollover='"+p.add_tag_img_rollover+"'/>").addClass("add-tag-button");v.click(function(){$(this).hide();m.click();return false});return v};var j=function(u){var v=$("<img src='"+p.delete_tag_img+"'/>").addClass("delete-tag-img");v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)});v.click(function(){var D=$(this).parent();var C=D.find(".tag-name").eq(0);var B=C.text();var z=h(B);var F=z[0];var y=z[1];var E=D.prev();D.remove();delete p.tags[F];var A=p.get_toggle_link_text_fn(p.tags);s.text(A);$.ajax({url:p.ajax_delete_tag_url,data:{tag_name:F},error:function(){p.tags[F]=y;if(E.hasClass("tag-button")){E.after(D)}else{m.prepend(D)}var G=p.get_toggle_link_text_fn(p.tags);alert("Remove tag failed");s.text(G);v.mouseenter(function(){$(this).attr("src",p.delete_tag_img_rollover)});v.mouseleave(function(){$(this).attr("src",p.delete_tag_img)})},success:function(){}});return true});var w=$("<span>").text(u).addClass("tag-name");w.click(function(){tag_name_and_value=u.split(":");p.tag_click_fn(tag_name_and_value[0],tag_name_and_value[1]);return true});var x=$("<span></span>").addClass("tag-button");x.append(w);if(p.editable){x.append(v)}return x};var d=function(v){var u;if(p.in_form){u=$("<textarea id='history-tag-input' rows='1' cols='"+p.input_size+"' value='"+escape(v)+"'></textarea>")}else{u=$("<input id='history-tag-input' type='text' size='"+p.input_size+"' value='"+escape(v)+"'></input>")}u.keyup(function(D){if(D.keyCode==27){$(this).trigger("blur")}else{if((D.keyCode==13)||(D.keyCode==188)||(D.keyCode==32)){new_value=this.value;if(return_key_pressed_for_autocomplete==true){return_key_pressed_for_autocomplete=false;return false}if(new_value.indexOf(": ",new_value.length-2)!=-1){this.value=new_value.substring(0,new_value.length-1);return false}if((D.keyCode==188)||(D.keyCode==32)){new_value=new_value.substring(0,new_value.length-1)}new_value=new_value.replace(/^\s+|\s+$/g,"");if(new_value.length<3){return false}this.value="";var A=j(new_value);var z=m.children(".tag-button");if(z.length!=0){var E=z.slice(z.length-1);E.after(A)}else{m.prepend(A)}var y=new_value.split(":");p.tags[y[0]]=y[1];var B=p.get_toggle_link_text_fn(p.tags);s.text(B);var C=$(this);$.ajax({url:p.ajax_add_tag_url,data:{new_tag:new_value},error:function(){A.remove();delete p.tags[y[0]];var F=p.get_toggle_link_text_fn(p.tags);s.text(F);alert("Add tag failed")},success:function(){C.flushCache()}});return false}}});var w=function(A,z,y,C,B){tag_name_and_value=C.split(":");return(tag_name_and_value.length==1?tag_name_and_value[0]:tag_name_and_value[1])};var x={selectFirst:false,formatItem:w,autoFill:false,highlight:false};u.autocomplete(p.ajax_autocomplete_tag_url,x);u.addClass("tag-input");return u};for(tag_name in p.tags){var q=p.tags[tag_name];var l=a(tag_name,q);var g=j(l,s,p.tags);m.append(g)}var n=d("");var f=i(n);m.blur(function(u){r=o(p.tags);if(r!=0){f.show();n.hide();m.removeClass("active-tag-area")}else{}});if(p.editable){m.append(f);m.append(n);n.hide();m.click(function(w){var v=$(this).hasClass("active-tag-area");if($(w.target).hasClass("delete-tag-img")&&!v){return false}if($(w.target).hasClass("tag-name")&&!v){return false}$(this).addClass("active-tag-area");f.hide();n.show();n.focus();var u=function(y){var x=m.attr("id");if(($(y.target).attr("id")!=x)&&($(y.target).parents().filter(x).length==0)){m.blur();$(document).unbind("click",u)}};$(window).click(u);return false})}if(p.use_toggle_link){m.hide()}else{var r=o(p.tags);if(r==0){f.hide();n.show()}}return this.addClass("tag-element")};
|
||||
File diff suppressed because one or more lines are too long
+134
-136
@@ -4,7 +4,9 @@
|
||||
|
||||
var DENSITY = 1000,
|
||||
DATA_ERROR = "There was an error in indexing this dataset.",
|
||||
DATA_NONE = "No data for this chrom/contig.";
|
||||
DATA_NONE = "No data for this chrom/contig.",
|
||||
CACHED_TILES = 200,
|
||||
CACHED_DATA = 20;
|
||||
|
||||
var View = function( chrom, max_length ) {
|
||||
this.chrom = chrom;
|
||||
@@ -29,7 +31,7 @@ $.extend( View.prototype, {
|
||||
}).show();
|
||||
$("#low").text( this.low );
|
||||
$("#high").text( this.high );
|
||||
for ( var i in this.tracks ) {
|
||||
for ( var i = 0, len = this.tracks.length; i < len; i++ ) {
|
||||
this.tracks[i].draw();
|
||||
}
|
||||
$("#bottom-spacer").remove();
|
||||
@@ -40,18 +42,19 @@ $.extend( View.prototype, {
|
||||
this.high = Math.min( this.length, Math.ceil( new_high ) );
|
||||
},
|
||||
zoom_in: function ( factor, point ) {
|
||||
if (this.max_high == 0) return;
|
||||
if (this.max_high === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var range = this.high - this.low;
|
||||
var diff = range / factor / 2;
|
||||
var center;
|
||||
|
||||
if (point == undefined) {
|
||||
var center = ( this.low + this.high ) / 2;
|
||||
if (point === undefined) {
|
||||
center = ( this.low + this.high ) / 2;
|
||||
} else {
|
||||
// console.log(100*point/$(document).width());
|
||||
var center = this.low + range * point / $(document).width();
|
||||
center = this.low + range * point / $(document).width();
|
||||
}
|
||||
// console.log(center);
|
||||
this.low = Math.floor( center - diff );
|
||||
this.high = Math.ceil( center + diff );
|
||||
if (this.low < this.max_low) {
|
||||
@@ -67,7 +70,9 @@ $.extend( View.prototype, {
|
||||
}
|
||||
},
|
||||
zoom_out: function ( factor ) {
|
||||
if (this.max_high == 0) return;
|
||||
if (this.max_high === 0) {
|
||||
return;
|
||||
}
|
||||
var center = ( this.low + this.high ) / 2;
|
||||
var range = this.high - this.low;
|
||||
var diff = range * factor / 2;
|
||||
@@ -105,7 +110,7 @@ var Track = function ( name, parent_element ) {
|
||||
};
|
||||
$.extend( Track.prototype, {
|
||||
make_container: function () {
|
||||
this.header_div = $("<div class='track-header'>").text( this.name );;
|
||||
this.header_div = $("<div class='track-header'>").text( this.name );
|
||||
this.content_div = $("<div class='track-content'>");
|
||||
this.container_div = $("<div class='track'></div>").append( this.header_div ).append( this.content_div );
|
||||
this.parent_element.append( this.container_div );
|
||||
@@ -113,9 +118,7 @@ $.extend( Track.prototype, {
|
||||
});
|
||||
|
||||
var TiledTrack = function() {
|
||||
this.last_resolution = null;
|
||||
this.last_w_scale = null;
|
||||
this.tile_cache = {};
|
||||
this.tile_cache = new Cache(CACHED_TILES);
|
||||
};
|
||||
$.extend( TiledTrack.prototype, Track.prototype, {
|
||||
draw: function() {
|
||||
@@ -133,23 +136,17 @@ $.extend( TiledTrack.prototype, Track.prototype, {
|
||||
|
||||
var w = this.content_div.width(),
|
||||
h = this.content_div.height(),
|
||||
w_scale = w / range,
|
||||
old_tiles = {},
|
||||
new_tiles = {};
|
||||
|
||||
// If resolution and scale are unchanged, try to reuse tiles
|
||||
if ( this.last_resolution == resolution && this.last_w_scale == w_scale ) {
|
||||
old_tiles = this.tile_cache;
|
||||
}
|
||||
w_scale = w / range;
|
||||
|
||||
var tile_element;
|
||||
// Index of first tile that overlaps visible region
|
||||
var tile_index = Math.floor( low / resolution / DENSITY );
|
||||
while ( ( tile_index * 1000 * resolution ) < high ) {
|
||||
while ( ( tile_index * DENSITY * resolution ) < high ) {
|
||||
// Check in cache
|
||||
if ( tile_index in old_tiles ) {
|
||||
// console.log( "tile from cache" );
|
||||
tile_element = old_tiles[tile_index];
|
||||
var key = w_scale + "_" + tile_index;
|
||||
if ( this.tile_cache[key] ) {
|
||||
// console.log("cached tile");
|
||||
tile_element = this.tile_cache[key];
|
||||
var tile_low = tile_index * DENSITY * resolution;
|
||||
tile_element.css( {
|
||||
left: ( tile_low - this.view.low ) * w_scale
|
||||
@@ -160,14 +157,10 @@ $.extend( TiledTrack.prototype, Track.prototype, {
|
||||
tile_element = this.draw_tile( resolution, tile_index, parent_element, w_scale, h );
|
||||
}
|
||||
if ( tile_element ) {
|
||||
// console.log( typeof(tile_element) );
|
||||
new_tiles[tile_index] = tile_element;
|
||||
this.tile_cache[key] = tile_element;
|
||||
}
|
||||
tile_index += 1;
|
||||
}
|
||||
this.last_resolution = resolution;
|
||||
this.last_w_scale = w_scale;
|
||||
this.tile_cache = new_tiles;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -199,70 +192,67 @@ $.extend( LabelTrack.prototype, Track.prototype, {
|
||||
|
||||
var LineTrack = function ( name, dataset_id, height ) {
|
||||
Track.call( this, name, $("#viewport") );
|
||||
TiledTrack.call( this );
|
||||
|
||||
this.track_type = "line";
|
||||
this.height_px = (height ? height : 100);
|
||||
this.container_div.addClass( "line-track" );
|
||||
this.content_div.css( "height", this.height_px + "px" );
|
||||
this.dataset_id = dataset_id;
|
||||
this.cache = new Cache(50);
|
||||
this.cache = new Cache(CACHED_DATA); // We need to cache some data because of
|
||||
// asynchronous calls
|
||||
};
|
||||
$.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
init: function() {
|
||||
var track = this;
|
||||
$.getJSON( data_url, { stats: true, track_type: track.track_type, chrom: track.view.chrom,
|
||||
low: null, high: null, dataset_id: track.dataset_id }, function ( data ) {
|
||||
$.getJSON( data_url, { stats: true, track_type: track.track_type,
|
||||
chrom: track.view.chrom, low: null, high: null,
|
||||
dataset_id: track.dataset_id }, function ( data ) {
|
||||
if (!data || data == "error") {
|
||||
track.content_div.addClass("error").text(DATA_ERROR);
|
||||
} else if (data == "no data") {
|
||||
// console.log(track.content_div);
|
||||
track.content_div.addClass("nodata").text(DATA_NONE);
|
||||
} else {
|
||||
track.min_value = data['min'];
|
||||
track.max_value = data['max'];
|
||||
track.content_div.css( "height", track.height_px + "px" );
|
||||
track.min_value = data.min;
|
||||
track.max_value = data.max;
|
||||
track.vertical_range = track.max_value - track.min_value;
|
||||
track.view.redraw();
|
||||
}
|
||||
});
|
||||
},
|
||||
get_data: function( resolution, position ) {
|
||||
var key = resolution + '-' + position,
|
||||
cache = this.cache;
|
||||
|
||||
if ( !cache[key] ) {
|
||||
var low = position * DENSITY * resolution,
|
||||
high = ( position + 1 ) * DENSITY * resolution;
|
||||
|
||||
$.getJSON( data_url, { track_type: this.track_type, chrom: this.view.chrom, low: low, high: high, dataset_id: this.dataset_id }, function ( data ) {
|
||||
cache[key] = data;
|
||||
$(document).trigger( "redraw" );
|
||||
});
|
||||
}
|
||||
return cache[key];
|
||||
var track = this,
|
||||
low = position * DENSITY * resolution,
|
||||
high = ( position + 1 ) * DENSITY * resolution,
|
||||
key = resolution + "_" + position;
|
||||
|
||||
$.getJSON( data_url, { track_type: this.track_type, chrom: this.view.chrom, low: low, high: high, dataset_id: this.dataset_id }, function ( data ) {
|
||||
track.cache[key] = data;
|
||||
$(document).trigger( "redraw" );
|
||||
});
|
||||
},
|
||||
draw_tile: function( resolution, tile_index, parent_element, w_scale, h_scale ) {
|
||||
if (!this.vertical_range) // We don't have the necessary information yet
|
||||
if (!this.vertical_range) { // We don't have the necessary information yet
|
||||
return;
|
||||
|
||||
var tile_low = tile_index * DENSITY * resolution,
|
||||
tile_high = ( tile_index + 1 ) * DENSITY * resolution,
|
||||
tile_length = DENSITY * resolution;
|
||||
var data = this.get_data( resolution, tile_index );
|
||||
if ( !data ) {
|
||||
in_path = false;
|
||||
return null;
|
||||
}
|
||||
var element = $("<canvas class='tile'></canvas>");
|
||||
|
||||
element.css( {
|
||||
|
||||
var tile_low = tile_index * DENSITY * resolution,
|
||||
tile_length = DENSITY * resolution,
|
||||
canvas = $("<canvas class='tile'></canvas>"),
|
||||
key = resolution + "_" + tile_index;
|
||||
|
||||
if (!this.cache[key]) {
|
||||
this.get_data( resolution, tile_index );
|
||||
return;
|
||||
}
|
||||
|
||||
var data = this.cache[key];
|
||||
canvas.css( {
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: ( tile_low - this.view.low ) * w_scale,
|
||||
left: ( tile_low - this.view.low ) * w_scale
|
||||
});
|
||||
parent_element.append( element );
|
||||
// Chunk is still loading, do nothing
|
||||
|
||||
var canvas = element;
|
||||
|
||||
canvas.get(0).width = Math.ceil( tile_length * w_scale );
|
||||
canvas.get(0).height = this.height_px;
|
||||
var ctx = canvas.get(0).getContext("2d");
|
||||
@@ -277,8 +267,7 @@ $.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
} else {
|
||||
// Translate
|
||||
x = x * w_scale;
|
||||
y_above_min = y - this.min_value;
|
||||
y = y_above_min / this.vertical_range * this.height_px;
|
||||
y = (y - this.min_value) / this.vertical_range * this.height_px;
|
||||
if ( in_path ) {
|
||||
ctx.lineTo( x, y );
|
||||
} else {
|
||||
@@ -288,44 +277,69 @@ $.extend( LineTrack.prototype, TiledTrack.prototype, {
|
||||
}
|
||||
}
|
||||
ctx.stroke();
|
||||
return element;
|
||||
parent_element.append( canvas );
|
||||
return canvas;
|
||||
}
|
||||
});
|
||||
|
||||
var FeatureTrack = function ( name, dataset_id, height ) {
|
||||
Track.call( this, name, $("#viewport") );
|
||||
TiledTrack.call( this );
|
||||
|
||||
this.track_type = "feature";
|
||||
this.height_px = (height ? height : 100);
|
||||
this.container_div.addClass( "feature-track" );
|
||||
this.content_div.css( "height", this.height_px + "px" );
|
||||
this.dataset_id = dataset_id;
|
||||
this.zo_slots = {};
|
||||
this.show_labels_scale = 0.01;
|
||||
this.show_labels_scale = 0.001;
|
||||
this.showing_labels = false;
|
||||
this.vertical_gap = 10;
|
||||
};
|
||||
$.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
init: function() {
|
||||
var track = this;
|
||||
$.getJSON( data_url, { track_type: track.track_type, low: track.view.max_low,
|
||||
high: track.view.max_high, dataset_id: track.dataset_id,
|
||||
chrom: track.view.chrom }, function ( data ) {
|
||||
if (data == "error") {
|
||||
track.content_div.addClass("error").text(DATA_ERROR);
|
||||
} else if (data.length === 0 || data == "no data") {
|
||||
track.content_div.addClass("nodata").text(DATA_NONE);
|
||||
} else {
|
||||
track.content_div.css( "height", track.height_px + "px" );
|
||||
track.values = data;
|
||||
track.calc_slots();
|
||||
track.slots = track.zo_slots;
|
||||
track.draw();
|
||||
}
|
||||
});
|
||||
},
|
||||
calc_slots: function( include_labels ) {
|
||||
// console.log("num vals: " + this.values.length);
|
||||
var end_ary = [];
|
||||
var scale = this.container_div.width() / (this.view.high - this.view.low);
|
||||
var end_ary = [],
|
||||
scale = this.container_div.width() / (this.view.high - this.view.low),
|
||||
labels_scale = this.show_labels_scale,
|
||||
max_high = this.view.max_high,
|
||||
max_low = this.view.max_low;
|
||||
// console.log(scale, this.view.high, this.view.low);
|
||||
if (include_labels) this.zi_slots = {};
|
||||
if (include_labels) {
|
||||
this.zi_slots = {};
|
||||
}
|
||||
var dummy_canvas = $("<canvas></canvas>").get(0).getContext("2d");
|
||||
for (var i in this.values) {
|
||||
|
||||
var feature = this.values[i];
|
||||
var f_start = Math.floor( Math.max(this.view.max_low, (feature.start - this.view.max_low) * scale) );
|
||||
for (var i = 0, len = this.values.length; i < len; i++) {
|
||||
var f_start, f_end, feature = this.values[i];
|
||||
if (include_labels) {
|
||||
f_start = Math.floor( Math.max(max_low, (feature.start - max_low) * labels_scale) );
|
||||
f_start -= dummy_canvas.measureText(feature.name).width;
|
||||
f_start -= 10; // Spacing between text and line
|
||||
f_end = Math.ceil( Math.min(max_high, (feature.end - max_low) * labels_scale) );
|
||||
} else {
|
||||
f_start = Math.floor( Math.max(max_low, (feature.start - max_low) * scale) );
|
||||
f_end = Math.ceil( Math.min(max_high, (feature.end - max_low) * scale) );
|
||||
}
|
||||
|
||||
var f_end = Math.ceil( Math.min(this.view.max_high, (feature.end - this.view.max_low) * scale) );
|
||||
// if (include_labels) { console.log(f_start, f_end); }
|
||||
var j = 0;
|
||||
while (true) {
|
||||
if (end_ary[j] == undefined || end_ary[j] < f_start) {
|
||||
if (end_ary[j] === undefined || end_ary[j] < f_start) {
|
||||
end_ary[j] = f_end;
|
||||
if (include_labels) {
|
||||
this.zi_slots[feature.name] = j;
|
||||
@@ -340,33 +354,16 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
this.height_px = end_ary.length * this.vertical_gap + 15;
|
||||
this.content_div.css( "height", this.height_px + "px" );
|
||||
},
|
||||
|
||||
init: function() {
|
||||
var track = this;
|
||||
$.getJSON( data_url, { track_type: track.track_type, low: track.view.max_low, high: track.view.max_high,
|
||||
dataset_id: track.dataset_id, chrom: track.view.chrom }, function ( data ) {
|
||||
if (data == "error") {
|
||||
track.content_div.addClass("error").text(DATA_ERROR);
|
||||
} else if (data.length == 0 || data == "no data") {
|
||||
// console.log(track.content_div);
|
||||
track.content_div.addClass("nodata").text(DATA_NONE);
|
||||
} else {
|
||||
track.values = data;
|
||||
track.calc_slots();
|
||||
track.slots = track.zo_slots;
|
||||
// console.log(track.zo_slots);
|
||||
track.draw();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
draw_tile: function( resolution, tile_index, parent_element, w_scale, h_scale ) {
|
||||
if (!this.values) // Still loading
|
||||
if (!this.values) { // Still loading
|
||||
return null;
|
||||
|
||||
}
|
||||
// Once we zoom in enough, show name labels
|
||||
if (w_scale > this.show_labels_scale && !this.showing_labels) {
|
||||
this.showing_labels = true;
|
||||
if (!this.zi_slots) this.calc_slots(true); // Once we zoom in enough, show name labels
|
||||
if (!this.zi_slots) {
|
||||
this.calc_slots(true);
|
||||
}
|
||||
this.slots = this.zi_slots;
|
||||
} else if (w_scale <= this.show_labels_scale && this.showing_labels) {
|
||||
this.showing_labels = false;
|
||||
@@ -378,63 +375,64 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
tile_high = ( tile_index + 1 ) * DENSITY * resolution,
|
||||
tile_length = DENSITY * resolution;
|
||||
// console.log(tile_low, tile_high, tile_length, w_scale);
|
||||
var view = this.view,
|
||||
range = view.high - view.low,
|
||||
width = Math.ceil( tile_length * w_scale ),
|
||||
slots = new Array(),
|
||||
var width = Math.ceil( tile_length * w_scale ),
|
||||
height = this.height_px,
|
||||
new_canvas = $("<canvas class='tile'></canvas>");
|
||||
|
||||
new_canvas.css({
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: ( tile_low - this.view.low ) * w_scale,
|
||||
left: ( tile_low - this.view.low ) * w_scale
|
||||
});
|
||||
new_canvas.get(0).width = width;
|
||||
new_canvas.get(0).height = height;
|
||||
// console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
|
||||
var ctx = new_canvas.get(0).getContext("2d");
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.font = "10px monospace";
|
||||
ctx.textAlign = "right";
|
||||
|
||||
var j = 0;
|
||||
for (var i in this.values) {
|
||||
feature = this.values[i];
|
||||
for (var i = 0, len = this.values.length; i < len; i++) {
|
||||
var feature = this.values[i];
|
||||
if (feature.start <= tile_high && feature.end >= tile_low) {
|
||||
f_start = Math.floor( Math.max(0, (feature.start - tile_low) * w_scale) );
|
||||
f_end = Math.ceil( Math.min(width, (feature.end - tile_low) * w_scale) );
|
||||
var f_start = Math.floor( Math.max(0, (feature.start - tile_low) * w_scale) ),
|
||||
f_end = Math.ceil( Math.min(width, (feature.end - tile_low) * w_scale) ),
|
||||
y_center = this.slots[feature.name] * this.vertical_gap;
|
||||
|
||||
// console.log(feature.start, feature.end, f_start, f_end, j);
|
||||
ctx.fillStyle = "#000";
|
||||
ctx.fillRect(f_start, this.slots[feature.name] * this.vertical_gap + 5, f_end - f_start, 1);
|
||||
ctx.fillRect(f_start, y_center + 5, f_end - f_start, 1);
|
||||
|
||||
if (this.showing_labels && ctx.fillText) {
|
||||
ctx.font = "10px monospace";
|
||||
ctx.textAlign = "right";
|
||||
ctx.fillText(feature.name, f_start, this.slots[feature.name] * 10 + 8);
|
||||
ctx.fillText(feature.name, f_start, y_center + 8);
|
||||
}
|
||||
|
||||
var exon_start, exon_end;
|
||||
if (feature.exon_start && feature.exon_end) {
|
||||
var exon_start = Math.floor( Math.max(0, (feature.exon_start - tile_low) * w_scale) );
|
||||
var exon_end = Math.ceil( Math.min(width, (feature.exon_end - tile_low) * w_scale) );
|
||||
// ctx.fillRect(exon_start, j * 10 + 3, exon_end - exon_start, 5);
|
||||
// ctx.fillRect(exon_start, this.slots[feature.name] * 10 + 3, exon_end - exon_start, 3);
|
||||
exon_start = Math.floor( Math.max(0, (feature.exon_start - tile_low) * w_scale) );
|
||||
exon_end = Math.ceil( Math.min(width, (feature.exon_end - tile_low) * w_scale) );
|
||||
ctx.fillRect(exon_start, y_center + 4, exon_end - exon_start, 3);
|
||||
}
|
||||
|
||||
for (var i in feature.blocks) {
|
||||
block = feature.blocks[i];
|
||||
block_start = Math.floor( Math.max(0, (block[0] - tile_low) * w_scale) );
|
||||
block_end = Math.ceil( Math.min(width, (block[1] - tile_low) * w_scale) );
|
||||
var thickness = 3, y_start = 4;
|
||||
if (exon_start && block_start >= exon_start && block_end <= exon_end) {
|
||||
thickness = 5, y_start = 3;
|
||||
}
|
||||
ctx.fillRect(exon_start, this.slots[feature.name] * this.vertical_gap + y_start, block_end - block_start, thickness);
|
||||
// console.log(block_start, block_end);
|
||||
if (feature.blocks) {
|
||||
for (var k = 0, k_len = feature.blocks.length; k < k_len; k++) {
|
||||
var block = feature.blocks[k],
|
||||
block_start = Math.floor( Math.max(0, (block[0] - tile_low) * w_scale) ),
|
||||
block_end = Math.ceil( Math.min(width, (block[1] - tile_low) * w_scale) );
|
||||
var thickness = 3, y_start = 4;
|
||||
if (exon_start && block_start >= exon_start && block_end <= exon_end) {
|
||||
thickness = 5;
|
||||
y_start = 3;
|
||||
}
|
||||
ctx.fillRect(block_start, y_center + y_start, block_end - block_start, thickness);
|
||||
// console.log(block_start, block_end);
|
||||
}
|
||||
}
|
||||
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
parent_element.append( new_canvas );
|
||||
return new_canvas;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
+4
-14
@@ -85,13 +85,15 @@ body {
|
||||
|
||||
.track-content.error {
|
||||
text-align: center;
|
||||
padding-top: 30px;
|
||||
padding-top: 10px;
|
||||
background-color: #ECB4AF;
|
||||
height: 30px;
|
||||
}
|
||||
.track-content.nodata {
|
||||
text-align: center;
|
||||
padding-top: 30px;
|
||||
padding-top: 10px;
|
||||
background-color: #ddd;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
@@ -102,15 +104,3 @@ body {
|
||||
border-left: solid gray 1px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
.feature-track .feature {
|
||||
|
||||
}
|
||||
|
||||
.feature-track .feature .forward {
|
||||
|
||||
}
|
||||
|
||||
.feature-track .feature .reverse {
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user