Merge pull request #365 from avandecreme/optimization

Overlays performance optimization. See #359
This commit is contained in:
iangilman 2014-03-24 09:15:08 -07:00
commit 693b9e2e89
3 changed files with 255 additions and 43 deletions

View File

@ -78,7 +78,11 @@
* @param {OpenSeadragon.OverlayPlacement} [options.placement=OpenSeadragon.OverlayPlacement.TOP_LEFT] * @param {OpenSeadragon.OverlayPlacement} [options.placement=OpenSeadragon.OverlayPlacement.TOP_LEFT]
* Relative position to the viewport. * Relative position to the viewport.
* Only used if location is a {@link OpenSeadragon.Point}. * Only used if location is a {@link OpenSeadragon.Point}.
* @param {OpenSeadragon.Overlay.OnDrawCallback} options.onDraw * @param {OpenSeadragon.Overlay.OnDrawCallback} [options.onDraw]
* @param {Boolean} [options.checkResize=true] Set to false to avoid to
* check the size of the overlay everytime it is drawn when using a
* {@link OpenSeadragon.Point} as options.location. It will improve
* performances but will cause a misalignment if the overlay size changes.
*/ */
$.Overlay = function( element, location, placement ) { $.Overlay = function( element, location, placement ) {
@ -125,6 +129,8 @@
options.placement : options.placement :
$.OverlayPlacement.TOP_LEFT; $.OverlayPlacement.TOP_LEFT;
this.onDraw = options.onDraw; this.onDraw = options.onDraw;
this.checkResize = options.checkResize === undefined ?
true : options.checkResize;
}; };
$.Overlay.prototype = /** @lends OpenSeadragon.Overlay.prototype */{ $.Overlay.prototype = /** @lends OpenSeadragon.Overlay.prototype */{
@ -212,19 +218,12 @@
var element = this.element, var element = this.element,
style = this.style, style = this.style,
scales = this.scales, scales = this.scales,
drawerCenter = new $.Point(
viewport.viewer.drawer.canvas.width / 2,
viewport.viewer.drawer.canvas.height / 2
),
degrees = viewport.degrees, degrees = viewport.degrees,
position = viewport.pixelFromPoint( position = viewport.pixelFromPoint(
this.bounds.getTopLeft(), this.bounds.getTopLeft(),
true true
), ),
size = viewport.deltaPixelsFromPoints( size,
this.bounds.getSize(),
true
),
overlayCenter; overlayCenter;
if ( element.parentNode != container ) { if ( element.parentNode != container ) {
@ -232,10 +231,18 @@
element.prevElementParent = element.parentNode; element.prevElementParent = element.parentNode;
element.prevNextSibling = element.nextSibling; element.prevNextSibling = element.nextSibling;
container.appendChild( element ); container.appendChild( element );
this.size = $.getElementSize( element );
} }
if ( !scales ) { if ( scales ) {
this.size = $.getElementSize( element ); size = viewport.deltaPixelsFromPoints(
this.bounds.getSize(),
true
);
} else if ( this.checkResize ) {
size = $.getElementSize( element );
} else {
size = this.size;
} }
this.position = position; this.position = position;
@ -254,6 +261,10 @@
if( degrees !== 0 && this.scales ) { if( degrees !== 0 && this.scales ) {
overlayCenter = new $.Point( size.x / 2, size.y / 2 ); overlayCenter = new $.Point( size.x / 2, size.y / 2 );
var drawerCenter = new $.Point(
viewport.viewer.drawer.canvas.width / 2,
viewport.viewer.drawer.canvas.height / 2
);
position = position.plus( overlayCenter ).rotate( position = position.plus( overlayCenter ).rotate(
degrees, degrees,
drawerCenter drawerCenter
@ -263,7 +274,7 @@
size = new $.Point( Math.abs( size.x ), Math.abs( size.y ) ); size = new $.Point( Math.abs( size.x ), Math.abs( size.y ) );
} }
// call the onDraw callback if there is one to allow, this allows someone to overwrite // call the onDraw callback if it exists to allow one to overwrite
// the drawing/positioning/sizing of the overlay // the drawing/positioning/sizing of the overlay
if ( this.onDraw ) { if ( this.onDraw ) {
this.onDraw( position, size, element ); this.onDraw( position, size, element );

View File

@ -2045,22 +2045,31 @@ function getOverlayObject( viewer, overlay ) {
var location = overlay.location; var location = overlay.location;
if ( !location ) { if ( !location ) {
var rect = ( overlay.height && overlay.width ) ? new $.Rect( if ( overlay.width && overlay.height ) {
overlay.x || overlay.px, location = overlay.px !== undefined ?
overlay.y || overlay.py, viewer.viewport.imageToViewportRectangle( new $.Rect(
overlay.px,
overlay.py,
overlay.width,
overlay.height
) ) :
new $.Rect(
overlay.x,
overlay.y,
overlay.width, overlay.width,
overlay.height overlay.height
) : new $.Point(
overlay.x || overlay.px,
overlay.y || overlay.py
); );
if( overlay.px !== undefined ) { } else {
//if they specified 'px' so it's in pixel coordinates so location = overlay.px !== undefined ?
//we need to translate to viewport coordinates viewer.viewport.imageToViewportCoordinates( new $.Point(
rect = viewer.viewport.imageToViewportRectangle( rect ); overlay.px,
overlay.py
) ) :
new $.Point(
overlay.x,
overlay.y
);
} }
location = overlay.placement ? viewer.viewport.pointFromPixel( rect ) :
rect;
} }
var placement = overlay.placement; var placement = overlay.placement;
@ -2072,7 +2081,8 @@ function getOverlayObject( viewer, overlay ) {
element: element, element: element,
location: location, location: location,
placement: placement, placement: placement,
onDraw: overlay.onDraw onDraw: overlay.onDraw,
checkResize: overlay.checkResize
}); });
} }

View File

@ -221,7 +221,7 @@
viewer = OpenSeadragon( { viewer = OpenSeadragon( {
id: 'example-overlays', id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/', prefixUrl: '/build/openseadragon/images/',
tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ], tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests springStiffness: 100, // Faster animation = faster tests
overlays: [ { overlays: [ {
px: 13, px: 13,
@ -232,7 +232,8 @@
}, { }, {
px: 400, px: 400,
py: 500, py: 500,
id: "fixed-overlay" id: "fixed-overlay",
placement: "TOP_LEFT"
} ] } ]
} ); } );
@ -284,7 +285,7 @@
viewer = OpenSeadragon( { viewer = OpenSeadragon( {
id: 'example-overlays', id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/', prefixUrl: '/build/openseadragon/images/',
tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ], tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests springStiffness: 100, // Faster animation = faster tests
overlays: [ { overlays: [ {
x: 0.2, x: 0.2,
@ -295,7 +296,8 @@
}, { }, {
x: 0.5, x: 0.5,
y: 0.6, y: 0.6,
id: "fixed-overlay" id: "fixed-overlay",
placement: "TOP_LEFT"
} ] } ]
} ); } );
@ -341,4 +343,193 @@
} ); } );
} ); } );
asyncTest( 'Overlays placement', function() {
var scalableOverlayLocation = new OpenSeadragon.Rect( 0.2, 0.1, 0.5, 0.1 );
var fixedOverlayLocation = new OpenSeadragon.Point( 0.5, 0.6 );
viewer = OpenSeadragon( {
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
overlays: [ {
x: scalableOverlayLocation.x,
y: scalableOverlayLocation.y,
width: scalableOverlayLocation.width,
height: scalableOverlayLocation.height,
id: "overlay",
placement: "TOP_LEFT"
}, {
x: fixedOverlayLocation.x,
y: fixedOverlayLocation.y,
id: "fixed-overlay",
placement: "TOP_LEFT"
} ]
} );
// Scalable overlays are always TOP_LEFT
function checkScalableOverlayPosition( contextMessage ) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point( 0.2, 0.1 ) ).apply( Math.floor );
var actPosition = $( "#overlay" ).position();
equal( actPosition.left, expPosition.x, "X position mismatch " + contextMessage );
equal( actPosition.top, expPosition.y, "Y position mismatch " + contextMessage );
}
function checkFixedOverlayPosition( expectedOffset, contextMessage ) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point( 0.5, 0.6 ) )
.apply( Math.floor )
.plus( expectedOffset );
var actPosition = $( "#fixed-overlay" ).position();
equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
}
waitForViewer( function() {
checkScalableOverlayPosition( "with TOP_LEFT placement." );
checkFixedOverlayPosition( new OpenSeadragon.Point( 0, 0 ),
"with TOP_LEFT placement." );
viewer.updateOverlay( "overlay", scalableOverlayLocation,
OpenSeadragon.OverlayPlacement.CENTER );
viewer.updateOverlay( "fixed-overlay", fixedOverlayLocation,
OpenSeadragon.OverlayPlacement.CENTER );
setTimeout( function() {
checkScalableOverlayPosition( "with CENTER placement." );
checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
"with CENTER placement." );
viewer.updateOverlay( "overlay", scalableOverlayLocation,
OpenSeadragon.OverlayPlacement.BOTTOM_RIGHT );
viewer.updateOverlay( "fixed-overlay", fixedOverlayLocation,
OpenSeadragon.OverlayPlacement.BOTTOM_RIGHT );
setTimeout( function() {
checkScalableOverlayPosition( "with BOTTOM_RIGHT placement." );
checkFixedOverlayPosition( new OpenSeadragon.Point( -70, -60 ),
"with BOTTOM_RIGHT placement." );
start();
}, 100 );
}, 100 );
} );
} );
asyncTest( 'Overlays placement and resizing check', function() {
var fixedOverlayLocation = new OpenSeadragon.Point( 0.5, 0.6 );
viewer = OpenSeadragon( {
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
overlays: [ {
x: fixedOverlayLocation.x,
y: fixedOverlayLocation.y,
id: "fixed-overlay",
placement: "CENTER",
checkResize: true
} ]
} );
function checkFixedOverlayPosition( expectedOffset, contextMessage ) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point( 0.5, 0.6 ) )
.apply( Math.floor )
.plus( expectedOffset );
var actPosition = $( "#fixed-overlay" ).position();
equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
}
waitForViewer( function() {
checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
"with overlay of size 70,60." );
$( "#fixed-overlay" ).width( 50 );
$( "#fixed-overlay" ).height( 40 );
// The resizing of the overlays is not detected by the viewer's loop.
viewer.forceRedraw();
setTimeout( function() {
checkFixedOverlayPosition( new OpenSeadragon.Point( -25, -20 ),
"with overlay of size 50,40." );
// Restore original size
$( "#fixed-overlay" ).width( 70 );
$( "#fixed-overlay" ).height( 60 );
start();
}, 100 );
} );
} );
asyncTest( 'Overlays placement and no resizing check', function() {
var fixedOverlayLocation = new OpenSeadragon.Point( 0.5, 0.6 );
viewer = OpenSeadragon( {
id: 'example-overlays',
prefixUrl: '/build/openseadragon/images/',
tileSources: '/test/data/testpattern.dzi',
springStiffness: 100, // Faster animation = faster tests
overlays: [ {
x: fixedOverlayLocation.x,
y: fixedOverlayLocation.y,
id: "fixed-overlay",
placement: "CENTER",
checkResize: false
} ]
} );
function checkFixedOverlayPosition( expectedOffset, contextMessage ) {
var viewport = viewer.viewport;
var expPosition = viewport.viewportToViewerElementCoordinates(
new OpenSeadragon.Point( 0.5, 0.6 ) )
.apply( Math.floor )
.plus( expectedOffset );
var actPosition = $( "#fixed-overlay" ).position();
equal( actPosition.left, expPosition.x, "Fixed overlay X position mismatch " + contextMessage );
equal( actPosition.top, expPosition.y, "Fixed overlay Y position mismatch " + contextMessage );
}
waitForViewer( function() {
checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
"with overlay of size 70,60." );
$( "#fixed-overlay" ).width( 50 );
$( "#fixed-overlay" ).height( 40 );
// The resizing of the overlays is not detected by the viewer's loop.
viewer.forceRedraw();
setTimeout( function() {
checkFixedOverlayPosition( new OpenSeadragon.Point( -35, -30 ),
"with overlay of size 50,40." );
// Restore original size
$( "#fixed-overlay" ).width( 70 );
$( "#fixed-overlay" ).height( 60 );
start();
}, 100 );
} );
} );
} )( ); } )( );