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", var distribution = "build/openseadragon/openseadragon.js",
minified = "build/openseadragon/openseadragon.min.js", minified = "build/openseadragon/openseadragon.min.js",
releaseRoot = "../site-build/built-openseadragon/",
sources = [ sources = [
"src/openseadragon.js", "src/openseadragon.js",
"src/fullscreen.js", "src/fullscreen.js",
@ -52,11 +53,7 @@ module.exports = function(grunt) {
clean: { clean: {
build: ["build"], build: ["build"],
release: { release: {
src: [ src: [releaseRoot],
"../site-build/openseadragon",
"../site-build/openseadragon.zip",
"../site-build/openseadragon.tar"
],
options: { options: {
force: true force: true
} }
@ -150,14 +147,16 @@ module.exports = function(grunt) {
grunt.file.recurse("images", function(abspath, rootdir, subdir, filename) { grunt.file.recurse("images", function(abspath, rootdir, subdir, filename) {
grunt.file.copy(abspath, "build/openseadragon/images/" + (subdir || "") + filename); grunt.file.copy(abspath, "build/openseadragon/images/" + (subdir || "") + filename);
}); });
grunt.file.copy("changelog.txt", "build/changelog.txt");
}); });
// ---------- // ----------
// Copy:release task. // 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.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 = releaseRoot
+ (subdir ? subdir + "/" : '/') + (subdir ? subdir + "/" : '/')
+ filename; + filename;
@ -184,7 +183,7 @@ module.exports = function(grunt) {
// ---------- // ----------
// Publish task. // 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"]); 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 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 ## 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. 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", "name": "OpenSeadragon",
"version": "0.9.123", "version": "0.9.124",
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.", "description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
"devDependencies": { "devDependencies": {
"grunt": "~0.4.0", "grunt": "~0.4.0",
@ -8,7 +8,7 @@
"grunt-contrib-concat": "~0.1.2", "grunt-contrib-concat": "~0.1.2",
"grunt-contrib-jshint": "~0.1.1", "grunt-contrib-jshint": "~0.1.1",
"grunt-contrib-uglify": "~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-connect": "~0.1.2",
"grunt-contrib-watch": "~0.2.0", "grunt-contrib-watch": "~0.2.0",
"grunt-contrib-clean": "~0.4.0", "grunt-contrib-clean": "~0.4.0",

View File

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

View File

@ -17,7 +17,8 @@ $.Navigator = function( options ){
var _this = this, var _this = this,
viewer = options.viewer, 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 //We may need to create a new element and id if they did not
//provide the id for the existing element //provide the id for the existing element
@ -148,6 +149,10 @@ $.Navigator = function( options ){
$.Viewer.apply( this, [ options ] ); $.Viewer.apply( this, [ options ] );
this.element.getElementsByTagName('form')[0].appendChild( this.displayRegion ); 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 containerSize.y
) / source.tileSize; ) / source.tileSize;
} else { } else {
this.minPixelRatio = thie.viewer.minPixelRatio; this.minPixelRatio = this.viewer.minPixelRatio;
} }
return $.Viewer.prototype.open.apply( this, [ source ] ); 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 * Fully deprecated. Will throw an error.
* and provides a callback hook for the resulting Document
* @function * @function
* @name OpenSeadragon.createFromDZI * @name OpenSeadragon.createFromDZI
* @param {String} xmlUrl * @param {String} xmlUrl
* @param {String} xmlString * @param {String} xmlString
* @param {Function} callback * @param {Function} callback
* @deprecated * @deprecated - use OpenSeadragon.Viewer.prototype.open
*/ */
createFromDZI: function( dzi, callback, tileHost ) { createFromDZI: function( dzi, callback, tileHost ) {
var async = typeof ( callback ) == "function", throw "OpenSeadragon.createFromDZI is deprecated, use Viewer.open.";
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 )
);
}
}, },
/** /**

View File

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

View File

@ -129,6 +129,7 @@ $.Viewer = function( options ) {
// did we decide this viewer has a sequence of tile sources // did we decide this viewer has a sequence of tile sources
"sequenced": false, "sequenced": false,
"sequence": 0, "sequence": 0,
"fullPage": false,
"onfullscreenchange": null "onfullscreenchange": null
}; };
@ -163,12 +164,12 @@ $.Viewer = function( options ) {
initialTileSource = this.tileSources; initialTileSource = this.tileSources;
} }
this.openTileSource( initialTileSource ); this.open( initialTileSource );
} }
this.element = this.element || document.getElementById( this.id ); this.element = this.element || document.getElementById( this.id );
this.canvas = $.makeNeutralElement( "div" ); this.canvas = $.makeNeutralElement( "div" );
this.textAreaToReceiveKeyboardCommands = $.makeNeutralElement( "textarea" ); this.keyboardCommandArea = $.makeNeutralElement( "textarea" );
this.canvas.className = "openseadragon-canvas"; this.canvas.className = "openseadragon-canvas";
(function( style ){ (function( style ){
@ -180,17 +181,6 @@ $.Viewer = function( options ) {
style.left = "0px"; style.left = "0px";
}( this.canvas.style )); }( 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 //the container is created through applying the ControlDock constructor above
this.container.className = "openseadragon-container"; this.container.className = "openseadragon-container";
(function( style ){ (function( style ){
@ -203,8 +193,18 @@ $.Viewer = function( options ) {
style.textAlign = "left"; // needed to protect against style.textAlign = "left"; // needed to protect against
}( this.container.style )); }( 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.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 ); this.element.appendChild( this.container );
//Used for toggling between fullscreen and default container size //Used for toggling between fullscreen and default container size
@ -215,62 +215,63 @@ $.Viewer = function( options ) {
this.bodyOverflow = document.body.style.overflow; this.bodyOverflow = document.body.style.overflow;
this.docOverflow = document.documentElement.style.overflow; this.docOverflow = document.documentElement.style.overflow;
this.textAreaToReceiveKeyboardCommands.innerTracker = new $.MouseTracker({ this.keyboardCommandArea.innerTracker = new $.MouseTracker({
_this : this, _this : this,
element: this.textAreaToReceiveKeyboardCommands, element: this.keyboardCommandArea,
focusHandler: function(){ focusHandler: function(){
var point = $.getElementPosition( this.element ); var point = $.getElementPosition( this.element );
window.scrollTo( 0, point.y ); window.scrollTo( 0, point.y );
}, },
keyHandler: function(tracker, keyCode, shiftKey){ keyHandler: function(tracker, keyCode, shiftKey){
switch( keyCode ){ switch( keyCode ){
case 61://=|+ 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)
_this.viewport.zoomBy(1.1); _this.viewport.zoomBy(1.1);
else _this.viewport.applyConstraints();
_this.viewport.panBy(new $.Point(0, -0.05)); return false;
_this.viewport.applyConstraints(); case 45://-|_
return false;
case 115://s
case 83://S
case 40://down arrow
if (shiftKey)
_this.viewport.zoomBy(0.9); _this.viewport.zoomBy(0.9);
else _this.viewport.applyConstraints();
_this.viewport.panBy(new $.Point(0, 0.05)); return false;
_this.viewport.applyConstraints(); case 48://0|)
return false; _this.viewport.goHome();
case 97://a _this.viewport.applyConstraints();
case 37://left arrow return false;
_this.viewport.panBy(new $.Point(-0.05, 0)); case 119://w
_this.viewport.applyConstraints(); case 87://W
return false; case 38://up arrow
case 100://d if (shiftKey)
case 39://right arrow _this.viewport.zoomBy(1.1);
_this.viewport.panBy(new $.Point(0.05, 0)); else
_this.viewport.applyConstraints(); _this.viewport.panBy(new $.Point(0, -0.05));
return false; _this.viewport.applyConstraints();
default: return false;
//console.log( 'navigator keycode %s', keyCode ); case 115://s
return true; 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({ this.innerTracker = new $.MouseTracker({
element: this.canvas, 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 * A deprecated function, renamed to 'open' to match event name and
* is treated as an URL and an xml document is requested via ajax, parsed * match current 'close' method.
* and then opened in the viewer.
* @function * @function
* @name OpenSeadragon.Viewer.prototype.openDzi * @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. * @return {OpenSeadragon.Viewer} Chainable.
* *
* @deprecated - use 'open' instead. * @deprecated - use 'open' instead.
*/ */
openDzi: function ( dzi ) { openDzi: function ( dzi ) {
var _this = this; return this.open( dzi );
$.createFromDZI(
dzi,
function( source ){
_this.open( source );
},
this.tileHost
);
return this;
}, },
/** /**
* 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... * tileSources is a complex option...
* *
* It can be a string, object, function, or an array of any of these: * 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. * named 'getTileUrl', it is treated as a custom TileSource.
* @function * @function
* @name OpenSeadragon.Viewer.prototype.openTileSource * @name OpenSeadragon.Viewer.prototype.openTileSource
* @param {String|Object|Function}
* @return {OpenSeadragon.Viewer} Chainable. * @return {OpenSeadragon.Viewer} Chainable.
*/ */
openTileSource: function ( tileSource ) { open: function ( tileSource ) {
var _this = this, var _this = this,
customTileSource, customTileSource,
readySource, readySource,
$TileSource, $TileSource,
options; 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(){ setTimeout(function(){
if ( $.type( tileSource ) == 'string') { if ( $.type( tileSource ) == 'string') {
//TODO: We cant assume a string implies a dzi since all //If its still a string it means it must be a url at this point
//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.
tileSource = new $.TileSource( tileSource, function( readySource ){ 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 ) ){ if( $.isFunction( tileSource.getTileUrl ) ){
//Custom tile source //Custom tile source
customTileSource = new $.TileSource(tileSource); customTileSource = new $.TileSource(tileSource);
customTileSource.getTileUrl = tileSource.getTileUrl; customTileSource.getTileUrl = tileSource.getTileUrl;
_this.open( customTileSource ); openTileSource( _this, customTileSource );
} else { } else {
//inline configuration //inline configuration
$TileSource = $.TileSource.determineType( _this, tileSource ); $TileSource = $.TileSource.determineType( _this, tileSource );
options = $TileSource.prototype.configure.apply( _this, [ tileSource ]); options = $TileSource.prototype.configure.apply( _this, [ tileSource ]);
readySource = new $TileSource( options ); readySource = new $TileSource( options );
_this.open( readySource ); openTileSource( _this, readySource );
} }
} else { } else {
//can assume it's already a tile source implementation //can assume it's already a tile source implementation
_this.open( tileSource ); openTileSource( _this, tileSource );
} }
}, 1); }, 1);
return this; 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 * @function
* @name OpenSeadragon.Viewer.prototype.close * @name OpenSeadragon.Viewer.prototype.close
@ -667,7 +504,7 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
* @return {Boolean} * @return {Boolean}
*/ */
isFullPage: function () { 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. //the bodies elements and replace them when we leave full screen.
this.previousBody = []; this.previousBody = [];
THIS[ this.hash ].prevElementParent = this.element.parentNode; 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 ); THIS[ this.hash ].prevElementSize = $.getElementSize( this.element );
nodes = body.childNodes.length; nodes = body.childNodes.length;
for ( i = 0; i < nodes; i ++ ){ for ( i = 0; i < nodes; i ++ ){
@ -785,6 +622,8 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, $.ControlDock.prototype,
) + 'px'; ) + 'px';
} }
THIS[ this.hash ].fullPage = true;
// mouse will be inside container now // mouse will be inside container now
$.delegate( this, onContainerEnter )(); $.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.height = THIS[ this.hash ].prevElementSize.y + 'px';
this.element.style.width = THIS[ this.hash ].prevElementSize.x + 'px'; this.element.style.width = THIS[ this.hash ].prevElementSize.x + 'px';
THIS[ this.hash ].fullPage = false;
// mouse will likely be outside now // mouse will likely be outside now
$.delegate( this, onContainerExit )(); $.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 ) ){ 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, var zoomPreClick,
factor; factor;
if ( this.viewport && quick ) { // ignore clicks where mouse moved if ( this.viewport && quick ) { // ignore clicks where mouse moved
@ -1287,16 +1307,15 @@ function onCanvasClick( tracker, position, quick, shift, event ) {
); );
this.viewport.applyConstraints(); this.viewport.applyConstraints();
} }
this.raiseEvent( 'click', { this.raiseEvent( 'canvas-click', {
tracker: tracker, tracker: tracker,
position: position, position: position,
quick: quick, quick: quick,
shift: shift, shift: shift
originalEvent: event
}); });
} }
function onCanvasDrag( tracker, position, delta, shift, event ) { function onCanvasDrag( tracker, position, delta, shift ) {
if ( this.viewport ) { if ( this.viewport ) {
if( !this.panHorizontal ){ if( !this.panHorizontal ){
delta.x = 0; delta.x = 0;
@ -1313,29 +1332,27 @@ function onCanvasDrag( tracker, position, delta, shift, event ) {
this.viewport.applyConstraints(); this.viewport.applyConstraints();
} }
} }
this.raiseEvent( 'drag', { this.raiseEvent( 'canvas-click', {
tracker: tracker, tracker: tracker,
position: position, position: position,
delta: delta, delta: delta,
shift: shift, shift: shift
originalEvent: event
}); });
} }
function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease, event ) { function onCanvasRelease( tracker, position, insideElementPress, insideElementRelease ) {
if ( insideElementPress && this.viewport ) { if ( insideElementPress && this.viewport ) {
this.viewport.applyConstraints(); this.viewport.applyConstraints();
} }
this.raiseEvent( 'release', { this.raiseEvent( 'canvas-release', {
tracker: tracker, tracker: tracker,
position: position, position: position,
insideElementPress: insideElementPress, insideElementPress: insideElementPress,
insideElementRelease: insideElementRelease, insideElementRelease: insideElementRelease
originalEvent: event
}); });
} }
function onCanvasScroll( tracker, position, scroll, shift, event ) { function onCanvasScroll( tracker, position, scroll, shift ) {
var factor; var factor;
if ( this.viewport ) { if ( this.viewport ) {
factor = Math.pow( this.zoomPerScroll, scroll ); factor = Math.pow( this.zoomPerScroll, scroll );
@ -1345,58 +1362,54 @@ function onCanvasScroll( tracker, position, scroll, shift, event ) {
); );
this.viewport.applyConstraints(); this.viewport.applyConstraints();
} }
this.raiseEvent( 'scroll', { this.raiseEvent( 'canvas-scroll', {
tracker: tracker, tracker: tracker,
position: position, position: position,
scroll: scroll, scroll: scroll,
shift: shift, shift: shift
originalEvent: event
}); });
//cancels event //cancels event
return false; return false;
} }
function onContainerExit( tracker, position, buttonDownElement, buttonDownAny, event ) { function onContainerExit( tracker, position, buttonDownElement, buttonDownAny ) {
if ( !buttonDownElement ) { if ( !buttonDownElement ) {
THIS[ this.hash ].mouseInside = false; THIS[ this.hash ].mouseInside = false;
if ( !THIS[ this.hash ].animating ) { if ( !THIS[ this.hash ].animating ) {
beginControlsAutoHide( this ); beginControlsAutoHide( this );
} }
} }
this.raiseEvent( 'exit', { this.raiseEvent( 'container-exit', {
tracker: tracker, tracker: tracker,
position: position, position: position,
buttonDownElement: buttonDownElement, buttonDownElement: buttonDownElement,
buttonDownAny: buttonDownAny, buttonDownAny: buttonDownAny
originalEvent: event
}); });
} }
function onContainerRelease( tracker, position, insideElementPress, insideElementRelease, event ) { function onContainerRelease( tracker, position, insideElementPress, insideElementRelease ) {
if ( !insideElementRelease ) { if ( !insideElementRelease ) {
THIS[ this.hash ].mouseInside = false; THIS[ this.hash ].mouseInside = false;
if ( !THIS[ this.hash ].animating ) { if ( !THIS[ this.hash ].animating ) {
beginControlsAutoHide( this ); beginControlsAutoHide( this );
} }
} }
this.raiseEvent( 'release', { this.raiseEvent( 'container-release', {
tracker: tracker, tracker: tracker,
position: position, position: position,
insideElementPress: insideElementPress, insideElementPress: insideElementPress,
insideElementRelease: insideElementRelease, insideElementRelease: insideElementRelease
originalEvent: event
}); });
} }
function onContainerEnter( tracker, position, buttonDownElement, buttonDownAny, event ) { function onContainerEnter( tracker, position, buttonDownElement, buttonDownAny ) {
THIS[ this.hash ].mouseInside = true; THIS[ this.hash ].mouseInside = true;
abortControlsAutoHide( this ); abortControlsAutoHide( this );
this.raiseEvent( 'enter', { this.raiseEvent( 'container-enter', {
tracker: tracker, tracker: tracker,
position: position, position: position,
buttonDownElement: buttonDownElement, buttonDownElement: buttonDownElement,
buttonDownAny: buttonDownAny, buttonDownAny: buttonDownAny
originalEvent: event
}); });
} }
@ -1589,4 +1602,4 @@ function onNext(){
} }
}( OpenSeadragon )); }( OpenSeadragon ));

View File

@ -14,7 +14,7 @@ QUnit.config.autostart = false;
module("navigator", { module("navigator", {
setup:function () { setup:function () {
resetDom(); Util.resetDom();
resetTestVariables(); resetTestVariables();
} }
}); });
@ -38,32 +38,11 @@ QUnit.config.autostart = false;
displayRegionHeight = null; 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 assessNavigatorLocation = function (expectedX, expectedY) {
var navigator = $(".navigator"); var navigator = $(".navigator");
assessNumericValue(expectedX, navigator.offset().left, 4, ' Navigator x position'); Util.assessNumericValue(expectedX, navigator.offset().left, 4, ' Navigator x position');
assessNumericValue(expectedY, navigator.offset().top, 4, ' Navigator y position'); Util.assessNumericValue(expectedY, navigator.offset().top, 4, ' Navigator y position');
}; };
var navigatorRegionBoundsInPoints = function () { var navigatorRegionBoundsInPoints = function () {
@ -113,10 +92,10 @@ QUnit.config.autostart = false;
var assessDisplayRegion = function (status) { var assessDisplayRegion = function (status) {
var expectedBounds = navigatorRegionBoundsInPoints(); var expectedBounds = navigatorRegionBoundsInPoints();
assessNumericValue(expectedBounds.width, displayRegion.width() + viewer.navigator.totalBorderWidths.x, 2, status + ' Width synchronization'); Util.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'); Util.assessNumericValue(expectedBounds.height, displayRegion.height() + viewer.navigator.totalBorderWidths.y, 2, status + ' Height synchronization');
assessNumericValue(expectedBounds.x, displayRegion.position().left, 2, status + ' Left synchronization'); Util.assessNumericValue(expectedBounds.x, displayRegion.position().left, 2, status + ' Left synchronization');
assessNumericValue(expectedBounds.y, displayRegion.position().top, 2, status + ' Top synchronization'); Util.assessNumericValue(expectedBounds.y, displayRegion.position().top, 2, status + ' Top synchronization');
}; };
var waitForViewer = function () { var waitForViewer = function () {
@ -138,11 +117,11 @@ QUnit.config.autostart = false;
viewerAndNavigatorDisplayReady = viewer.drawer !== null && viewerAndNavigatorDisplayReady = viewer.drawer !== null &&
!viewer.drawer.needsUpdate() && !viewer.drawer.needsUpdate() &&
currentDisplayWidth > 0 && currentDisplayWidth > 0 &&
equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, .0001) && Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, .0001) &&
equalsWithVariance(lastDisplayWidth, currentDisplayWidth, .0001) && Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, .0001) &&
equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, .0001) && Util.equalsWithVariance(viewer.viewport.getBounds(true).x, viewer.viewport.getBounds().x, .0001) &&
equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, .0001) && Util.equalsWithVariance(viewer.viewport.getBounds(true).y, viewer.viewport.getBounds().y, .0001) &&
equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, .0001); Util.equalsWithVariance(viewer.viewport.getBounds(true).width, viewer.viewport.getBounds().width, .0001);
} }
catch (err) { catch (err) {
//Ignore. Subsequent code will try again shortly //Ignore. Subsequent code will try again shortly
@ -213,10 +192,10 @@ QUnit.config.autostart = false;
expecteYCoordinate = 1 / viewer.source.aspectRatio - viewer.viewport.getBounds().height; expecteYCoordinate = 1 / viewer.source.aspectRatio - viewer.viewport.getBounds().height;
} }
if (viewer.viewport.getBounds().width < 1) { 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) { 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) { if (viewer.source.aspectRatio < 1) {
yPositionVariance = yPositionVariance / viewer.source.aspectRatio; yPositionVariance = yPositionVariance / viewer.source.aspectRatio;
} }
assessNumericValue(1 / viewer.source.aspectRatio / 2, viewer.viewport.getCenter().y, yPositionVariance, ' Viewer at center, y coord'); Util.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(.5, viewer.viewport.getCenter().x, .4, ' Viewer at center, x coord');
}; };
var clickOnNavigator = function (theContentCorner) { var clickOnNavigator = function (theContentCorner) {

View File

@ -28,8 +28,30 @@
.simulate('mouseover', event) .simulate('mouseover', event)
.simulate('mousedown', event) .simulate('mousedown', event)
.simulate('mouseup', 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);
} }
}; };
})(); })();