Updated to address feedbac from @iangilman

This commit is contained in:
houseofyin 2013-04-04 22:30:59 -04:00
commit bbf0fc4302
11 changed files with 415 additions and 467 deletions

View File

@ -14,6 +14,7 @@ module.exports = function(grunt) {
// ----------
var distribution = "build/openseadragon/openseadragon.js",
minified = "build/openseadragon/openseadragon.min.js",
releaseRoot = "../site-build/built-openseadragon/",
sources = [
"src/openseadragon.js",
"src/fullscreen.js",
@ -52,11 +53,7 @@ module.exports = function(grunt) {
clean: {
build: ["build"],
release: {
src: [
"../site-build/openseadragon",
"../site-build/openseadragon.zip",
"../site-build/openseadragon.tar"
],
src: [releaseRoot],
options: {
force: true
}
@ -150,14 +147,16 @@ module.exports = function(grunt) {
grunt.file.recurse("images", function(abspath, rootdir, subdir, filename) {
grunt.file.copy(abspath, "build/openseadragon/images/" + (subdir || "") + filename);
});
grunt.file.copy("changelog.txt", "build/changelog.txt");
});
// ----------
// Copy:release task.
// Copies the contents of the build folder into ../site-build.
// Copies the contents of the build folder into the release folder.
grunt.registerTask("copy:release", function() {
grunt.file.recurse("build", function(abspath, rootdir, subdir, filename) {
var dest = "../site-build/"
var dest = releaseRoot
+ (subdir ? subdir + "/" : '/')
+ filename;
@ -184,7 +183,7 @@ module.exports = function(grunt) {
// ----------
// Publish task.
// Cleans the built files out of ../site-build and copies newly built ones over.
// Cleans the built files out of the release folder and copies newly built ones over.
grunt.registerTask("publish", ["package", "clean:release", "copy:release"]);
// ----------

View File

@ -54,6 +54,12 @@ If you wish to work interactively with the tests or test your changes:
and open `http://localhost:8000/` in your browser
## Contributing
OpenSeadragon is truly a community project; we welcome your involvement!
When contributing, please attempt to match the code style already in the codebase. Note that we use four spaces per indentation stop. For more thoughts on code style, see https://github.com/rwldrn/idiomatic.js/.
## Licenses
OpenSeadragon was initially released with a New BSD License ( preserved below ), while work done by Chris Thatcher is additionally licensed under the MIT License.

29
changelog.txt Normal file
View File

@ -0,0 +1,29 @@
OPENSEADRAGON CHANGELOG
=======================
0.9.125: In Progress
* Fully deprecated OpenSeadragon.createFromDZI, safely deprecated Viewer.openTileSource and
Viewer.openDZI to use Viewer.open internally. (#53 & #54).
* Full page bug fix for when viewer is child of document body (#43).
* Overlays for DZI bug fix (#45).
0.9.124:
* Performance enhancements.
0.9.123:
* Real fullscreen support.
0.9.122:
* Performance enhancements.
0.9.121:
* Touch pan now works on Android.
* Pinch zoom is better on all devices.

View File

@ -1,6 +1,6 @@
{
"name": "OpenSeadragon",
"version": "0.9.123",
"version": "0.9.124",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"devDependencies": {
"grunt": "~0.4.0",
@ -8,7 +8,7 @@
"grunt-contrib-concat": "~0.1.2",
"grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-uglify": "~0.1.1",
"grunt-contrib-qunit": "~0.1.1",
"grunt-contrib-qunit": "~0.2.0",
"grunt-contrib-connect": "~0.1.2",
"grunt-contrib-watch": "~0.2.0",
"grunt-contrib-clean": "~0.4.0",

View File

@ -108,19 +108,8 @@ $.extend( $.DziTileSource.prototype, $.TileSource.prototype, {
options = configureFromObject( this, data );
}
if( url && !options.tilesUrl ){
if( 'http' !== url.substring( 0, 4 ) ){
host = location.protocol + '//' + location.host;
}
dziPath = url.split('/');
dziName = dziPath.pop();
dziName = dziName.substring(0, dziName.lastIndexOf('.'));
dziPath = '/' + dziPath.join('/') + '/' + dziName + '_files/';
tilesUrl = dziPath;
if( host ){
tilesUrl = host + tilesUrl;
}
options.tilesUrl = tilesUrl;
if (url && !options.tilesUrl) {
options.tilesUrl = url.replace(/([^\/]+)\.dzi$/, '$1_files/');
}
return options;
@ -216,6 +205,7 @@ function configureFromXML( tileSource, xmlDoc ){
configuration = {
Image: {
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
Url: root.getAttribute( "Url" ),
Format: root.getAttribute( "Format" ),
DisplayRect: null,
Overlap: parseInt( root.getAttribute( "Overlap" ), 10 ),
@ -315,8 +305,7 @@ function configureFromObject( tileSource, configuration ){
));
}
return {
return $.extend(true, {
width: width, /* width *required */
height: height, /* height *required */
tileSize: tileSize, /* tileSize *required */
@ -326,7 +315,7 @@ function configureFromObject( tileSource, configuration ){
tilesUrl: tilesUrl, /* tilesUrl */
fileFormat: fileFormat, /* fileFormat */
displayRects: displayRects /* displayRects */
};
}, configuration );
}

View File

@ -17,7 +17,8 @@ $.Navigator = function( options ){
var _this = this,
viewer = options.viewer,
viewerSize = $.getElementSize( viewer.element );
viewerSize = $.getElementSize( viewer.element),
unneededElement;
//We may need to create a new element and id if they did not
//provide the id for the existing element
@ -148,6 +149,10 @@ $.Navigator = function( options ){
$.Viewer.apply( this, [ options ] );
this.element.getElementsByTagName('form')[0].appendChild( this.displayRegion );
unneededElement = this.element.getElementsByTagName('textarea')[0];
if (unneededElement) {
unneededElement.parentNode.removeChild(unneededElement);
}
};
@ -194,7 +199,7 @@ $.extend( $.Navigator.prototype, $.EventHandler.prototype, $.Viewer.prototype, {
containerSize.y
) / source.tileSize;
} else {
this.minPixelRatio = thie.viewer.minPixelRatio;
this.minPixelRatio = this.viewer.minPixelRatio;
}
return $.Viewer.prototype.open.apply( this, [ source ] );
}

View File

@ -1385,108 +1385,16 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
/**
* Loads a Deep Zoom Image description from a url, XML string or JSON string
* and provides a callback hook for the resulting Document
* Fully deprecated. Will throw an error.
* @function
* @name OpenSeadragon.createFromDZI
* @param {String} xmlUrl
* @param {String} xmlString
* @param {Function} callback
* @deprecated
* @deprecated - use OpenSeadragon.Viewer.prototype.open
*/
createFromDZI: function( dzi, callback, tileHost ) {
var async = typeof ( callback ) == "function",
dziUrl = (
dzi.substring(0,1) != '<' &&
dzi.substring(0,1) != '{'
) ? dzi : null,
dziString = dziUrl ? null : dzi,
error = null,
urlParts,
filename,
lastDot,
tilesUrl,
callbackName;
if( tileHost ){
tilesUrl = tileHost + "/_files/";
} else if( dziUrl ) {
urlParts = dziUrl.split( '/' );
filename = urlParts[ urlParts.length - 1 ];
if( filename.match(/_dzi\.js$/) ){
//for jsonp dzi specification, the '_dzi' needs to be removed
//from the filename to be consistent with the spec
filename = filename.replace('_dzi.js', '.js');
}
lastDot = filename.lastIndexOf( '.' );
if ( lastDot > -1 ) {
urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot );
}
tilesUrl = urlParts.join( '/' ) + "_files/";
}
function finish( func, obj ) {
try {
return func( obj, tilesUrl );
} catch ( e ) {
if ( async ) {
return null;
} else {
throw e;
}
}
}
if ( async ) {
if ( dziString ) {
window.setTimeout( function() {
var source = finish( processDZIXml, $.parseXml( xmlString ) );
// call after finish sets error
callback( source, error );
}, 1);
} else {
if( dziUrl.match(/_dzi\.js$/) ){
callbackName = dziUrl.split( '/' ).pop().replace('.js','');
$.jsonp({
url: dziUrl,
callbackName: callbackName,
callback: function( imageData ){
var source = finish( processDZIJSON, imageData.Image );
callback( source );
}
});
} else {
$.makeAjaxRequest( dziUrl, function( xhr ) {
var source = finish( processDZIResponse, xhr );
// call after finish sets error
callback( source, error );
});
}
}
return null;
}
if ( dziString ) {
return finish(
processDZIXml,
$.parseXml( dziString )
);
} else {
return finish(
processDZIResponse,
$.makeAjaxRequest( dziUrl )
);
}
throw "OpenSeadragon.createFromDZI is deprecated, use Viewer.open.";
},
/**

View File

@ -281,9 +281,7 @@ $.TileSource.prototype = {
callback: callback
});
} else {
//TODO: struggling a little with TileSource rewrite to make info
// requests work asyncronously. For now I'm opting to make
// all xhr info request syncronous.
// request info via xhr asyncronously.
$.makeAjaxRequest( url, function( xhr ) {
var data = processResponse( xhr );
callback( data );
@ -415,7 +413,7 @@ function processResponse( xhr ){
* @eprivate
* @inner
* @function
* @param {Object|Array} data - the tile source configuration object
* @param {Object|Array|Document} data - the tile source configuration object
* @param {String} url - the url where the tile source configuration object was
* loaded from, if any.
*/

View File

@ -129,6 +129,7 @@ $.Viewer = function( options ) {
// did we decide this viewer has a sequence of tile sources
"sequenced": false,
"sequence": 0,
"fullPage": false,
"onfullscreenchange": null
};
@ -163,12 +164,12 @@ $.Viewer = function( options ) {
initialTileSource = this.tileSources;
}
this.openTileSource( initialTileSource );
this.open( initialTileSource );
}
this.element = this.element || document.getElementById( this.id );
this.canvas = $.makeNeutralElement( "div" );
this.textAreaToReceiveKeyboardCommands = $.makeNeutralElement( "textarea" );
this.element = this.element || document.getElementById( this.id );
this.canvas = $.makeNeutralElement( "div" );
this.keyboardCommandArea = $.makeNeutralElement( "textarea" );
this.canvas.className = "openseadragon-canvas";
(function( style ){
@ -180,17 +181,6 @@ $.Viewer = function( options ) {
style.left = "0px";
}( this.canvas.style ));
this.textAreaToReceiveKeyboardCommands.className = "findmetoo";
(function( style ){
style.width = "100%";
style.height = "100%";
style.overflow = "hidden";
style.position = "absolute";
style.top = "0px";
style.left = "0px";
}( this.textAreaToReceiveKeyboardCommands.style ));
//the container is created through applying the ControlDock constructor above
this.container.className = "openseadragon-container";
(function( style ){
@ -203,8 +193,18 @@ $.Viewer = function( options ) {
style.textAlign = "left"; // needed to protect against
}( this.container.style ));
this.keyboardCommandArea.className = "keyboard-command-area";
(function( style ){
style.width = "100%";
style.height = "100%";
style.overflow = "hidden";
style.position = "absolute";
style.top = "0px";
style.left = "0px";
}( this.keyboardCommandArea.style ));
this.container.insertBefore( this.canvas, this.container.firstChild );
this.container.insertBefore( this.textAreaToReceiveKeyboardCommands, this.container.firstChild );
this.container.insertBefore( this.keyboardCommandArea, this.container.firstChild );
this.element.appendChild( this.container );
//Used for toggling between fullscreen and default container size
@ -215,62 +215,63 @@ $.Viewer = function( options ) {
this.bodyOverflow = document.body.style.overflow;
this.docOverflow = document.documentElement.style.overflow;
this.textAreaToReceiveKeyboardCommands.innerTracker = new $.MouseTracker({
_this : this,
element: this.textAreaToReceiveKeyboardCommands,
focusHandler: function(){
var point = $.getElementPosition( this.element );
window.scrollTo( 0, point.y );
},
this.keyboardCommandArea.innerTracker = new $.MouseTracker({
_this : this,
element: this.keyboardCommandArea,
focusHandler: function(){
var point = $.getElementPosition( this.element );
window.scrollTo( 0, point.y );
},
keyHandler: function(tracker, keyCode, shiftKey){
switch( keyCode ){
case 61://=|+
_this.viewport.zoomBy(1.1);
_this.viewport.applyConstraints();
return false;
case 45://-|_
_this.viewport.zoomBy(0.9);
_this.viewport.applyConstraints();
return false;
case 48://0|)
_this.viewport.goHome();
_this.viewport.applyConstraints();
return false;
case 119://w
case 87://W
case 38://up arrow
if (shiftKey)
keyHandler: function(tracker, keyCode, shiftKey){
switch( keyCode ){
case 61://=|+
_this.viewport.zoomBy(1.1);
else
_this.viewport.panBy(new $.Point(0, -0.05));
_this.viewport.applyConstraints();
return false;
case 115://s
case 83://S
case 40://down arrow
if (shiftKey)
_this.viewport.applyConstraints();
return false;
case 45://-|_
_this.viewport.zoomBy(0.9);
else
_this.viewport.panBy(new $.Point(0, 0.05));
_this.viewport.applyConstraints();
return false;
case 97://a
case 37://left arrow
_this.viewport.panBy(new $.Point(-0.05, 0));
_this.viewport.applyConstraints();
return false;
case 100://d
case 39://right arrow
_this.viewport.panBy(new $.Point(0.05, 0));
_this.viewport.applyConstraints();
return false;
default:
//console.log( 'navigator keycode %s', keyCode );
return true;
_this.viewport.applyConstraints();
return false;
case 48://0|)
_this.viewport.goHome();
_this.viewport.applyConstraints();
return false;
case 119://w
case 87://W
case 38://up arrow
if (shiftKey)
_this.viewport.zoomBy(1.1);
else
_this.viewport.panBy(new $.Point(0, -0.05));
_this.viewport.applyConstraints();
return false;
case 115://s
case 83://S
case 40://down arrow
if (shiftKey)
_this.viewport.zoomBy(0.9);
else
_this.viewport.panBy(new $.Point(0, 0.05));
_this.viewport.applyConstraints();
return false;
case 97://a
case 37://left arrow
_this.viewport.panBy(new $.Point(-0.05, 0));
_this.viewport.applyConstraints();
return false;
case 100://d
case 39://right arrow
_this.viewport.panBy(new $.Point(0.05, 0));
_this.viewport.applyConstraints();
return false;
default:
//console.log( 'navigator keycode %s', keyCode );
return true;
}
}
}
}).setTracking( true ); // default state
}).setTracking( true ); // default state
this.innerTracker = new $.MouseTracker({
element: this.canvas,
@ -324,29 +325,36 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
},
/**
* If the string is xml is simply parsed and opened, otherwise the string
* is treated as an URL and an xml document is requested via ajax, parsed
* and then opened in the viewer.
* A deprecated function, renamed to 'open' to match event name and
* match current 'close' method.
* @function
* @name OpenSeadragon.Viewer.prototype.openDzi
* @param {String} dzi and xml string or the url to a DZI xml document.
* @param {String} dzi xml string or the url to a DZI xml document.
* @return {OpenSeadragon.Viewer} Chainable.
*
* @deprecated - use 'open' instead.
*/
openDzi: function ( dzi ) {
var _this = this;
$.createFromDZI(
dzi,
function( source ){
_this.open( source );
},
this.tileHost
);
return this;
return this.open( dzi );
},
/**
* A deprecated function, renamed to 'open' to match event name and
* match current 'close' method.
* @function
* @name OpenSeadragon.Viewer.prototype.openTileSource
* @param {String|Object|Function} See OpenSeadragon.Viewer.prototype.open
* @return {OpenSeadragon.Viewer} Chainable.
*
* @deprecated - use 'open' instead.
*/
openTileSource: function ( tileSource ) {
return this.open( tileSource );
},
/**
* Open a TileSource object into the viewer.
*
* tileSources is a complex option...
*
* It can be a string, object, function, or an array of any of these:
@ -361,227 +369,56 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
* named 'getTileUrl', it is treated as a custom TileSource.
* @function
* @name OpenSeadragon.Viewer.prototype.openTileSource
* @param {String|Object|Function}
* @return {OpenSeadragon.Viewer} Chainable.
*/
openTileSource: function ( tileSource ) {
open: function ( tileSource ) {
var _this = this,
customTileSource,
readySource,
$TileSource,
options;
//allow plain xml strings or json strings to be parsed here
if( $.type( tileSource ) == 'string' ){
if( tileSource.match(/\s*<.*/) ){
tileSource = $.parseXml( tileSource );
}else if( tileSource.match(/\s*[\{\[].*/) ){
/*jshint evil:true*/
tileSource = eval( '('+tileSource+')' );
}
}
setTimeout(function(){
if ( $.type( tileSource ) == 'string') {
//TODO: We cant assume a string implies a dzi since all
//complete TileSource implementations should have a getInfo
//which allows them to be configured via AJAX. Im not sure
//if its better to use file extension or url pattern, or to
//inspect the resulting info object.
//If its still a string it means it must be a url at this point
tileSource = new $.TileSource( tileSource, function( readySource ){
_this.open( readySource );
openTileSource( _this, readySource );
});
} else if ( $.isPlainObject( tileSource ) ){
} else if ( $.isPlainObject( tileSource ) || tileSource.nodeType ){
if( $.isFunction( tileSource.getTileUrl ) ){
//Custom tile source
customTileSource = new $.TileSource(tileSource);
customTileSource.getTileUrl = tileSource.getTileUrl;
_this.open( customTileSource );
openTileSource( _this, customTileSource );
} else {
//inline configuration
$TileSource = $.TileSource.determineType( _this, tileSource );
options = $TileSource.prototype.configure.apply( _this, [ tileSource ]);
readySource = new $TileSource( options );
_this.open( readySource );
openTileSource( _this, readySource );
}
} else {
//can assume it's already a tile source implementation
_this.open( tileSource );
openTileSource( _this, tileSource );
}
}, 1);
return this;
},
/**
* @function
* @name OpenSeadragon.Viewer.prototype.open
* @return {OpenSeadragon.Viewer} Chainable.
*/
open: function( source ) {
var _this = this,
overlay,
i;
if ( this.source ) {
this.close( );
}
// to ignore earlier opens
THIS[ this.hash ].lastOpenStartTime = +new Date();
window.setTimeout( function () {
if ( THIS[ _this.hash ].lastOpenStartTime > THIS[ _this.hash ].lastOpenEndTime ) {
THIS[ _this.hash ].setMessage( $.getString( "Messages.Loading" ) );
}
}, 2000);
THIS[ this.hash ].lastOpenEndTime = +new Date();
this.canvas.innerHTML = "";
THIS[ this.hash ].prevContainerSize = $.getElementSize( this.container );
if( this.collectionMode ){
this.source = new $.TileSourceCollection({
rows: this.collectionRows,
layout: this.collectionLayout,
tileSize: this.collectionTileSize,
tileSources: this.tileSources,
tileMargin: this.collectionTileMargin
});
this.viewport = this.viewport ? this.viewport : new $.Viewport({
collectionMode: true,
collectionTileSource: this.source,
containerSize: THIS[ this.hash ].prevContainerSize,
contentSize: this.source.dimensions,
springStiffness: this.springStiffness,
animationTime: this.animationTime,
showNavigator: false,
minZoomImageRatio: 1,
maxZoomPixelRatio: 1,
viewer: this //,
//TODO: figure out how to support these in a way that makes sense
//minZoomLevel: this.minZoomLevel,
//maxZoomLevel: this.maxZoomLevel
});
}else{
if( source ){
this.source = source;
}
this.viewport = this.viewport ? this.viewport : new $.Viewport({
containerSize: THIS[ this.hash ].prevContainerSize,
contentSize: this.source.dimensions,
springStiffness: this.springStiffness,
animationTime: this.animationTime,
minZoomImageRatio: this.minZoomImageRatio,
maxZoomPixelRatio: this.maxZoomPixelRatio,
visibilityRatio: this.visibilityRatio,
wrapHorizontal: this.wrapHorizontal,
wrapVertical: this.wrapVertical,
defaultZoomLevel: this.defaultZoomLevel,
minZoomLevel: this.minZoomLevel,
maxZoomLevel: this.maxZoomLevel,
viewer: this
});
}
if( this.preserveVewport ){
this.viewport.resetContentSize( this.source.dimensions );
}
this.source.overlays = this.source.overlays || [];
this.drawer = new $.Drawer({
source: this.source,
viewport: this.viewport,
element: this.canvas,
overlays: [].concat( this.overlays ).concat( this.source.overlays ),
maxImageCacheCount: this.maxImageCacheCount,
imageLoaderLimit: this.imageLoaderLimit,
minZoomImageRatio: this.minZoomImageRatio,
wrapHorizontal: this.wrapHorizontal,
wrapVertical: this.wrapVertical,
immediateRender: this.immediateRender,
blendTime: this.blendTime,
alwaysBlend: this.alwaysBlend,
minPixelRatio: this.collectionMode ? 0 : this.minPixelRatio,
timeout: this.timeout,
debugMode: this.debugMode,
debugGridColor: this.debugGridColor
});
//Instantiate a navigator if configured
if ( this.showNavigator && ! this.navigator && !this.collectionMode ){
this.navigator = new $.Navigator({
id: this.navigatorId,
position: this.navigatorPosition,
sizeRatio: this.navigatorSizeRatio,
height: this.navigatorHeight,
width: this.navigatorWidth,
tileSources: this.tileSources,
tileHost: this.tileHost,
prefixUrl: this.prefixUrl,
overlays: this.overlays,
viewer: this
});
}
//Instantiate a referencestrip if configured
if ( this.showReferenceStrip && ! this.referenceStrip ){
this.referenceStrip = new $.ReferenceStrip({
id: this.referenceStripElement,
position: this.referenceStripPosition,
sizeRatio: this.referenceStripSizeRatio,
scroll: this.referenceStripScroll,
height: this.referenceStripHeight,
width: this.referenceStripWidth,
tileSources: this.tileSources,
tileHost: this.tileHost,
prefixUrl: this.prefixUrl,
overlays: this.overlays,
viewer: this
});
}
//this.profiler = new $.Profiler();
THIS[ this.hash ].animating = false;
THIS[ this.hash ].forceRedraw = true;
scheduleUpdate( this, updateMulti );
//Assuming you had programatically created a bunch of overlays
//and added them via configuration
for ( i = 0; i < this.overlayControls.length; i++ ) {
overlay = this.overlayControls[ i ];
if ( overlay.point ) {
this.drawer.addOverlay(
overlay.id,
new $.Point(
overlay.point.X,
overlay.point.Y
),
$.OverlayPlacement.TOP_LEFT
);
} else {
this.drawer.addOverlay(
overlay.id,
new $.Rect(
overlay.rect.Point.X,
overlay.rect.Point.Y,
overlay.rect.Width,
overlay.rect.Height
),
overlay.placement
);
}
}
VIEWERS[ this.hash ] = this;
if( this.navigator ){
this.navigator.open( source );
}
this.raiseEvent( 'open', { source: source, viewer: this } );
return this;
},
/**
* @function
* @name OpenSeadragon.Viewer.prototype.close
@ -667,7 +504,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
* @return {Boolean}
*/
isFullPage: function () {
return this.element.parentNode == document.body;
return THIS[ this.hash ].fullPage;
},
@ -724,7 +561,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
//the bodies elements and replace them when we leave full screen.
this.previousBody = [];
THIS[ this.hash ].prevElementParent = this.element.parentNode;
THIS[ this.hash ].prevNextSibling = this.element.prevNextSibling;
THIS[ this.hash ].prevNextSibling = this.element.nextSibling;
THIS[ this.hash ].prevElementSize = $.getElementSize( this.element );
nodes = body.childNodes.length;
for ( i = 0; i < nodes; i ++ ){
@ -785,6 +622,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
) + 'px';
}
THIS[ this.hash ].fullPage = true;
// mouse will be inside container now
$.delegate( this, onContainerEnter )();
@ -846,6 +685,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
this.element.style.height = THIS[ this.hash ].prevElementSize.y + 'px';
this.element.style.width = THIS[ this.hash ].prevElementSize.x + 'px';
THIS[ this.hash ].fullPage = false;
// mouse will likely be outside now
$.delegate( this, onContainerExit )();
@ -1155,7 +996,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
}
}
this.openTileSource( this.tileSources[ page ] );
this.open( this.tileSources[ page ] );
}
if( $.isFunction( this.onPageChange ) ){
@ -1172,6 +1013,185 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
});
/**
* @function
* @private
*/
function openTileSource( viewer, source ) {
var _this = viewer,
overlay,
i;
if ( _this.source ) {
_this.close( );
}
// to ignore earlier opens
THIS[ _this.hash ].lastOpenStartTime = +new Date();
window.setTimeout( function () {
if ( THIS[ _this.hash ].lastOpenStartTime > THIS[ _this.hash ].lastOpenEndTime ) {
THIS[ _this.hash ].setMessage( $.getString( "Messages.Loading" ) );
}
}, 2000);
THIS[ _this.hash ].lastOpenEndTime = +new Date();
_this.canvas.innerHTML = "";
THIS[ _this.hash ].prevContainerSize = $.getElementSize( _this.container );
if( _this.collectionMode ){
_this.source = new $.TileSourceCollection({
rows: _this.collectionRows,
layout: _this.collectionLayout,
tileSize: _this.collectionTileSize,
tileSources: _this.tileSources,
tileMargin: _this.collectionTileMargin
});
_this.viewport = _this.viewport ? _this.viewport : new $.Viewport({
collectionMode: true,
collectionTileSource: _this.source,
containerSize: THIS[ _this.hash ].prevContainerSize,
contentSize: _this.source.dimensions,
springStiffness: _this.springStiffness,
animationTime: _this.animationTime,
showNavigator: false,
minZoomImageRatio: 1,
maxZoomPixelRatio: 1,
viewer: _this //,
//TODO: figure out how to support these in a way that makes sense
//minZoomLevel: this.minZoomLevel,
//maxZoomLevel: this.maxZoomLevel
});
}else{
if( source ){
_this.source = source;
}
_this.viewport = _this.viewport ? _this.viewport : new $.Viewport({
containerSize: THIS[ _this.hash ].prevContainerSize,
contentSize: _this.source.dimensions,
springStiffness: _this.springStiffness,
animationTime: _this.animationTime,
minZoomImageRatio: _this.minZoomImageRatio,
maxZoomPixelRatio: _this.maxZoomPixelRatio,
visibilityRatio: _this.visibilityRatio,
wrapHorizontal: _this.wrapHorizontal,
wrapVertical: _this.wrapVertical,
defaultZoomLevel: _this.defaultZoomLevel,
minZoomLevel: _this.minZoomLevel,
maxZoomLevel: _this.maxZoomLevel,
viewer: _this
});
}
if( _this.preserveVewport ){
_this.viewport.resetContentSize( _this.source.dimensions );
}
_this.source.overlays = _this.source.overlays || [];
_this.drawer = new $.Drawer({
source: _this.source,
viewport: _this.viewport,
element: _this.canvas,
overlays: [].concat( _this.overlays ).concat( _this.source.overlays ),
maxImageCacheCount: _this.maxImageCacheCount,
imageLoaderLimit: _this.imageLoaderLimit,
minZoomImageRatio: _this.minZoomImageRatio,
wrapHorizontal: _this.wrapHorizontal,
wrapVertical: _this.wrapVertical,
immediateRender: _this.immediateRender,
blendTime: _this.blendTime,
alwaysBlend: _this.alwaysBlend,
minPixelRatio: _this.collectionMode ? 0 : _this.minPixelRatio,
timeout: _this.timeout,
debugMode: _this.debugMode,
debugGridColor: _this.debugGridColor
});
//Instantiate a navigator if configured
if ( _this.showNavigator && ! _this.navigator && !_this.collectionMode ){
_this.navigator = new $.Navigator({
id: _this.navigatorId,
position: _this.navigatorPosition,
sizeRatio: _this.navigatorSizeRatio,
height: _this.navigatorHeight,
width: _this.navigatorWidth,
tileSources: _this.tileSources,
tileHost: _this.tileHost,
prefixUrl: _this.prefixUrl,
overlays: _this.overlays,
viewer: _this
});
}
//Instantiate a referencestrip if configured
if ( _this.showReferenceStrip && !_this.referenceStrip ){
_this.referenceStrip = new $.ReferenceStrip({
id: _this.referenceStripElement,
position: _this.referenceStripPosition,
sizeRatio: _this.referenceStripSizeRatio,
scroll: _this.referenceStripScroll,
height: _this.referenceStripHeight,
width: _this.referenceStripWidth,
tileSources: _this.tileSources,
tileHost: _this.tileHost,
prefixUrl: _this.prefixUrl,
overlays: _this.overlays,
viewer: _this
});
}
//this.profiler = new $.Profiler();
THIS[ _this.hash ].animating = false;
THIS[ _this.hash ].forceRedraw = true;
scheduleUpdate( _this, updateMulti );
//Assuming you had programatically created a bunch of overlays
//and added them via configuration
for ( i = 0; i < _this.overlayControls.length; i++ ) {
overlay = _this.overlayControls[ i ];
if ( overlay.point ) {
_this.drawer.addOverlay(
overlay.id,
new $.Point(
overlay.point.X,
overlay.point.Y
),
$.OverlayPlacement.TOP_LEFT
);
} else {
_this.drawer.addOverlay(
overlay.id,
new $.Rect(
overlay.rect.Point.X,
overlay.rect.Point.Y,
overlay.rect.Width,
overlay.rect.Height
),
overlay.placement
);
}
}
VIEWERS[ _this.hash ] = _this;
if( _this.navigator ){
_this.navigator.open( source );
}
_this.raiseEvent( 'open', { source: source, viewer: _this } );
return _this;
}
///////////////////////////////////////////////////////////////////////////////
@ -1275,7 +1295,7 @@ function onBlur(){
}
function onCanvasClick( tracker, position, quick, shift, event ) {
function onCanvasClick( tracker, position, quick, shift ) {
var zoomPreClick,
factor;
if ( this.viewport && quick ) { // ignore clicks where mouse moved
@ -1287,16 +1307,15 @@ function onCanvasClick( tracker, position, quick, shift, event ) {
);
this.viewport.applyConstraints();
}
this.raiseEvent( 'click', {
this.raiseEvent( 'canvas-click', {
tracker: tracker,
position: position,
quick: quick,
shift: shift,
originalEvent: event
shift: shift
});
}
function onCanvasDrag( tracker, position, delta, shift, event ) {
function onCanvasDrag( tracker, position, delta, shift ) {
if ( this.viewport ) {
if( !this.panHorizontal ){
delta.x = 0;
@ -1313,29 +1332,27 @@ function onCanvasDrag( tracker, position, delta, shift, event ) {
this.viewport.applyConstraints();
}
}
this.raiseEvent( 'drag', {
this.raiseEvent( 'canvas-click', {
tracker: tracker,
position: position,
delta: delta,
shift: shift,
originalEvent: event
shift: shift
});
}
function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease, event ) {
function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease ) {
if ( insideElementPress && this.viewport ) {
this.viewport.applyConstraints();
}
this.raiseEvent( 'release', {
this.raiseEvent( 'canvas-release', {
tracker: tracker,
position: position,
insideElementPress: insideElementPress,
insideElementRelease: insideElementRelease,
originalEvent: event
insideElementRelease: insideElementRelease
});
}
function onCanvasScroll( tracker, position, scroll, shift, event ) {
function onCanvasScroll( tracker, position, scroll, shift ) {
var factor;
if ( this.viewport ) {
factor = Math.pow( this.zoomPerScroll, scroll );
@ -1345,58 +1362,54 @@ function onCanvasScroll( tracker, position, scroll, shift, event ) {
);
this.viewport.applyConstraints();
}
this.raiseEvent( 'scroll', {
this.raiseEvent( 'canvas-scroll', {
tracker: tracker,
position: position,
scroll: scroll,
shift: shift,
originalEvent: event
shift: shift
});
//cancels event
return false;
}
function onContainerExit( tracker, position, buttonDownElement, buttonDownAny, event ) {
function onContainerExit( tracker, position, buttonDownElement, buttonDownAny ) {
if ( !buttonDownElement ) {
THIS[ this.hash ].mouseInside = false;
if ( !THIS[ this.hash ].animating ) {
beginControlsAutoHide( this );
}
}
this.raiseEvent( 'exit', {
this.raiseEvent( 'container-exit', {
tracker: tracker,
position: position,
buttonDownElement: buttonDownElement,
buttonDownAny: buttonDownAny,
originalEvent: event
buttonDownAny: buttonDownAny
});
}
function onContainerRelease( tracker, position, insideElementPress, insideElementRelease, event ) {
function onContainerRelease( tracker, position, insideElementPress, insideElementRelease ) {
if ( !insideElementRelease ) {
THIS[ this.hash ].mouseInside = false;
if ( !THIS[ this.hash ].animating ) {
beginControlsAutoHide( this );
}
}
this.raiseEvent( 'release', {
this.raiseEvent( 'container-release', {
tracker: tracker,
position: position,
insideElementPress: insideElementPress,
insideElementRelease: insideElementRelease,
originalEvent: event
insideElementRelease: insideElementRelease
});
}
function onContainerEnter( tracker, position, buttonDownElement, buttonDownAny, event ) {
function onContainerEnter( tracker, position, buttonDownElement, buttonDownAny ) {
THIS[ this.hash ].mouseInside = true;
abortControlsAutoHide( this );
this.raiseEvent( 'enter', {
this.raiseEvent( 'container-enter', {
tracker: tracker,
position: position,
buttonDownElement: buttonDownElement,
buttonDownAny: buttonDownAny,
originalEvent: event
buttonDownAny: buttonDownAny
});
}
@ -1589,4 +1602,4 @@ function onNext(){
}
}( OpenSeadragon ));
}( OpenSeadragon ));

View File

@ -14,7 +14,7 @@ QUnit.config.autostart = false;
module("navigator", {
setup:function () {
resetDom();
Util.resetDom();
resetTestVariables();
}
});
@ -38,32 +38,11 @@ QUnit.config.autostart = false;
displayRegionHeight = null;
};
var resetDom = function () {
if ($('#exampleNavigator').is(':ui-dialog')) {
$('#exampleNavigator').dialog('destroy');
}
$("#exampleNavigator").remove();
$(".navigator").remove();
$("#example").empty();
$("#tallexample").empty();
$("#wideexample").empty();
$("#example").parent().append('<div id="exampleNavigator"></div>');
};
var equalsWithVariance = function (value1, value2, variance) {
return Math.abs(value1 - value2) <= variance;
};
var assessNumericValue = function (value1, value2, variance, message) {
ok(equalsWithVariance(value1, value2, variance), message + " Expected:" + value1 + " Found: " + value2 + " Variance: " + variance);
};
var assessNavigatorLocation = function (expectedX, expectedY) {
var navigator = $(".navigator");
assessNumericValue(expectedX, navigator.offset().left, 4, ' Navigator x position');
assessNumericValue(expectedY, navigator.offset().top, 4, ' Navigator y position');
Util.assessNumericValue(expectedX, navigator.offset().left, 4, ' Navigator x position');
Util.assessNumericValue(expectedY, navigator.offset().top, 4, ' Navigator y position');
};
var navigatorRegionBoundsInPoints = function () {
@ -113,10 +92,10 @@ QUnit.config.autostart = false;
var assessDisplayRegion = function (status) {
var expectedBounds = navigatorRegionBoundsInPoints();
assessNumericValue(expectedBounds.width, displayRegion.width() + viewer.navigator.totalBorderWidths.x, 2, status + ' Width synchronization');
assessNumericValue(expectedBounds.height, displayRegion.height() + viewer.navigator.totalBorderWidths.y, 2, status + ' Height synchronization');
assessNumericValue(expectedBounds.x, displayRegion.position().left, 2, status + ' Left synchronization');
assessNumericValue(expectedBounds.y, displayRegion.position().top, 2, status + ' Top synchronization');
Util.assessNumericValue(expectedBounds.width, displayRegion.width() + viewer.navigator.totalBorderWidths.x, 2, status + ' Width synchronization');
Util.assessNumericValue(expectedBounds.height, displayRegion.height() + viewer.navigator.totalBorderWidths.y, 2, status + ' Height synchronization');
Util.assessNumericValue(expectedBounds.x, displayRegion.position().left, 2, status + ' Left synchronization');
Util.assessNumericValue(expectedBounds.y, displayRegion.position().top, 2, status + ' Top synchronization');
};
var waitForViewer = function () {
@ -138,11 +117,11 @@ QUnit.config.autostart = false;
viewerAndNavigatorDisplayReady = viewer.drawer !== null &&
!viewer.drawer.needsUpdate() &&
currentDisplayWidth > 0 &&
equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, .0001) &&
equalsWithVariance(lastDisplayWidth, currentDisplayWidth, .0001) &&
equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, .0001) &&
equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, .0001) &&
equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, .0001);
Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, .0001) &&
Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, .0001) &&
Util.equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, .0001) &&
Util.equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, .0001) &&
Util.equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, .0001);
}
catch (err) {
//Ignore. Subsequent code will try again shortly
@ -213,10 +192,10 @@ QUnit.config.autostart = false;
expecteYCoordinate = 1 / viewer.source.aspectRatio - viewer.viewport.getBounds().height;
}
if (viewer.viewport.getBounds().width < 1) {
assessNumericValue(expectedXCoordinate, viewer.viewport.getBounds().x, .04, ' Viewer at ' + theContentCorner + ', x coord');
Util.assessNumericValue(expectedXCoordinate, viewer.viewport.getBounds().x, .04, ' Viewer at ' + theContentCorner + ', x coord');
}
if (viewer.viewport.getBounds().height < 1 / viewer.source.aspectRatio) {
assessNumericValue(expecteYCoordinate, viewer.viewport.getBounds().y, .04, ' Viewer at ' + theContentCorner + ', y coord');
Util.assessNumericValue(expecteYCoordinate, viewer.viewport.getBounds().y, .04, ' Viewer at ' + theContentCorner + ', y coord');
}
}
};
@ -226,8 +205,8 @@ QUnit.config.autostart = false;
if (viewer.source.aspectRatio < 1) {
yPositionVariance = yPositionVariance / viewer.source.aspectRatio;
}
assessNumericValue(1 / viewer.source.aspectRatio / 2, viewer.viewport.getCenter().y, yPositionVariance, ' Viewer at center, y coord');
assessNumericValue(.5, viewer.viewport.getCenter().x, .4, ' Viewer at center, x coord');
Util.assessNumericValue(1 / viewer.source.aspectRatio / 2, viewer.viewport.getCenter().y, yPositionVariance, ' Viewer at center, y coord');
Util.assessNumericValue(.5, viewer.viewport.getCenter().x, .4, ' Viewer at center, x coord');
};
var clickOnNavigator = function (theContentCorner) {

View File

@ -28,8 +28,30 @@
.simulate('mouseover', event)
.simulate('mousedown', event)
.simulate('mouseup', event);
},
resetDom: function () {
if ($('#exampleNavigator').is(':ui-dialog')) {
$('#exampleNavigator').dialog('destroy');
}
$("#exampleNavigator").remove();
$(".navigator").remove();
$("#example").empty();
$("#tallexample").empty();
$("#wideexample").empty();
$("#example").parent().append('<div id="exampleNavigator"></div>');
},
equalsWithVariance: function (value1, value2, variance) {
return Math.abs(value1 - value2) <= variance;
},
assessNumericValue: function (value1, value2, variance, message) {
ok(Util.equalsWithVariance(value1, value2, variance), message + " Expected:" + value1 + " Found: " + value2 + " Variance: " + variance);
}
};
})();