mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
trackster: load block data incrementally, huge performance gains from drawing smaller tiles
This commit is contained in:
@@ -18,11 +18,10 @@ class IntervalIndexDataProvider( object ):
|
||||
index = Indexes( self.converted_dataset.file_name )
|
||||
results = []
|
||||
|
||||
uid = 0
|
||||
for start, end, offset in index.find(chrom, start, end):
|
||||
source.seek(offset)
|
||||
feature = source.readline().split()
|
||||
payload = { 'uid': uid, 'start': start, 'end': end, 'name': feature[3] }
|
||||
payload = { 'uid': offset, 'start': start, 'end': end, 'name': feature[3] }
|
||||
try:
|
||||
payload['strand'] = feature[5]
|
||||
except IndexError:
|
||||
@@ -44,6 +43,5 @@ class IntervalIndexDataProvider( object ):
|
||||
pass
|
||||
|
||||
results.append(payload)
|
||||
uid += 1
|
||||
|
||||
return results
|
||||
|
||||
@@ -1 +1 @@
|
||||
$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};jQuery(document).ready(function(){jQuery("a[confirm]").click(function(){return confirm(jQuery(this).attr("confirm"))});jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.show()})});function ensure_popup_helper(){if($("#popup-helper").length==0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function make_popupmenu(d,c){ensure_popup_helper();var a=$(d);var b=$("<ul id='"+d.attr("id")+"-menu'></ul>");$.each(c,function(g,f){if(f){$("<li/>").html(g).click(f).appendTo(b)}else{$("<li class='head'/>").html(g).appendTo(b)}});var e=$("<div class='popmenu-wrapper'>");e.append(b).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(d,e)}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){var h=$(b).offset();$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)};
|
||||
$.fn.makeAbsolute=function(a){return this.each(function(){var b=$(this);var c=b.position();b.css({position:"absolute",marginLeft:0,marginTop:0,top:c.top,left:c.left,right:$(window).width()-(c.left+b.width())});if(a){b.remove().appendTo("body")}})};jQuery(document).ready(function(){jQuery("a[confirm]").click(function(){return confirm(jQuery(this).attr("confirm"))});make_popup_menus()});function make_popup_menus(){jQuery("div[popupmenu]").each(function(){var c={};$(this).find("a").each(function(){var b=$(this).attr("confirm"),d=$(this).attr("href"),e=$(this).attr("target");c[$(this).text()]=function(){if(!b||confirm(b)){var g=window;if(e=="_parent"){g=window.parent}g.location=d}}});var a=$("#"+$(this).attr("popupmenu"));make_popupmenu(a,c);$(this).remove();a.show()})}function ensure_popup_helper(){if($("#popup-helper").length==0){$("<div id='popup-helper'/>").css({background:"white",opacity:0,zIndex:15000,position:"absolute",top:0,left:0,width:"100%",height:"100%"}).appendTo("body").hide()}}function make_popupmenu(d,c){ensure_popup_helper();var a=$(d);var b=$("<ul id='"+d.attr("id")+"-menu'></ul>");$.each(c,function(g,f){if(f){$("<li/>").html(g).click(f).appendTo(b)}else{$("<li class='head'/>").html(g).appendTo(b)}});var e=$("<div class='popmenu-wrapper'>");e.append(b).append("<div class='overlay-border'>").css("position","absolute").appendTo("body").hide();attach_popupmenu(d,e)}function attach_popupmenu(b,d){var a=function(){d.unbind().hide();$("#popup-helper").unbind("click.popupmenu").hide()};var c=function(g){var h=$(b).offset();$("#popup-helper").bind("click.popupmenu",a).show();d.click(a).css({left:0,top:-1000}).show();var f=g.pageX-d.width()/2;f=Math.min(f,$(document).scrollLeft()+$(window).width()-$(d).width()-20);f=Math.max(f,$(document).scrollLeft()+20);d.css({top:g.pageY-5,left:f});return false};$(b).click(c)}var array_length=function(a){if(a.length){return a.length}var b=0;for(element in a){b++}return b};
|
||||
File diff suppressed because one or more lines are too long
+39
-42
@@ -1,7 +1,7 @@
|
||||
/* Trackster
|
||||
2009, James Taylor, Kanwei Li
|
||||
*/
|
||||
var DEBUG = true;
|
||||
var DEBUG = false;
|
||||
|
||||
var DENSITY = 1000,
|
||||
FEATURE_LEVELS = 100,
|
||||
@@ -109,7 +109,7 @@ $.extend( View.prototype, {
|
||||
|
||||
// 10^log10(range / DENSITY) Close approximation for browser window, assuming DENSITY = window width
|
||||
this.resolution = Math.pow( 10, Math.ceil( Math.log( (this.high - this.low) / DENSITY ) / Math.LN10 ) );
|
||||
this.zoom_res = Math.max(1,Math.ceil( Math.log( (this.high - this.low) / FEATURE_LEVELS ) / Math.log(FEATURE_LEVELS) ));
|
||||
this.zoom_res = Math.max(1,Math.ceil( Math.log( this.resolution, FEATURE_LEVELS ) / Math.log(FEATURE_LEVELS) ));
|
||||
|
||||
// Overview
|
||||
$("#overview-box").css( {
|
||||
@@ -404,7 +404,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
});
|
||||
},
|
||||
get_data: function( low, high ) {
|
||||
console.log("getting: ", low, high);
|
||||
// console.log("getting: ", low, high);
|
||||
var track = this,
|
||||
key = low + '_' + high;
|
||||
|
||||
@@ -420,39 +420,24 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
});
|
||||
}
|
||||
},
|
||||
calc_slots: function( include_labels ) {
|
||||
calc_slots: function() {
|
||||
// console.log("num vals: " + this.values.length);
|
||||
var end_ary = [],
|
||||
scale = this.content_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 = {};
|
||||
}
|
||||
var dummy_canvas = $("<canvas></canvas>").get(0).getContext("2d");
|
||||
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( (feature.start - max_low) * labels_scale );
|
||||
f_start -= dummy_canvas.measureText(feature.name).width;
|
||||
f_end = Math.ceil( (feature.end - max_low) * labels_scale );
|
||||
} else {
|
||||
f_start = Math.floor( (feature.start - max_low) * scale );
|
||||
f_end = Math.ceil( (feature.end - max_low) * scale );
|
||||
}
|
||||
f_start = Math.floor( (feature.start - max_low) * scale );
|
||||
f_end = Math.ceil( (feature.end - 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) {
|
||||
end_ary[j] = f_end;
|
||||
if (include_labels) {
|
||||
this.zi_slots[feature.uid] = j;
|
||||
} else {
|
||||
this.zo_slots[feature.uid] = j;
|
||||
}
|
||||
this.zo_slots[feature.uid] = j;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
@@ -464,20 +449,23 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
incremental_slots: function( level, features ) {
|
||||
if (!this.inc_slots[level]) {
|
||||
this.inc_slots[level] = {};
|
||||
this.inc_slots[level].w_scale = 1000 / Math.pow(FEATURE_LEVELS, level);
|
||||
this.inc_slots[level].w_scale = DENSITY / Math.pow(FEATURE_LEVELS, level+1);
|
||||
// this.inc_slots[level].w_scale = 1000 / (this.view.high - this.view.low);
|
||||
|
||||
}
|
||||
var slots = this.inc_slots[level];
|
||||
if (slots[uid]) {
|
||||
return slots[uid];
|
||||
}
|
||||
// console.log(level, slots.w_scale, slots);
|
||||
var end_ary = [],
|
||||
undone = [],
|
||||
max_high = this.view.max_high,
|
||||
highest_slot = 0, // To measure how big to draw canvas
|
||||
dummy_canvas = $("<canvas></canvas>").get(0).getContext("2d"),
|
||||
max_low = this.view.max_low;
|
||||
|
||||
for (var i = 0, len = features.length; i < len; i++) {
|
||||
var feature = features[i];
|
||||
// console.log(feature.name, feature.uid, slots[feature.uid]);
|
||||
if (slots[feature.uid]) {
|
||||
highest_slot = Math.max(highest_slot, slots[feature.uid]);
|
||||
end_ary[ slots[feature.uid] ] = Math.ceil( (feature.end - max_low) * slots.w_scale );
|
||||
} else {
|
||||
undone.push(feature);
|
||||
@@ -488,6 +476,19 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
f_start = Math.floor( (feature.start - max_low) * slots.w_scale );
|
||||
f_start -= dummy_canvas.measureText(feature.name).width;
|
||||
f_end = Math.ceil( (feature.end - max_low) * slots.w_scale );
|
||||
// console.log(f_start, f_end, feature.name);
|
||||
var j = 0;
|
||||
while (true) {
|
||||
if (end_ary[j] === undefined || end_ary[j] < f_start) {
|
||||
end_ary[j] = f_end;
|
||||
slots[feature.uid] = j;
|
||||
highest_slot = Math.max(highest_slot, j);
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return highest_slot;
|
||||
|
||||
},
|
||||
draw_tile: function( resolution, tile_index, parent_element, w_scale ) {
|
||||
@@ -499,14 +500,10 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
tile_span = DENSITY * resolution;
|
||||
// console.log("drawing " + tile_index);
|
||||
// Once we zoom in enough, show name labels
|
||||
var data;
|
||||
var data, slots, required_height;
|
||||
if (w_scale > this.show_labels_scale) {
|
||||
if (!this.showing_labels) {
|
||||
this.showing_labels = true;
|
||||
if (!this.zi_slots) {
|
||||
this.calc_slots(true);
|
||||
}
|
||||
this.slots = this.zi_slots;
|
||||
}
|
||||
for (var k in this.data_cache.obj_cache) {
|
||||
var k_split = k.split("_"), k_low = k_split[0], k_high = k_split[1];
|
||||
@@ -520,20 +517,20 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
this.get_data(tile_low, tile_high);
|
||||
return;
|
||||
}
|
||||
|
||||
required_height = this.incremental_slots( this.view.zoom_res, data ) * this.vertical_gap + 15;
|
||||
// console.log(required_height);
|
||||
slots = this.inc_slots[this.view.zoom_res];
|
||||
} else {
|
||||
if (this.showing_labels) {
|
||||
this.showing_labels = false;
|
||||
this.slots = this.zo_slots;
|
||||
}
|
||||
required_height = this.height_px;
|
||||
slots = this.zo_slots;
|
||||
data = this.values;
|
||||
}
|
||||
// console.log(this.slots);
|
||||
|
||||
|
||||
|
||||
// console.log(tile_low, tile_high, tile_length, w_scale);
|
||||
var width = Math.ceil( tile_span * w_scale ),
|
||||
height = this.height_px,
|
||||
new_canvas = $("<canvas class='tile'></canvas>");
|
||||
|
||||
new_canvas.css({
|
||||
@@ -542,7 +539,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
left: ( tile_low - this.view.low ) * w_scale - this.left_offset
|
||||
});
|
||||
new_canvas.get(0).width = width + this.left_offset;
|
||||
new_canvas.get(0).height = height;
|
||||
new_canvas.get(0).height = required_height;
|
||||
// console.log(( tile_low - this.view.low ) * w_scale, tile_index, w_scale);
|
||||
var ctx = new_canvas.get(0).getContext("2d");
|
||||
ctx.fillStyle = this.base_color;
|
||||
@@ -555,7 +552,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
if (feature.start <= tile_high && feature.end >= tile_low) {
|
||||
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.uid] * this.vertical_gap;
|
||||
y_center = slots[feature.uid] * this.vertical_gap;
|
||||
|
||||
var thickness, y_start, thick_start = null, thick_end = null;
|
||||
if (feature.thick_start && feature.thick_end) {
|
||||
@@ -569,7 +566,7 @@ $.extend( FeatureTrack.prototype, TiledTrack.prototype, {
|
||||
// Showing labels, blocks, details
|
||||
if (ctx.fillText && feature.start > tile_low) {
|
||||
ctx.fillText(feature.name, f_start - 1 + this.left_offset, y_center + 8);
|
||||
// ctx.fillText(commatize(feature.start), f_start - 1, y_center + 8);
|
||||
// ctx.fillText(commatize(feature.start), f_start - 1 + this.left_offset, y_center + 8);
|
||||
}
|
||||
var blocks = feature.blocks;
|
||||
if (blocks) {
|
||||
|
||||
Reference in New Issue
Block a user