2 new changesets in galaxy-central: http://bitbucket.org/galaxy/galaxy-central/changeset/c5acbf5f1c38/ changeset: c5acbf5f1c38 user: james_taylor date: 2011-08-12 00:36:51 summary: remove delayed draw and replace with synchronized drawing through requestAnimationFrame (or a fallback) affected #: 1 file (214 bytes) --- a/static/scripts/trackster.js Thu Aug 11 10:14:53 2011 -0400 +++ b/static/scripts/trackster.js Thu Aug 11 18:36:51 2011 -0400 @@ -23,6 +23,20 @@ // end class_module encapsulation }; +/** + * Find browser's reeuestAnimationFrame method or fallback on a setTimeout + */ +var requestAnimationFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function( callback, element ) { + window.setTimeout(callback, 1000 / 60); + }; + })(); + /** * Compute the type of overlap between two regions. They are assumed to be on the same chrom/contig. @@ -529,8 +543,8 @@ if (this.vis_id !== undefined) { this.hidden_input = $("<input/>").attr("type", "hidden").val(this.vis_id).appendTo(this.nav_controls); } - this.zo_link = $("<a id='zoom-out' />").click(function() { view.zoom_out(); view.redraw(); }).appendTo(this.nav_controls); - this.zi_link = $("<a id='zoom-in' />").click(function() { view.zoom_in(); view.redraw(); }).appendTo(this.nav_controls); + this.zo_link = $("<a id='zoom-out' />").click(function() { view.zoom_out(); view.request_redraw(); }).appendTo(this.nav_controls); + this.zi_link = $("<a id='zoom-in' />").click(function() { view.zoom_in(); view.request_redraw(); }).appendTo(this.nav_controls); // Get initial set of chroms. this.load_chroms({low: 0}, callback); @@ -634,7 +648,7 @@ view.low = Math.round(min / width * span) + old_low; view.high = Math.round(max / width * span) + old_low; $(d.proxy).remove(); - view.redraw(); + view.request_redraw(); }); this.add_label_track( new LabelTrack( this, this.top_labeltrack ) ); @@ -742,7 +756,7 @@ view.chrom_select.val(view.chrom); view.max_high = found.len-1; // -1 because we're using 0-based indexing. view.reset(); - view.redraw(true); + view.request_redraw(true); for (var track_id = 0, len = view.tracks.length; track_id < len; track_id++) { var track = view.tracks[track_id]; @@ -756,7 +770,7 @@ view.high = Math.min(high, view.max_high); } view.reset_overview(); - view.redraw(); + view.request_redraw(); } }, go_to: function(str) { @@ -797,7 +811,7 @@ view.high -= delta_chrom; view.low -= delta_chrom; } - view.redraw(); + view.request_redraw(); }, /** * Add a track to the view. @@ -834,10 +848,14 @@ this.low = this.max_low; this.high = this.max_high; this.viewport_container.find(".yaxislabel").remove(); - }, + }, + request_redraw: function( nodraw ) { + var view = this; + requestAnimationFrame( function() { view.redraw( nodraw ) } ); + }, redraw: function(nodraw) { - var span = this.high - this.low, - low = this.low, + + var low = this.low, high = this.high; if (low < this.max_low) { @@ -846,6 +864,7 @@ if (high > this.max_high) { high = this.max_high; } + var span = this.high - this.low; if (this.high !== 0 && span < this.min_separation) { high = low + this.min_separation; } @@ -893,7 +912,7 @@ } this.low = Math.round(cur_center - new_half); this.high = Math.round(cur_center + new_half); - this.redraw(); + this.request_redraw(); }, zoom_out: function () { if (this.max_high === 0) { @@ -904,12 +923,12 @@ 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(); + this.request_redraw(); }, resize_window: function() { this.viewport_container.height( this.container.height() - this.top_container.height() - this.bottom_container.height() ); this.nav_container.width( this.container.width() ); - this.redraw(); + this.request_redraw(); }, /** Show a track in the overview. */ set_overview: function(track) { @@ -2084,41 +2103,28 @@ this.max_height = 0; // Index of first tile that overlaps visible region var tile_index = Math.floor( low / resolution / DENSITY ); - // A list of tiles drawn/retrieved. + // If any tile could not be drawn yet, this will be set to false + var all_tiles_drawn = true; var drawn_tiles = []; var tile_count = 0; // Draw or fetch and show tiles. while ( ( tile_index * DENSITY * resolution ) < high ) { - // Check in cache - var key = this._gen_tile_cache_key(width, w_scale, tile_index); - var cached = this.tile_cache.get(key); - var tile_low = tile_index * DENSITY * this.view.resolution; - var tile_high = tile_low + DENSITY * this.view.resolution; - if (!force && cached) { - drawn_tiles.push(cached); - this.show_tile(cached, parent_element, w_scale); + tile = this.draw_helper( force, width, tile_index, resolution, parent_element, w_scale ) + if ( tile ) { + drawn_tiles.push( tile ); } else { - this.delayed_draw(force, key, tile_index, resolution, parent_element, w_scale, drawn_tiles); + all_tiles_drawn = false; } tile_index += 1; tile_count++; } - // // Use interval to check if tiles have been drawn. When all tiles are drawn, call post-draw actions. - // var track = this; - var intervalId = setInterval(function() { - if (drawn_tiles.length === tile_count) { - // All tiles have been drawn. - clearInterval(intervalId); - track.postdraw_actions(drawn_tiles, width, w_scale, clear_after); - } - }, 50); - - // + if ( all_tiles_drawn ) { + track.postdraw_actions(drawn_tiles, width, w_scale, clear_after); + } // Draw child tracks. - // for (var i = 0; i < this.child_tracks.length; i++) { this.child_tracks[i].draw(force, clear_after); } @@ -2152,55 +2158,65 @@ } }, /** - * Do actual tile drawing. + * Handle a single tile, either from cache or by setting up a deferred + * operation and then requesting another redraw */ - delayed_draw: function(force, key, tile_index, resolution, parent_element, w_scale, drawn_tiles, more_tile_data) { + draw_helper: function(force, width, tile_index, resolution, parent_element, w_scale, drawn_tiles, more_tile_data) { + var track = this, + key = this._gen_tile_cache_key(width, w_scale, tile_index), tile_low = tile_index * DENSITY * resolution, tile_high = tile_low + DENSITY * resolution; + + // Check tile cache, if found show existing tile in correct position + var tile = (force ? undefined : track.tile_cache.get(key)); + if (tile) { + track.show_tile(tile, parent_element, w_scale); + return tile; + } + + // Helper to determine if object is jQuery deferred + var is_deferred = function ( d ) { + return ( 'isResolved' in d ); + } - // Helper method. - var draw_and_show_tile = function(id, result, resolution, tile_index, parent_element, w_scale, seq_data) { - // DEBUG: this is still called too many times when moving slowly, - // console.log( "draw_and_show_tile", resolution, tile_index, w_scale ); - var tile = track.draw_tile(result, resolution, tile_index, w_scale, seq_data); + // Flag to track whether we can draw everything now + var can_draw_now = true + + // Get the track data, maybe a deferred + var tile_data = track.data_manager.get_data( tile_low, tile_high, track.mode, resolution, track.data_url_extra_params ); + if ( is_deferred( tile_data ) ) { + can_draw_now = false; + } + + // Get seq data if needed, maybe a deferred + var seq_data; + if ( view.reference_track && w_scale > view.canvas_manager.char_width_px ) { + seq_data = view.reference_track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, view.reference_track.data_url_extra_params) + if ( is_deferred( seq_data ) ) { + can_draw_now = false; + } + } + + // If we can draw now, do so + if ( can_draw_now ) { + extend( tile_data, more_tile_data ); + var tile = track.draw_tile(tile_data, resolution, tile_index, w_scale, seq_data); track.tile_cache.set(key, tile); // Don't show if no tile - if (tile === undefined) { - return; + if (tile !== undefined) { + track.show_tile(tile, parent_element, w_scale); } - track.show_tile(tile, parent_element, w_scale); - drawn_tiles.push(tile); - }; - // Put a 50ms delay on drawing so that if the user scrolls fast, we don't load extra data - var id = setTimeout(function() { - if (tile_low <= track.view.high && tile_high >= track.view.low) { - // Show/draw tile: check cache for tile; if tile not in cache, draw it. - var tile = (force ? undefined : track.tile_cache.get(key)); - if (tile) { - track.show_tile(tile, parent_element, w_scale); - drawn_tiles.push(tile); - } - else { - // - // Really draw tile: get data, seq data if available, and draw tile. - // - $.when(track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, track.data_url_extra_params)).then(function(tile_data) { - extend(tile_data, more_tile_data); - // If sequence data needed, get that and draw. Otherwise draw. - if (view.reference_track && w_scale > view.canvas_manager.char_width_px) { - $.when(view.reference_track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, - view.reference_track.data_url_extra_params)).then(function(seq_data) { - draw_and_show_tile(id, tile_data, resolution, tile_index, parent_element, w_scale, seq_data); - }); - } - else { - draw_and_show_tile(id, tile_data, resolution, tile_index, parent_element, w_scale); - } - }); - } - } - }, 50); + return tile + } + + // Can't draw now, so trigger another redraw when the data is ready + $.when( tile_data, seq_data ).then( function() { + view.request_redraw(); + }); + + // Indicate to caller that this tile could not be drawn + return null; }, /** * Show track tile and perform associated actions. @@ -2585,9 +2601,7 @@ } } - // // If mode is Histogram and tiles do not share max, redraw tiles as necessary using new max. - // if (track.mode == "Histogram") { // Get global max. var global_max = -1; @@ -2599,11 +2613,10 @@ } for (var i = 0; i < tiles.length; i++) { - if (tiles[i].max_val !== global_max) { - var tile = tiles[i]; + var tile = tiles[i]; + if (tile.max_val !== global_max) { tile.canvas.remove(); - track.delayed_draw(true, track._gen_tile_cache_key(width, w_scale, tile.index), tile.index, - tile.resolution, tile.canvas.parent(), w_scale, [], { max: global_max }); + track.draw_helper(true, width, tile.index, tile.resolution, tile.canvas.parent(), w_scale, [], { max: global_max }); } } } http://bitbucket.org/galaxy/galaxy-central/changeset/06f0bca6de24/ changeset: 06f0bca6de24 user: james_taylor date: 2011-08-12 00:37:14 summary: Automated merge with https://bitbucket.org/galaxy/galaxy-central affected #: 1 file (214 bytes) --- a/static/scripts/trackster.js Thu Aug 11 14:33:15 2011 -0400 +++ b/static/scripts/trackster.js Thu Aug 11 18:37:14 2011 -0400 @@ -23,6 +23,20 @@ // end class_module encapsulation }; +/** + * Find browser's reeuestAnimationFrame method or fallback on a setTimeout + */ +var requestAnimationFrame = (function(){ + return window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function( callback, element ) { + window.setTimeout(callback, 1000 / 60); + }; + })(); + /** * Compute the type of overlap between two regions. They are assumed to be on the same chrom/contig. @@ -529,8 +543,8 @@ if (this.vis_id !== undefined) { this.hidden_input = $("<input/>").attr("type", "hidden").val(this.vis_id).appendTo(this.nav_controls); } - this.zo_link = $("<a id='zoom-out' />").click(function() { view.zoom_out(); view.redraw(); }).appendTo(this.nav_controls); - this.zi_link = $("<a id='zoom-in' />").click(function() { view.zoom_in(); view.redraw(); }).appendTo(this.nav_controls); + this.zo_link = $("<a id='zoom-out' />").click(function() { view.zoom_out(); view.request_redraw(); }).appendTo(this.nav_controls); + this.zi_link = $("<a id='zoom-in' />").click(function() { view.zoom_in(); view.request_redraw(); }).appendTo(this.nav_controls); // Get initial set of chroms. this.load_chroms({low: 0}, callback); @@ -634,7 +648,7 @@ view.low = Math.round(min / width * span) + old_low; view.high = Math.round(max / width * span) + old_low; $(d.proxy).remove(); - view.redraw(); + view.request_redraw(); }); this.add_label_track( new LabelTrack( this, this.top_labeltrack ) ); @@ -742,7 +756,7 @@ view.chrom_select.val(view.chrom); view.max_high = found.len-1; // -1 because we're using 0-based indexing. view.reset(); - view.redraw(true); + view.request_redraw(true); for (var track_id = 0, len = view.tracks.length; track_id < len; track_id++) { var track = view.tracks[track_id]; @@ -756,7 +770,7 @@ view.high = Math.min(high, view.max_high); } view.reset_overview(); - view.redraw(); + view.request_redraw(); } }, go_to: function(str) { @@ -797,7 +811,7 @@ view.high -= delta_chrom; view.low -= delta_chrom; } - view.redraw(); + view.request_redraw(); }, /** * Add a track to the view. @@ -834,10 +848,14 @@ this.low = this.max_low; this.high = this.max_high; this.viewport_container.find(".yaxislabel").remove(); - }, + }, + request_redraw: function( nodraw ) { + var view = this; + requestAnimationFrame( function() { view.redraw( nodraw ) } ); + }, redraw: function(nodraw) { - var span = this.high - this.low, - low = this.low, + + var low = this.low, high = this.high; if (low < this.max_low) { @@ -846,6 +864,7 @@ if (high > this.max_high) { high = this.max_high; } + var span = this.high - this.low; if (this.high !== 0 && span < this.min_separation) { high = low + this.min_separation; } @@ -893,7 +912,7 @@ } this.low = Math.round(cur_center - new_half); this.high = Math.round(cur_center + new_half); - this.redraw(); + this.request_redraw(); }, zoom_out: function () { if (this.max_high === 0) { @@ -904,12 +923,12 @@ 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(); + this.request_redraw(); }, resize_window: function() { this.viewport_container.height( this.container.height() - this.top_container.height() - this.bottom_container.height() ); this.nav_container.width( this.container.width() ); - this.redraw(); + this.request_redraw(); }, /** Show a track in the overview. */ set_overview: function(track) { @@ -2084,41 +2103,28 @@ this.max_height = 0; // Index of first tile that overlaps visible region var tile_index = Math.floor( low / resolution / DENSITY ); - // A list of tiles drawn/retrieved. + // If any tile could not be drawn yet, this will be set to false + var all_tiles_drawn = true; var drawn_tiles = []; var tile_count = 0; // Draw or fetch and show tiles. while ( ( tile_index * DENSITY * resolution ) < high ) { - // Check in cache - var key = this._gen_tile_cache_key(width, w_scale, tile_index); - var cached = this.tile_cache.get(key); - var tile_low = tile_index * DENSITY * this.view.resolution; - var tile_high = tile_low + DENSITY * this.view.resolution; - if (!force && cached) { - drawn_tiles.push(cached); - this.show_tile(cached, parent_element, w_scale); + tile = this.draw_helper( force, width, tile_index, resolution, parent_element, w_scale ) + if ( tile ) { + drawn_tiles.push( tile ); } else { - this.delayed_draw(force, key, tile_index, resolution, parent_element, w_scale, drawn_tiles); + all_tiles_drawn = false; } tile_index += 1; tile_count++; } - // // Use interval to check if tiles have been drawn. When all tiles are drawn, call post-draw actions. - // var track = this; - var intervalId = setInterval(function() { - if (drawn_tiles.length === tile_count) { - // All tiles have been drawn. - clearInterval(intervalId); - track.postdraw_actions(drawn_tiles, width, w_scale, clear_after); - } - }, 50); - - // + if ( all_tiles_drawn ) { + track.postdraw_actions(drawn_tiles, width, w_scale, clear_after); + } // Draw child tracks. - // for (var i = 0; i < this.child_tracks.length; i++) { this.child_tracks[i].draw(force, clear_after); } @@ -2152,55 +2158,65 @@ } }, /** - * Do actual tile drawing. + * Handle a single tile, either from cache or by setting up a deferred + * operation and then requesting another redraw */ - delayed_draw: function(force, key, tile_index, resolution, parent_element, w_scale, drawn_tiles, more_tile_data) { + draw_helper: function(force, width, tile_index, resolution, parent_element, w_scale, drawn_tiles, more_tile_data) { + var track = this, + key = this._gen_tile_cache_key(width, w_scale, tile_index), tile_low = tile_index * DENSITY * resolution, tile_high = tile_low + DENSITY * resolution; + + // Check tile cache, if found show existing tile in correct position + var tile = (force ? undefined : track.tile_cache.get(key)); + if (tile) { + track.show_tile(tile, parent_element, w_scale); + return tile; + } + + // Helper to determine if object is jQuery deferred + var is_deferred = function ( d ) { + return ( 'isResolved' in d ); + } - // Helper method. - var draw_and_show_tile = function(id, result, resolution, tile_index, parent_element, w_scale, seq_data) { - // DEBUG: this is still called too many times when moving slowly, - // console.log( "draw_and_show_tile", resolution, tile_index, w_scale ); - var tile = track.draw_tile(result, resolution, tile_index, w_scale, seq_data); + // Flag to track whether we can draw everything now + var can_draw_now = true + + // Get the track data, maybe a deferred + var tile_data = track.data_manager.get_data( tile_low, tile_high, track.mode, resolution, track.data_url_extra_params ); + if ( is_deferred( tile_data ) ) { + can_draw_now = false; + } + + // Get seq data if needed, maybe a deferred + var seq_data; + if ( view.reference_track && w_scale > view.canvas_manager.char_width_px ) { + seq_data = view.reference_track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, view.reference_track.data_url_extra_params) + if ( is_deferred( seq_data ) ) { + can_draw_now = false; + } + } + + // If we can draw now, do so + if ( can_draw_now ) { + extend( tile_data, more_tile_data ); + var tile = track.draw_tile(tile_data, resolution, tile_index, w_scale, seq_data); track.tile_cache.set(key, tile); // Don't show if no tile - if (tile === undefined) { - return; + if (tile !== undefined) { + track.show_tile(tile, parent_element, w_scale); } - track.show_tile(tile, parent_element, w_scale); - drawn_tiles.push(tile); - }; - // Put a 50ms delay on drawing so that if the user scrolls fast, we don't load extra data - var id = setTimeout(function() { - if (tile_low <= track.view.high && tile_high >= track.view.low) { - // Show/draw tile: check cache for tile; if tile not in cache, draw it. - var tile = (force ? undefined : track.tile_cache.get(key)); - if (tile) { - track.show_tile(tile, parent_element, w_scale); - drawn_tiles.push(tile); - } - else { - // - // Really draw tile: get data, seq data if available, and draw tile. - // - $.when(track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, track.data_url_extra_params)).then(function(tile_data) { - extend(tile_data, more_tile_data); - // If sequence data needed, get that and draw. Otherwise draw. - if (view.reference_track && w_scale > view.canvas_manager.char_width_px) { - $.when(view.reference_track.data_manager.get_data(tile_low, tile_high, track.mode, resolution, - view.reference_track.data_url_extra_params)).then(function(seq_data) { - draw_and_show_tile(id, tile_data, resolution, tile_index, parent_element, w_scale, seq_data); - }); - } - else { - draw_and_show_tile(id, tile_data, resolution, tile_index, parent_element, w_scale); - } - }); - } - } - }, 50); + return tile + } + + // Can't draw now, so trigger another redraw when the data is ready + $.when( tile_data, seq_data ).then( function() { + view.request_redraw(); + }); + + // Indicate to caller that this tile could not be drawn + return null; }, /** * Show track tile and perform associated actions. @@ -2585,9 +2601,7 @@ } } - // // If mode is Histogram and tiles do not share max, redraw tiles as necessary using new max. - // if (track.mode == "Histogram") { // Get global max. var global_max = -1; @@ -2599,11 +2613,10 @@ } for (var i = 0; i < tiles.length; i++) { - if (tiles[i].max_val !== global_max) { - var tile = tiles[i]; + var tile = tiles[i]; + if (tile.max_val !== global_max) { tile.canvas.remove(); - track.delayed_draw(true, track._gen_tile_cache_key(width, w_scale, tile.index), tile.index, - tile.resolution, tile.canvas.parent(), w_scale, [], { max: global_max }); + track.draw_helper(true, width, tile.index, tile.resolution, tile.canvas.parent(), w_scale, [], { max: global_max }); } } } Repository URL: https://bitbucket.org/galaxy/galaxy-central/ -- This is a commit notification from bitbucket.org. You are receiving this because you have the service enabled, addressing the recipient of this email.