Merge pull request #33 from openseadragon/prerender

Prerender bundles a number of performance optimizations.
This commit is contained in:
Chris Thatcher 2013-03-14 06:21:52 -07:00
commit 695dbae3f6
7 changed files with 106 additions and 34 deletions

View File

@ -148,7 +148,7 @@ module.exports = function(grunt) {
grunt.registerTask("copy:release", function() { grunt.registerTask("copy:release", function() {
grunt.file.recurse("build", function(abspath, rootdir, subdir, filename) { grunt.file.recurse("build", function(abspath, rootdir, subdir, filename) {
var dest = "../site-build/" var dest = "../site-build/"
+ (subdir ? subdir + "/" : "") + (subdir ? subdir + "/" : '/')
+ filename; + filename;
grunt.file.copy(abspath, dest); grunt.file.copy(abspath, dest);

View File

@ -515,7 +515,12 @@ function updateViewport( drawer ) {
).x; ).x;
zeroRatioT = drawer.viewport.deltaPixelsFromPoints( zeroRatioT = drawer.viewport.deltaPixelsFromPoints(
drawer.source.getPixelRatio( 0 ), drawer.source.getPixelRatio(
Math.max(
drawer.source.getClosestLevel( drawer.viewport.containerSize ) - 1,
0
)
),
false false
).x; ).x;
@ -850,7 +855,7 @@ function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
} }
deltaTime = currentTime - tile.blendStart; deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / ( blendTimeMillis || 1 ) ); opacity = blendTimeMillis ? Math.min( 1, deltaTime / ( blendTimeMillis ) ) : 1;
if ( drawer.alwaysBlend ) { if ( drawer.alwaysBlend ) {
opacity *= levelOpacity; opacity *= levelOpacity;
@ -1085,9 +1090,6 @@ function drawTiles( drawer, lastDrawn ){
showNavigator: false, showNavigator: false,
showSequenceControl: false, showSequenceControl: false,
showNavigationControl: false, showNavigationControl: false,
//visibilityRatio: 1,
//debugMode: true,
//debugGridColor: 'red',
tileSources: [ tileSources: [
tileSource tileSource
] ]
@ -1153,6 +1155,7 @@ function drawTiles( drawer, lastDrawn ){
function drawDebugInfo( drawer, tile, count, i ){ function drawDebugInfo( drawer, tile, count, i ){
if ( USE_CANVAS ) { if ( USE_CANVAS ) {
drawer.context.save();
drawer.context.lineWidth = 2; drawer.context.lineWidth = 2;
drawer.context.font = 'small-caps bold 13px ariel'; drawer.context.font = 'small-caps bold 13px ariel';
drawer.context.strokeStyle = drawer.debugGridColor; drawer.context.strokeStyle = drawer.debugGridColor;
@ -1205,6 +1208,7 @@ function drawDebugInfo( drawer, tile, count, i ){
tile.position.x + 10, tile.position.x + 10,
tile.position.y + 70 tile.position.y + 70
); );
drawer.context.restore();
} }
} }

View File

@ -37,7 +37,10 @@ $.Navigator = function( options ){
showNavigator: false, showNavigator: false,
mouseNavEnabled: false, mouseNavEnabled: false,
showNavigationControl: false, showNavigationControl: false,
showSequenceControl: false showSequenceControl: false,
immediateRender: true,
blendTime: 0,
animationTime: 0
}); });
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
@ -228,6 +231,20 @@ $.extend( $.Navigator.prototype, $.EventHandler.prototype, $.Viewer.prototype, {
}( this.displayRegion.style )); }( this.displayRegion.style ));
} }
},
open: function( source ){
var containerSize = this.viewer.viewport.containerSize.times( this.sizeRatio );
if( source.tileSize > containerSize.x ||
source.tileSize > containerSize.y ){
this.minPixelRatio = Math.min(
containerSize.x,
containerSize.y
) / source.tileSize;
} else {
this.minPixelRatio = thie.viewer.minPixelRatio;
}
return $.Viewer.prototype.open.apply( this, [ source ] );
} }
}); });

View File

@ -474,26 +474,26 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
constrainDuringPan: false, constrainDuringPan: false,
wrapHorizontal: false, wrapHorizontal: false,
wrapVertical: false, wrapVertical: false,
visibilityRatio: 0.5, visibilityRatio: 0.5, //-> how much of the viewer can be negative space
minPixelRatio: 0.5, minPixelRatio: 1, //->closer to 0 draws tiles meant for a higher zoom at this zoom
minZoomImageRatio: 0.8,
maxZoomPixelRatio: 2,
defaultZoomLevel: 0, defaultZoomLevel: 0,
minZoomLevel: null, minZoomLevel: null,
maxZoomLevel: null, maxZoomLevel: null,
//UI RESPONSIVENESS AND FEEL //UI RESPONSIVENESS AND FEEL
springStiffness: 5.0, springStiffness: 7.0,
clickTimeThreshold: 300, clickTimeThreshold: 300,
clickDistThreshold: 5, clickDistThreshold: 5,
zoomPerClick: 2.0, zoomPerClick: 2,
zoomPerScroll: 1.2, zoomPerScroll: 1.2,
zoomPerSecond: 2.0, zoomPerSecond: 1.0,
animationTime: 1.5, animationTime: 1.2,
blendTime: 1.5, blendTime: 0,
alwaysBlend: false, alwaysBlend: false,
autoHideControls: true, autoHideControls: true,
immediateRender: false, immediateRender: false,
minZoomImageRatio: 0.9, //-> closer to 0 allows zoom out to infinity
maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels
//DEFAULT CONTROL SETTINGS //DEFAULT CONTROL SETTINGS
showSequenceControl: true, //SEQUENCE showSequenceControl: true, //SEQUENCE
@ -532,7 +532,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
//PERFORMANCE SETTINGS //PERFORMANCE SETTINGS
imageLoaderLimit: 0, imageLoaderLimit: 0,
maxImageCacheCount: 200, maxImageCacheCount: 200,
timeout: 5000, timeout: 30000,
//INTERFACE RESOURCE SETTINGS //INTERFACE RESOURCE SETTINGS
prefixUrl: "/images/", prefixUrl: "/images/",

View File

@ -377,11 +377,13 @@ function loadPanels(strip, viewerSize, scroll){
tileSources: [ strip.viewer.tileSources[ i ] ], tileSources: [ strip.viewer.tileSources[ i ] ],
element: element, element: element,
navigatorSizeRatio: strip.sizeRatio, navigatorSizeRatio: strip.sizeRatio,
minPixelRatio: strip.minPixelRatio,
showNavigator: false, showNavigator: false,
mouseNavEnabled: false, mouseNavEnabled: false,
showNavigationControl: false, showNavigationControl: false,
showSequenceControl: false showSequenceControl: false,
immediateRender: true,
blendTime: 0,
animationTime: 0
} ); } );
miniViewer.displayRegion = $.makeNeutralElement( "textarea" ); miniViewer.displayRegion = $.makeNeutralElement( "textarea" );

View File

@ -1,5 +1,5 @@
(function( $ ){ (function( $ ){
var TILE_CACHE = {};
/** /**
* @class * @class
* @param {Number} level The zoom level this tile belongs to. * @param {Number} level The zoom level this tile belongs to.
@ -140,9 +140,11 @@ $.Tile.prototype = {
drawCanvas: function( context ) { drawCanvas: function( context ) {
var position = this.position, var position = this.position,
size = this.size; size = this.size,
rendered,
canvas;
if ( !this.loaded || !this.image ) { if ( !this.loaded || !( this.image || TILE_CACHE[ this.url ] ) ){
$.console.warn( $.console.warn(
"Attempting to draw tile %s when it's not yet loaded.", "Attempting to draw tile %s when it's not yet loaded.",
this.toString() this.toString()
@ -151,13 +153,13 @@ $.Tile.prototype = {
} }
context.globalAlpha = this.opacity; context.globalAlpha = this.opacity;
context.save(); //context.save();
//if we are supposed to b rendering fully opaque rectangle, //if we are supposed to be rendering fully opaque rectangle,
//ie its done fading or fading is turned off, and if we are drawing //ie its done fading or fading is turned off, and if we are drawing
//an image with an alpha channel, then the only way //an image with an alpha channel, then the only way
//to avoid seeing the tile underneath is to clear the rectangle //to avoid seeing the tile underneath is to clear the rectangle
if( context.globalAlpha == 1 && this.image.src.match('.png') ){ if( context.globalAlpha == 1 && this.url.match('.png') ){
//clearing only the inside of the rectangle occupied //clearing only the inside of the rectangle occupied
//by the png prevents edge flikering //by the png prevents edge flikering
context.clearRect( context.clearRect(
@ -169,9 +171,35 @@ $.Tile.prototype = {
} }
context.drawImage( this.image, position.x, position.y, size.x, size.y ); if( !TILE_CACHE[ this.url ] ){
canvas = document.createElement( 'canvas' );
canvas.width = this.image.width;
canvas.height = this.image.height;
rendered = canvas.getContext('2d');
rendered.drawImage( this.image, 0, 0 );
TILE_CACHE[ this.url ] = rendered;
//since we are caching the prerendered image on a canvas
//allow the image to not be held in memory
this.image = null;
}
context.restore(); rendered = TILE_CACHE[ this.url ];
//rendered.save();
context.drawImage(
rendered.canvas,
0,
0,
rendered.canvas.width,
rendered.canvas.height,
position.x,
position.y,
size.x,
size.y
);
//rendered.restore();
//context.restore();
}, },
/** /**
@ -182,6 +210,9 @@ $.Tile.prototype = {
if ( this.element && this.element.parentNode ) { if ( this.element && this.element.parentNode ) {
this.element.parentNode.removeChild( this.element ); this.element.parentNode.removeChild( this.element );
} }
if ( TILE_CACHE[ this.url ]){
delete TILE_CACHE[ this.url ];
}
this.element = null; this.element = null;
this.image = null; this.image = null;

View File

@ -180,6 +180,24 @@ $.TileSource.prototype = {
return new $.Point(rx, ry); return new $.Point(rx, ry);
}, },
/**
* @function
* @param {Number} level
*/
getClosestLevel: function( rect ) {
var i,
tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.tileSize ),
tiles;
for( i = this.minLevel; i < this.maxLevel; i++ ){
tiles = this.getNumTiles( i );
if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){
break;
}
}
return Math.max( 0, i - 1 );
},
/** /**
* @function * @function
* @param {Number} level * @param {Number} level