trackster: Implemented drag-zooming by letting you drag a region in the top label track (where chrom position is shown). Refactored to not use zoom levels anymore.

This commit is contained in:
Kanwei Li
2010-06-03 17:58:58 -04:00
parent 6f8aaecaa6
commit 0bcd4656bd
7 changed files with 83 additions and 55 deletions
+9
View File
@@ -454,6 +454,15 @@ function init_history_items(historywrapper, noinit, nochanges) {
}
}
function commatize( number ) {
number += ''; // Convert to string
var rgx = /(\d+)(\d{3})/;
while (rgx.test(number)) {
number = number.replace(rgx, '$1' + ',' + '$2');
}
return number;
}
$(document).ready( function() {
// Links with confirmation
$( "a[confirm]" ).click( function() {
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+30 -42
View File
@@ -1,7 +1,6 @@
/* Trackster
2010, James Taylor, Kanwei Li
*/
var DEBUG = false;
var DENSITY = 200,
FEATURE_LEVELS = 10,
@@ -37,15 +36,6 @@ left_img_inv.onload = function() {
LEFT_STRAND_INV = CONTEXT.createPattern(left_img_inv, "repeat");
};
function commatize( number ) {
number += ''; // Convert to string
var rgx = /(\d+)(\d{3})/;
while (rgx.test(number)) {
number = number.replace(rgx, '$1' + ',' + '$2');
}
return number;
}
var Cache = function( num_elements ) {
this.num_elements = num_elements;
this.clear();
@@ -87,11 +77,11 @@ var View = function( chrom, title, vis_id, dbkey ) {
this.label_tracks = [];
this.max_low = 0;
this.max_high = 0;
this.center = (this.max_high - this.max_low) / 2;
this.zoom_factor = 3;
this.zoom_level = 0;
this.track_id_counter = 0;
this.zoom_factor = 3;
this.min_separation = 30;
this.has_changes = false;
this.reset();
};
$.extend( View.prototype, {
add_track: function ( track ) {
@@ -129,27 +119,24 @@ $.extend( View.prototype, {
reset: function() {
this.low = this.max_low;
this.high = this.max_high;
this.center = this.center = (this.max_high - this.max_low) / 2;
this.zoom_level = 0;
$(".yaxislabel").remove();
},
redraw: function(nodraw) {
this.span = this.max_high - this.max_low;
var span = this.span / Math.pow(this.zoom_factor, this.zoom_level),
low = this.center - (span / 2),
high = low + span;
var span = this.high - this.low,
low = this.low,
high = this.high;
if (low < 0) {
low = 0;
high = low + span;
} else if (high > this.max_high) {
if (low < this.max_low) {
low = this.max_low;
}
if (high > this.max_high) {
high = this.max_high;
low = high - span;
}
if (span < this.min_separation) {
high = low + this.min_separation;
}
this.low = Math.floor(low);
this.high = Math.ceil(high);
this.center = Math.round( this.low + (this.high - this.low) / 2 );
// 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) / 200 ) / Math.LN10 ) );
@@ -157,9 +144,9 @@ $.extend( View.prototype, {
// Overview
$("#overview-box").css( {
left: ( this.low / this.span ) * $("#overview-viewport").width(),
left: ( this.low / (this.max_high - this.max_low) ) * $("#overview-viewport").width(),
// Minimum width for usability
width: Math.max( 12, ( ( this.high - this.low ) / this.span ) * $("#overview-viewport").width() )
width: Math.max( 12, (this.high - this.low)/(this.max_high - this.max_low) * $("#overview-viewport").width() )
}).show();
$("#low").val( commatize(this.low) );
$("#high").val( commatize(this.high) );
@@ -174,26 +161,29 @@ $.extend( View.prototype, {
}
}
},
zoom_in: function ( point, container ) {
if (this.max_high === 0 || this.high - this.low < 30) {
zoom_in: function (point, container) {
if (this.max_high === 0 || this.high - this.low < this.min_separation) {
return;
}
if ( point ) {
this.center = point / container.width() * (this.high - this.low) + this.low;
var span = this.high - this.low,
cur_center = span / 2 + this.low,
new_half = (span / this.zoom_factor) / 2;
if (point) {
cur_center = point / container.width() * (this.high - this.low) + this.low;
}
this.zoom_level += 1;
this.low = Math.round(cur_center - new_half);
this.high = Math.round(cur_center + new_half);
this.redraw();
},
zoom_out: function () {
if (this.max_high === 0) {
return;
}
if (this.zoom_level <= 0) {
this.zoom_level = 0;
return;
}
this.zoom_level -= 1;
var span = this.high - this.low,
cur_center = span / 2 + this.low,
new_half = (span * this.zoom_factor) / 2;
this.low = Math.round(cur_center - new_half);
this.high = Math.round(cur_center + new_half);
this.redraw();
}
});
@@ -269,8 +259,6 @@ $.extend( TiledTrack.prototype, Track.prototype, {
high = this.view.high,
range = high - low,
resolution = this.view.resolution;
if (DEBUG) { $("#debug").text(resolution + " " + this.view.zoom_res); }
var parent_element = $("<div style='position: relative;'></div>"),
w_scale = this.content_div.width() / range,
@@ -283,7 +271,7 @@ $.extend( TiledTrack.prototype, Track.prototype, {
var tile_index = Math.floor( low / resolution / DENSITY );
while ( ( tile_index * DENSITY * resolution ) < high ) {
// Check in cache
var key = this.content_div.width() + '_' + this.view.zoom_level + '_' + tile_index;
var key = this.content_div.width() + '_' + w_scale + '_' + tile_index;
var cached = this.tile_cache.get(key);
if ( cached ) {
// console.log("cached tile " + tile_index);
-1
View File
@@ -111,7 +111,6 @@
.label-track {
/* font-weight: bold; */
/* font-size: 10px; */
}
.label-track .label {
border-left: solid #999 1px;
+1 -1
View File
@@ -7,7 +7,7 @@
</head>
<body>
<div class="document">
<div class="warningmessagelarge">
<div class="donemessagelarge">
<strong>Hello world! It's running...</strong>
<hr>
To customize this page edit <code>static/welcome.html</code>
+41 -9
View File
@@ -32,11 +32,11 @@ ${h.css( "history", "autocomplete_tagging" )}
<div class="unified-panel-header" unselectable="on">
<div class="unified-panel-header-inner">Trackster Visualization | ${config['title']}
<a id="save-button" class="panel-header-button right-float" href="javascript:void(0);">Save</a>
<a id="refresh-button" class="panel-header-button right-float" href="javascript:void(0);">Refresh</a>
<a id="refresh-button" class="panel-header-button right-float" href="javascript:void(0);" onclick="view.update_options();return false;">Refresh</a>
</div>
</div>
<div id="content">
<div id="top-labeltrack"></div>
<div id="top-labeltrack" style="position: relative;"></div>
<div id="viewport-container" style="overflow-x: hidden; overflow-y: auto;">
<div id="viewport"></div>
</div>
@@ -63,7 +63,6 @@ ${h.css( "history", "autocomplete_tagging" )}
<img src="${h.url_for('/static/images/fugue/magnifier-zoom-out.png')}" />
</a>
</form>
<div id="debug" style="float: right"></div>
</div>
</div>
</div>
@@ -146,6 +145,9 @@ ${h.js( 'galaxy.base', 'galaxy.panels', "json2", "jquery", "jquery.event.drag",
});
$("#content").bind("mousewheel", function( e, delta ) {
if (Math.abs(delta) < 0.5) {
return;
}
if (delta > 0) {
view.zoom_in(e.pageX, $("#viewport-container"));
} else {
@@ -166,19 +168,19 @@ ${h.js( 'galaxy.base', 'galaxy.panels', "json2", "jquery", "jquery.event.drag",
this.current_x = e.offsetX;
var delta_chrom = Math.round(delta / $(document).width() * view.span);
view.center += delta_chrom;
view.high += delta_chrom;
view.low += delta_chrom;
view.redraw();
});
// To adjust the size of the viewport to fit the fixed-height footer
var refresh = function( e ) {
$("#viewport-container").height( $(window).height() - 120 );
$("#viewport-container").height( $(window).height() - 100 );
$("#nav-container").width( $("#center").width() );
view.redraw();
};
$(window).bind( "resize", function(e) { refresh(e); } );
$("#right-border").bind( "click", function(e) { refresh(e); } );
$("#right-border").bind( "dragend", function(e) { refresh(e); } );
$("#right-border").bind( "click dragend", function(e) { refresh(e); } );
$(window).trigger( "resize" );
$("#viewport-container").bind( "dragstart", function( e ) {
@@ -195,8 +197,9 @@ ${h.js( 'galaxy.base', 'galaxy.panels', "json2", "jquery", "jquery.event.drag",
this.current_height = e.clientY;
this.current_x = e.offsetX;
var delta_chrom = Math.round(delta / $(document).width() * (view.high - view.low));
view.center -= delta_chrom;
var delta_chrom = Math.round(delta / $("#viewport-container").width() * (view.high - view.low));
view.high -= delta_chrom;
view.low -= delta_chrom;
view.redraw();
});
@@ -286,6 +289,35 @@ ${h.js( 'galaxy.base', 'galaxy.panels', "json2", "jquery", "jquery.event.drag",
view.add_label_track( new LabelTrack( $("#top-labeltrack") ) );
view.add_label_track( new LabelTrack( $("#nav-labeltrack") ) );
$("#top-labeltrack").bind( "dragstart", function(e) {
this.drag_origin_x = e.clientX;
this.drag_origin_pos = e.clientX / $("#viewport-container").width() * (view.high - view.low) + view.low;
this.drag_div = $("<div />").css( {
"height": $("#viewport-container").height(), "top": "0px", "position": "absolute",
"background-color": "#cfc", "border": "1px solid #6a6", "opacity": 0.5
} ).appendTo( $(this) );
}).bind( "drag", function(e) {
var min = Math.min(e.clientX, this.drag_origin_x),
max = Math.max(e.clientX, this.drag_origin_x),
span = (view.high - view.low),
width = $("#viewport-container").width();
$("#low").val(commatize(Math.round(min / width * span) + view.low));
$("#high").val(commatize(Math.round(max / width * span) + view.low));
this.drag_div.css( { "left": min + "px", "width": (max - min) + "px" } );
}).bind( "dragend", function(e) {
var min = Math.min(e.clientX, this.drag_origin_x),
max = Math.max(e.clientX, this.drag_origin_x),
span = (view.high - view.low),
width = $("#viewport-container").width(),
old_low = view.low;
view.low = Math.round(min / width * span) + old_low;
view.high = Math.round(max / width * span) + old_low;
this.drag_div.remove();
view.redraw();
});
$.ajax({
url: "${h.url_for( action='chroms' )}",
%if config.get('vis_id'):