Significant improvments to API documentation. Allow what was an object literal OpenSeadragon to be used a function which provides a simplified interface for constructing a Viewer and TileSource by simple, documented configuration settings. Major performance improvements for touch on iPhone, hopefully all mobile devices.

This commit is contained in:
thatcher 2012-03-01 08:38:15 -05:00
parent 32c950e661
commit 3f6e8abbfc
7 changed files with 1362 additions and 820 deletions

View File

@ -6,7 +6,7 @@
PROJECT: openseadragon PROJECT: openseadragon
BUILD_MAJOR: 0 BUILD_MAJOR: 0
BUILD_MINOR: 9 BUILD_MINOR: 9
BUILD_ID: 16 BUILD_ID: 18
BUILD: ${PROJECT}.${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID} BUILD: ${PROJECT}.${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID}
VERSION: ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID} VERSION: ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,7 @@
(function( $ ){ (function( $ ){
// the max number of images we should keep in memory var TIMEOUT = 5000,
var QUOTA = 100,
// the most shrunk a tile should be
MIN_PIXEL_RATIO = 0.5,
//TODO: make TIMEOUT configurable
TIMEOUT = 5000,
BROWSER = $.Browser.vendor, BROWSER = $.Browser.vendor,
BROWSER_VERSION = $.Browser.version, BROWSER_VERSION = $.Browser.version,
@ -16,11 +11,13 @@ var QUOTA = 100,
( BROWSER == $.BROWSERS.OPERA ) || ( BROWSER == $.BROWSERS.OPERA ) ||
( BROWSER == $.BROWSERS.SAFARI && BROWSER_VERSION >= 4 ) || ( BROWSER == $.BROWSERS.SAFARI && BROWSER_VERSION >= 4 ) ||
( BROWSER == $.BROWSERS.CHROME && BROWSER_VERSION >= 2 ) ( BROWSER == $.BROWSERS.CHROME && BROWSER_VERSION >= 2 )
), ) && ( !navigator.appVersion.match( 'Mobile' ) ),
USE_CANVAS = $.isFunction( document.createElement( "canvas" ).getContext ) && USE_CANVAS = $.isFunction( document.createElement( "canvas" ).getContext ) &&
SUBPIXEL_RENDERING; SUBPIXEL_RENDERING;
//console.error( 'USE_CANVAS ' + USE_CANVAS );
/** /**
* @class * @class
* @param {OpenSeadragon.TileSource} source - Reference to Viewer tile source. * @param {OpenSeadragon.TileSource} source - Reference to Viewer tile source.
@ -44,27 +41,55 @@ var QUOTA = 100,
* @property {Boolean} updateAgain - Does the drawer need to update the viewort again? * @property {Boolean} updateAgain - Does the drawer need to update the viewort again?
* @property {Element} element - DEPRECATED Alias for container. * @property {Element} element - DEPRECATED Alias for container.
*/ */
$.Drawer = function( source, viewport, element ) { $.Drawer = function( options ) {
this.viewport = viewport; //backward compatibility for positional args while prefering more
this.source = source; //idiomatic javascript options object as the only argument
this.container = $.getElement( element ); var args = arguments;
if( !$.isPlainObject( options ) ){
options = {
source: args[ 0 ],
viewport: args[ 1 ],
element: args[ 2 ]
};
}
$.extend( true, this, {
//references to closely related openseadragon objects
//viewport: null,
//source: null,
//internal state properties
downloading: 0,
tilesMatrix: {},
tilesLoaded: [],
coverage: {},
overlays: [],
lastDrawn: [],
lastResetTime: 0,
midUpdate: false,
updateAgain: true,
//configurable settings
maxImageCacheCount: $.DEFAULT_SETTINGS.maxImageCacheCount,
imageLoaderLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
immediateRender: $.DEFAULT_SETTINGS.immediateRender,
blendTime: $.DEFAULT_SETTINGS.blendTime,
alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,
minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio
}, options );
this.container = $.getElement( this.element );
this.canvas = $.makeNeutralElement( USE_CANVAS ? "canvas" : "div" ); this.canvas = $.makeNeutralElement( USE_CANVAS ? "canvas" : "div" );
this.context = USE_CANVAS ? this.canvas.getContext( "2d" ) : null; this.context = USE_CANVAS ? this.canvas.getContext( "2d" ) : null;
this.config = this.viewport.config; this.normHeight = this.source.dimensions.y / this.source.dimensions.x;
this.normHeight = source.dimensions.y / source.dimensions.x;
this.downloading = 0;
this.tilesMatrix = {};
this.tilesLoaded = [];
this.coverage = {};
this.overlays = [];
this.lastDrawn = [];
this.lastResetTime = 0;
this.midUpdate = false;
this.updateAgain = true;
this.element = this.container; this.element = this.container;
this.canvas.style.width = "100%"; this.canvas.style.width = "100%";
this.canvas.style.height = "100%"; this.canvas.style.height = "100%";
this.canvas.style.position = "absolute"; this.canvas.style.position = "absolute";
@ -208,7 +233,7 @@ $.Drawer.prototype = {
* the local cache to optimize user experience in certain cases. Because * the local cache to optimize user experience in certain cases. Because
* the number of parallel image loads is configurable, if too many images * the number of parallel image loads is configurable, if too many images
* are currently being loaded, the request will be ignored. Since by * are currently being loaded, the request will be ignored. Since by
* default viewer.config.imageLoaderLimit is 0, the native browser parallel * default drawer.imageLoaderLimit is 0, the native browser parallel
* image loading policy will be used. * image loading policy will be used.
* @method * @method
* @param {String} src - The url of the image to load. * @param {String} src - The url of the image to load.
@ -217,7 +242,7 @@ $.Drawer.prototype = {
* For now this means the callback is expected to distinguish between * For now this means the callback is expected to distinguish between
* error and success conditions by inspecting the Image object. * error and success conditions by inspecting the Image object.
* @return {Boolean} loading - Wheter the request was submitted or ignored * @return {Boolean} loading - Wheter the request was submitted or ignored
* based on viewer.config.imageLoaderLimit. * based on OpenSeadragon.DEFAULT_SETTINGS.imageLoaderLimit.
*/ */
loadImage: function( src, callback ) { loadImage: function( src, callback ) {
var _this = this, var _this = this,
@ -226,8 +251,8 @@ $.Drawer.prototype = {
jobid, jobid,
complete; complete;
if ( !this.config.imageLoaderLimit || if ( !this.imageLoaderLimit ||
this.downloading < this.config.imageLoaderLimit ) { this.downloading < this.imageLoaderLimit ) {
this.downloading++; this.downloading++;
@ -297,14 +322,14 @@ function updateViewport( drawer ) {
lowestLevel = Math.max( lowestLevel = Math.max(
drawer.source.minLevel, drawer.source.minLevel,
Math.floor( Math.floor(
Math.log( drawer.config.minZoomImageRatio ) / Math.log( drawer.minZoomImageRatio ) /
Math.log( 2 ) Math.log( 2 )
) )
), ),
highestLevel = Math.min( highestLevel = Math.min(
drawer.source.maxLevel, drawer.source.maxLevel,
Math.floor( Math.floor(
Math.log( zeroRatioC / MIN_PIXEL_RATIO ) / Math.log( zeroRatioC / drawer.minPixelRatio ) /
Math.log( 2 ) Math.log( 2 )
) )
), ),
@ -330,21 +355,21 @@ function updateViewport( drawer ) {
} }
//TODO //TODO
if ( !drawer.config.wrapHorizontal && if ( !drawer.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) { ( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return; return;
} else if } else if
( !drawer.config.wrapVertical && ( !drawer.wrapVertical &&
( viewportBR.y < 0 || viewportTL.y > drawer.normHeight ) ) { ( viewportBR.y < 0 || viewportTL.y > drawer.normHeight ) ) {
return; return;
} }
//TODO //TODO
if ( !drawer.config.wrapHorizontal ) { if ( !drawer.wrapHorizontal ) {
viewportTL.x = Math.max( viewportTL.x, 0 ); viewportTL.x = Math.max( viewportTL.x, 0 );
viewportBR.x = Math.min( viewportBR.x, 1 ); viewportBR.x = Math.min( viewportBR.x, 1 );
} }
if ( !drawer.config.wrapVertical ) { if ( !drawer.wrapVertical ) {
viewportTL.y = Math.max( viewportTL.y, 0 ); viewportTL.y = Math.max( viewportTL.y, 0 );
viewportBR.y = Math.min( viewportBR.y, drawer.normHeight ); viewportBR.y = Math.min( viewportBR.y, drawer.normHeight );
} }
@ -361,7 +386,7 @@ function updateViewport( drawer ) {
true true
).x; ).x;
if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) || if ( ( !haveDrawn && renderPixelRatioC >= drawer.minPixelRatio ) ||
( level == lowestLevel ) ) { ( level == lowestLevel ) ) {
drawLevel = true; drawLevel = true;
haveDrawn = true; haveDrawn = true;
@ -379,7 +404,7 @@ function updateViewport( drawer ) {
false false
).x; ).x;
optimalRatio = drawer.config.immediateRender ? optimalRatio = drawer.immediateRender ?
1 : 1 :
zeroRatioT; zeroRatioT;
@ -437,10 +462,10 @@ function updateLevel( drawer, haveDrawn, level, levelOpacity, levelVisibility, v
resetCoverage( drawer.coverage, level ); resetCoverage( drawer.coverage, level );
if ( !drawer.config.wrapHorizontal ) { if ( !drawer.wrapHorizontal ) {
tileBR.x = Math.min( tileBR.x, numberOfTiles.x - 1 ); tileBR.x = Math.min( tileBR.x, numberOfTiles.x - 1 );
} }
if ( !drawer.config.wrapVertical ) { if ( !drawer.wrapVertical ) {
tileBR.y = Math.min( tileBR.y, numberOfTiles.y - 1 ); tileBR.y = Math.min( tileBR.y, numberOfTiles.y - 1 );
} }
@ -609,7 +634,7 @@ function onTileLoad( drawer, tile, time, image ) {
insertionIndex = drawer.tilesLoaded.length; insertionIndex = drawer.tilesLoaded.length;
if ( drawer.tilesLoaded.length >= QUOTA ) { if ( drawer.tilesLoaded.length >= drawer.maxImageCacheCount ) {
cutoff = Math.ceil( Math.log( drawer.source.tileSize ) / Math.log( 2 ) ); cutoff = Math.ceil( Math.log( drawer.source.tileSize ) / Math.log( 2 ) );
worstTile = null; worstTile = null;
@ -671,7 +696,7 @@ function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility
function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){ function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
var blendTimeMillis = 1000 * drawer.config.blendTime, var blendTimeMillis = 1000 * drawer.blendTime,
deltaTime, deltaTime,
opacity; opacity;
@ -682,7 +707,7 @@ function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
deltaTime = currentTime - tile.blendStart; deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / blendTimeMillis ); opacity = Math.min( 1, deltaTime / blendTimeMillis );
if ( drawer.config.alwaysBlend ) { if ( drawer.alwaysBlend ) {
opacity *= levelOpacity; opacity *= levelOpacity;
} }

View File

@ -59,18 +59,138 @@
**/ **/
/** /**
* The root namespace for OpenSeadragon. All utility methods and classes * The root namespace for OpenSeadragon, this function also serves as a single
* are defined on or below this namespace. The OpenSeadragon namespace will * point of instantiation for an {@link OpenSeadragon.Viewer}, including all
* only be defined once even if mutliple versions are loaded on the page in * combinations of out-of-the-box configurable features. All utility methods
* succession. * and classes are defined on or below this namespace.
*
* @namespace * @namespace
* @function
* @name OpenSeadragon * @name OpenSeadragon
* @exports $ as OpenSeadragon * @exports $ as OpenSeadragon
*
* @param {Object} options All required and optional settings for instantiating
* a new instance of an OpenSeadragon image viewer.
*
* @param {String} options.xmlPath
* DEPRECATED. A relative path to load a DZI file from the server.
* Prefer the newer options.tileSources.
*
* @param {Array|String|Function|Object[]|Array[]|String[]|Function[]} options.tileSources
* As an Array, the tileSource can hold either be all Objects or mixed
* types of Arrays of Objects, String, Function. When a value is a String,
* the tileSource is used to create a {@link OpenSeadragon.DziTileSource}.
* When a value is a Function, the function is used to create a new
* {@link OpenSeadragon.TileSource} whose abstract method
* getUrl( level, x, y ) is implemented by the function. Finally, when it
* is an Array of objects, it is used to create a
* {@link OpenSeadragon.LegacyTileSource}.
*
* @param {Boolean} [options.debugMode=true]
* Currently does nothing. TODO: provide an in-screen panel providing event
* detail feedback.
*
* @param {Number} [options.animationTime=1.5]
* Specifies the animation duration per each {@link OpenSeadragon.Spring}
* which occur when the image is dragged or zoomed.
*
* @param {Number} [options.blendTime=0.5]
* Specifies the duration of animation as higher or lower level tiles are
* replacing the existing tile.
*
* @param {Boolean} [options.alwaysBlend=false]
* Forces the tile to always blend. By default the tiles skip blending
* when the blendTime is surpassed and the current animation frame would
* not complete the blend.
*
* @param {Boolean} [options.autoHideControls=true]
* If the user stops interacting with the viewport, fade the navigation
* controls. Useful for presentation since the controls are by default
* floated on top of the image the user is viewing.
*
* @param {Boolean} [options.immediateRender=false]
*
* @param {Boolean} [options.wrapHorizontal=false]
* Should the image wrap horizontally within the viewport. Useful for
* maps or images representing the surface of a sphere or cylinder.
*
* @param {Boolean} [options.wrapVertical=false]
* Should the image wrap vertically within the viewport. Useful for
* maps or images representing the surface of a sphere or cylinder.
*
* @param {Number} [options.minZoomImageRatio=0.8]
* @param {Number} [options.maxZoomPixelRatio=2]
*
* @param {Number} [options.visibilityRatio=0.5]
* The percentage ( as a number from 0 to 1 ) of the source image which
* must be kept within the viewport. If the image is dragged beyond that
* limit, it will 'bounce' back until the minimum visibility ration is
* achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to
* true will provide the effect of an infinitely scrolling viewport.
*
* @param {Number} [options.springStiffness=5.0]
* @param {Number} [options.imageLoaderLimit=0]
* @param {Number} [options.clickTimeThreshold=200]
* @param {Number} [options.clickDistThreshold=5]
* @param {Number} [options.zoomPerClick=2.0]
* @param {Number} [options.zoomPerScroll=1.2]
* @param {Number} [options.zoomPerSecond=2.0]
*
* @param {Boolean} [options.showNavigationControl=true]
*
* @param {Number} [options.controlsFadeDelay=2000]
* The number of milliseconds to wait once the user has stopped interacting
* with the interface before begining to fade the controls. Assumes
* showNavigationControl and autoHideControls are both true.
*
* @param {Number} [options.controlsFadeLength=1500]
* The number of milliseconds to animate the controls fading out.
*
* @param {Number} [options.maxImageCacheCount=100]
* The max number of images we should keep in memory (per drawer).
*
* @param {Number} [options.minPixelRatio=0.5]
* The higher the minPixelRatio, the lower the quality of the image that
* is considered sufficient to stop rendering a given zoom level. For
* example, if you are targeting mobile devices with less bandwith you may
* try setting this to 1.5 or higher.
*
* @param {Boolean} [options.mouseNavEnabled=true]
* Is the user able to interact with the image via mouse or touch. Default
* interactions include draging the image in a plane, and zooming in toward
* and away from the image.
*
* @param {String} [options.prefixUrl='']
* Appends the prefixUrl to navImages paths, which is very useful
* since the default paths are rarely useful for production
* environments.
*
* @param {Object} [options.navImages=]
* An object with a property for each button or other built-in navigation
* control, eg the current 'zoomIn', 'zoomOut', 'home', and 'fullpage'.
* Each of those in turn provides an image path for each state of the botton
* or navigation control, eg 'REST', 'GROUP', 'HOVER', 'PRESS'. Finally the
* image paths, by default assume there is a folder on the servers root path
* called '/images', eg '/images/zoomin_rest.png'. If you need to adjust
* these paths, prefer setting the option.prefixUrl rather than overriding
* every image path directly through this setting.
*
* @returns {OpenSeadragon.Viewer}
*/ */
OpenSeadragon = window.OpenSeadragon || (function(){ OpenSeadragon = window.OpenSeadragon || function( options ){
//Taken from jquery 1.6.1 return new OpenSeadragon.Viewer( options );
// [[Class]] -> type pairs
};
(function( $ ){
/**
* Taken from jquery 1.6.1
* [[Class]] -> type pairs
* @private
*/
var class2type = { var class2type = {
'[object Boolean]': 'boolean', '[object Boolean]': 'boolean',
'[object Number]': 'number', '[object Number]': 'number',
@ -89,89 +209,65 @@ OpenSeadragon = window.OpenSeadragon || (function(){
trim = String.prototype.trim, trim = String.prototype.trim,
indexOf = Array.prototype.indexOf; indexOf = Array.prototype.indexOf;
return {
DEFAULT_SETTINGS: { /**
debugMode: true, * Taken from jQuery 1.6.1
animationTime: 1.5, * @name $.isFunction
blendTime: 0.5, * @function
alwaysBlend: false, * @see <a href='http://www.jquery.com/'>jQuery</a>
autoHideControls: true, */
immediateRender: false, $.isFunction = function( obj ) {
wrapHorizontal: false, return $.type(obj) === "function";
wrapVertical: false, };
minZoomImageRatio: 0.8,
maxZoomPixelRatio: 2,
visibilityRatio: 0.5,
springStiffness: 5.0,
imageLoaderLimit: 0,
clickTimeThreshold: 200,
clickDistThreshold: 5,
zoomPerClick: 2.0,
zoomPerScroll: 1.2,
zoomPerSecond: 2.0,
showNavigationControl: true,
controlsFadeDelay: 2000,
controlsFadeLength: 1500,
maxImageCacheCount: 100,
minPixelRatio: 0.5,
mouseNavEnabled: true,
prefixUrl: null,
navImages: {
zoomIn: {
REST: '/images/zoomin_rest.png',
GROUP: '/images/zoomin_grouphover.png',
HOVER: '/images/zoomin_hover.png',
DOWN: '/images/zoomin_pressed.png'
},
zoomOut: {
REST: '/images/zoomout_rest.png',
GROUP: '/images/zoomout_grouphover.png',
HOVER: '/images/zoomout_hover.png',
DOWN: '/images/zoomout_pressed.png'
},
home: {
REST: '/images/home_rest.png',
GROUP: '/images/home_grouphover.png',
HOVER: '/images/home_hover.png',
DOWN: '/images/home_pressed.png'
},
fullpage: {
REST: '/images/fullpage_rest.png',
GROUP: '/images/fullpage_grouphover.png',
HOVER: '/images/fullpage_hover.png',
DOWN: '/images/fullpage_pressed.png'
}
}
},
// See test/unit/core.js for details concerning isFunction.
// Since version 1.3, DOM methods and functions like alert
// aren't supported. They return false on IE (#2968).
isFunction: function( obj ) {
return OpenSeadragon.type(obj) === "function";
},
isArray: Array.isArray || function( obj ) { /**
return OpenSeadragon.type(obj) === "array"; * Taken from jQuery 1.6.1
}, * @name $.isArray
* @function
* @see <a href='http://www.jquery.com/'>jQuery</a>
*/
$.isArray = Array.isArray || function( obj ) {
return $.type(obj) === "array";
};
// A crude way of determining if an object is a window
isWindow: function( obj ) { /**
* A crude way of determining if an object is a window.
* Taken from jQuery 1.6.1
* @name $.isWindow
* @function
* @see <a href='http://www.jquery.com/'>jQuery</a>
*/
$.isWindow = function( obj ) {
return obj && typeof obj === "object" && "setInterval" in obj; return obj && typeof obj === "object" && "setInterval" in obj;
}, };
type: function( obj ) {
/**
* Taken from jQuery 1.6.1
* @name $.type
* @function
* @see <a href='http://www.jquery.com/'>jQuery</a>
*/
$.type = function( obj ) {
return obj == null ? return obj == null ?
String( obj ) : String( obj ) :
class2type[ toString.call(obj) ] || "object"; class2type[ toString.call(obj) ] || "object";
}, };
isPlainObject: function( obj ) {
/**
* Taken from jQuery 1.6.1
* @name $.isPlainObject
* @function
* @see <a href='http://www.jquery.com/'>jQuery</a>
*/
$.isPlainObject = function( obj ) {
// Must be an Object. // Must be an Object.
// Because of IE, we also have to check the presence of the constructor property. // Because of IE, we also have to check the presence of the constructor property.
// Make sure that DOM nodes and window objects don't pass through, as well // Make sure that DOM nodes and window objects don't pass through, as well
if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || OpenSeadragon.isWindow( obj ) ) { if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || $.isWindow( obj ) ) {
return false; return false;
} }
@ -189,42 +285,42 @@ OpenSeadragon = window.OpenSeadragon || (function(){
for ( key in obj ) {} for ( key in obj ) {}
return key === undefined || hasOwn.call( obj, key ); return key === undefined || hasOwn.call( obj, key );
}, };
isEmptyObject: function( obj ) {
/**
* Taken from jQuery 1.6.1
* @name $.isEmptyObject
* @function
* @see <a href='http://www.jquery.com/'>jQuery</a>
*/
$.isEmptyObject = function( obj ) {
for ( var name in obj ) { for ( var name in obj ) {
return false; return false;
} }
return true; return true;
}
}; };
}());
}( OpenSeadragon ));
/**
* This closure defines all static methods available to the OpenSeadragon
* namespace. Many, if not most, are taked directly from jQuery for use
* to simplify and reduce common programming patterns. More static methods
* from jQuery may eventually make their way into this though we are
* attempting to avoid substaintial plagarism or the more explicit dependency
* on jQuery only because OpenSeadragon is a broadly useful code base and
* would be made less broad by requiring jQuery fully.
*
* Some static methods have also been refactored from the original OpenSeadragon
* project.
*/
(function( $ ){ (function( $ ){
/** /**
* @static * Taken from jQuery 1.6.1
* @ignore * @see <a href='http://www.jquery.com/'>jQuery</a>
*/
$.SIGNAL = "----seadragon----";
/**
* Invokes the the method as if it where a method belonging to the object.
* @param {Object} object
* @param {Function} method
*/
$.delegate = function( object, method ) {
return function() {
if ( arguments === undefined )
arguments = [];
return method.apply( object, arguments );
};
};
/**
* Taken from jQuery 1.6.1, see the jQuery documentation
*/ */
$.extend = function() { $.extend = function() {
var options, var options,
@ -295,151 +391,114 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return target; return target;
}; };
//The following functions are originally from the Openseadragon Utils
//module but have been moved to Openseadragon to avoid the 'Utils' anti- $.extend( $, {
//pattern. Not all of the code is A-grade compared to equivalent functions /**
// from libraries like jquery, but until we need better we'll leave those * These are the default values for the optional settings documented
//orignally developed by the project. * in the {@link OpenSeadragon} constructor detail.
* @name $.DEFAULT_SETTINGS
* @static
*/
DEFAULT_SETTINGS: {
xmlPath: null,
tileSources: null,
debugMode: true,
animationTime: 1.5,
blendTime: 0.5,
alwaysBlend: false,
autoHideControls: true,
immediateRender: false,
wrapHorizontal: false,
wrapVertical: false,
minZoomImageRatio: 0.8,
maxZoomPixelRatio: 2,
visibilityRatio: 0.5,
springStiffness: 5.0,
imageLoaderLimit: 0,
clickTimeThreshold: 200,
clickDistThreshold: 5,
zoomPerClick: 2.0,
zoomPerScroll: 1.2,
zoomPerSecond: 2.0,
showNavigationControl: true,
//These two were referenced but never defined
controlsFadeDelay: 2000,
controlsFadeLength: 1500,
maxImageCacheCount: 100,
minPixelRatio: 0.5,
mouseNavEnabled: true,
prefixUrl: null,
navImages: {
zoomIn: {
REST: '/images/zoomin_rest.png',
GROUP: '/images/zoomin_grouphover.png',
HOVER: '/images/zoomin_hover.png',
DOWN: '/images/zoomin_pressed.png'
},
zoomOut: {
REST: '/images/zoomout_rest.png',
GROUP: '/images/zoomout_grouphover.png',
HOVER: '/images/zoomout_hover.png',
DOWN: '/images/zoomout_pressed.png'
},
home: {
REST: '/images/home_rest.png',
GROUP: '/images/home_grouphover.png',
HOVER: '/images/home_hover.png',
DOWN: '/images/home_pressed.png'
},
fullpage: {
REST: '/images/fullpage_rest.png',
GROUP: '/images/fullpage_grouphover.png',
HOVER: '/images/fullpage_hover.png',
DOWN: '/images/fullpage_pressed.png'
}
}
},
/**
* TODO: get rid of this. I can't see how it's required at all. Looks
* like an early legacy code artifact.
* @static
* @ignore
*/
SIGNAL: "----seadragon----",
/**
* Invokes the the method as if it where a method belonging to the object.
* @name $.delegate
* @function
* @param {Object} object
* @param {Function} method
*/
delegate: function( object, method ) {
return function() {
if ( arguments === undefined )
arguments = [];
return method.apply( object, arguments );
};
},
/** /**
* An enumeration of Browser vendors including UNKNOWN, IE, FIREFOX, * An enumeration of Browser vendors including UNKNOWN, IE, FIREFOX,
* SAFARI, CHROME, and OPERA. * SAFARI, CHROME, and OPERA.
* @name $.BROWSERS
* @static * @static
*/ */
$.BROWSERS = { BROWSERS: {
UNKNOWN: 0, UNKNOWN: 0,
IE: 1, IE: 1,
FIREFOX: 2, FIREFOX: 2,
SAFARI: 3, SAFARI: 3,
CHROME: 4, CHROME: 4,
OPERA: 5 OPERA: 5
};
/**
* The current browser vendor, version, and related information regarding
* detected features. Features include <br/>
* <strong>'alpha'</strong> - Does the browser support image alpha
* transparency.<br/>
* @static
*/
$.Browser = {
vendor: $.BROWSERS.UNKNOWN,
version: 0,
alpha: true
};
var ACTIVEX = [
"Msxml2.XMLHTTP",
"Msxml3.XMLHTTP",
"Microsoft.XMLHTTP"
],
FILEFORMATS = {
"bmp": false,
"jpeg": true,
"jpg": true,
"png": true,
"tif": false,
"wdp": false
}, },
URLPARAMS = {};
(function() {
//A small auto-executing routine to determine the browser vendor,
//version and supporting feature sets.
var app = navigator.appName,
ver = navigator.appVersion,
ua = navigator.userAgent;
switch( navigator.appName ){
case "Microsoft Internet Explorer":
if( !!window.attachEvent &&
!!window.ActiveXObject ) {
$.Browser.vendor = $.BROWSERS.IE;
$.Browser.version = parseFloat(
ua.substring(
ua.indexOf( "MSIE" ) + 5,
ua.indexOf( ";", ua.indexOf( "MSIE" ) ) )
);
}
break;
case "Netscape":
if( !!window.addEventListener ){
if ( ua.indexOf( "Firefox" ) >= 0 ) {
$.Browser.vendor = $.BROWSERS.FIREFOX;
$.Browser.version = parseFloat(
ua.substring( ua.indexOf( "Firefox" ) + 8 )
);
} else if ( ua.indexOf( "Safari" ) >= 0 ) {
$.Browser.vendor = ua.indexOf( "Chrome" ) >= 0 ?
$.BROWSERS.CHROME :
$.BROWSERS.SAFARI;
$.Browser.version = parseFloat(
ua.substring(
ua.substring( 0, ua.indexOf( "Safari" ) ).lastIndexOf( "/" ) + 1,
ua.indexOf( "Safari" )
)
);
}
}
break;
case "Opera":
$.Browser.vendor = $.BROWSERS.OPERA;
$.Browser.version = parseFloat( ver );
break;
}
// ignore '?' portion of query string
var query = window.location.search.substring( 1 ),
parts = query.split('&'),
part,
sep,
i;
for ( i = 0; i < parts.length; i++ ) {
part = parts[ i ];
sep = part.indexOf( '=' );
if ( sep > 0 ) {
URLPARAMS[ part.substring( 0, sep ) ] =
decodeURIComponent( part.substring( sep + 1 ) );
}
}
//determine if this browser supports image alpha transparency
$.Browser.alpha = !(
$.Browser.vendor == $.BROWSERS.IE || (
$.Browser.vendor == $.BROWSERS.CHROME &&
$.Browser.version < 2
)
);
})();
//TODO: $.console is often used inside a try/catch block which generally
// prevents allowings errors to occur with detection until a debugger
// is attached. Although I've been guilty of the same anti-pattern
// I eventually was convinced that errors should naturally propogate in
// all but the most special cases.
/**
* A convenient alias for console when available, and a simple null
* function when console is unavailable.
* @static
* @private
*/
var nullfunction = function( msg ){
//document.location.hash = msg;
};
$.console = window.console || {
log: nullfunction,
debug: nullfunction,
info: nullfunction,
warn: nullfunction,
error: nullfunction
};
$.extend( $, {
/** /**
* Returns a DOM Element for the given id or element. * Returns a DOM Element for the given id or element.
@ -455,6 +514,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element; return element;
}, },
/** /**
* Determines the position of the upper-left corner of the element. * Determines the position of the upper-left corner of the element.
* @function * @function
@ -488,6 +548,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result; return result;
}, },
/** /**
* Determines the height and width of the given element. * Determines the height and width of the given element.
* @function * @function
@ -504,6 +565,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
); );
}, },
/** /**
* Returns the CSSStyle object for the given element. * Returns the CSSStyle object for the given element.
* @function * @function
@ -523,6 +585,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
} }
}, },
/** /**
* Gets the latest event, really only useful internally since its * Gets the latest event, really only useful internally since its
* specific to IE behavior. TODO: Deprecate this from the api and * specific to IE behavior. TODO: Deprecate this from the api and
@ -536,6 +599,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return event ? event : window.event; return event ? event : window.event;
}, },
/** /**
* Gets the position of the mouse on the screen for a given event. * Gets the position of the mouse on the screen for a given event.
* @function * @function
@ -569,6 +633,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result; return result;
}, },
/** /**
* Determines the pages current scroll position. * Determines the pages current scroll position.
* @function * @function
@ -594,6 +659,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result; return result;
}, },
/** /**
* Determines the size of the browsers window. * Determines the size of the browsers window.
* @function * @function
@ -667,6 +733,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return div; return div;
}, },
/** /**
* Creates an easily positionable element of the given type that therefor * Creates an easily positionable element of the given type that therefor
* serves as an excellent container element. * serves as an excellent container element.
@ -688,6 +755,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element; return element;
}, },
/** /**
* Ensures an image is loaded correctly to support alpha transparency. * Ensures an image is loaded correctly to support alpha transparency.
* Generally only IE has issues doing this correctly for formats like * Generally only IE has issues doing this correctly for formats like
@ -731,6 +799,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element; return element;
}, },
/** /**
* Sets the opacity of the specified element. * Sets the opacity of the specified element.
* @function * @function
@ -779,6 +848,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
} }
}, },
/** /**
* Adds an event listener for the given element, eventName and handler. * Adds an event listener for the given element, eventName and handler.
* @function * @function
@ -808,6 +878,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
} }
}, },
/** /**
* Remove a given event listener for the given element, event type and * Remove a given event listener for the given element, event type and
* handler. * handler.
@ -838,6 +909,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
} }
}, },
/** /**
* Cancels the default browser behavior had the event propagated all * Cancels the default browser behavior had the event propagated all
* the way up the DOM to the window object. * the way up the DOM to the window object.
@ -858,6 +930,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
event.returnValue = false; event.returnValue = false;
}, },
/** /**
* Stops the propagation of the event up the DOM. * Stops the propagation of the event up the DOM.
* @function * @function
@ -874,6 +947,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
event.cancelBubble = true; // IE for stopping propagation event.cancelBubble = true; // IE for stopping propagation
}, },
/** /**
* Similar to OpenSeadragon.delegate, but it does not immediately call * Similar to OpenSeadragon.delegate, but it does not immediately call
* the method on the object, returning a function which can be called * the method on the object, returning a function which can be called
@ -910,6 +984,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}; };
}, },
/** /**
* Retreives the value of a url parameter from the window.location string. * Retreives the value of a url parameter from the window.location string.
* @function * @function
@ -922,6 +997,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return value ? value : null; return value ? value : null;
}, },
/** /**
* Makes an AJAX request. * Makes an AJAX request.
* @function * @function
@ -1077,6 +1153,138 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}); });
/**
* The current browser vendor, version, and related information regarding
* detected features. Features include <br/>
* <strong>'alpha'</strong> - Does the browser support image alpha
* transparency.<br/>
* @name $.Browser
* @static
*/
$.Browser = {
vendor: $.BROWSERS.UNKNOWN,
version: 0,
alpha: true
};
var ACTIVEX = [
"Msxml2.XMLHTTP",
"Msxml3.XMLHTTP",
"Microsoft.XMLHTTP"
],
FILEFORMATS = {
"bmp": false,
"jpeg": true,
"jpg": true,
"png": true,
"tif": false,
"wdp": false
},
URLPARAMS = {};
(function() {
//A small auto-executing routine to determine the browser vendor,
//version and supporting feature sets.
var app = navigator.appName,
ver = navigator.appVersion,
ua = navigator.userAgent;
//console.error( 'appName: ' + navigator.appName );
//console.error( 'appVersion: ' + navigator.appVersion );
//console.error( 'userAgent: ' + navigator.userAgent );
switch( navigator.appName ){
case "Microsoft Internet Explorer":
if( !!window.attachEvent &&
!!window.ActiveXObject ) {
$.Browser.vendor = $.BROWSERS.IE;
$.Browser.version = parseFloat(
ua.substring(
ua.indexOf( "MSIE" ) + 5,
ua.indexOf( ";", ua.indexOf( "MSIE" ) ) )
);
}
break;
case "Netscape":
if( !!window.addEventListener ){
if ( ua.indexOf( "Firefox" ) >= 0 ) {
$.Browser.vendor = $.BROWSERS.FIREFOX;
$.Browser.version = parseFloat(
ua.substring( ua.indexOf( "Firefox" ) + 8 )
);
} else if ( ua.indexOf( "Safari" ) >= 0 ) {
$.Browser.vendor = ua.indexOf( "Chrome" ) >= 0 ?
$.BROWSERS.CHROME :
$.BROWSERS.SAFARI;
$.Browser.version = parseFloat(
ua.substring(
ua.substring( 0, ua.indexOf( "Safari" ) ).lastIndexOf( "/" ) + 1,
ua.indexOf( "Safari" )
)
);
}
}
break;
case "Opera":
$.Browser.vendor = $.BROWSERS.OPERA;
$.Browser.version = parseFloat( ver );
break;
}
// ignore '?' portion of query string
var query = window.location.search.substring( 1 ),
parts = query.split('&'),
part,
sep,
i;
for ( i = 0; i < parts.length; i++ ) {
part = parts[ i ];
sep = part.indexOf( '=' );
if ( sep > 0 ) {
URLPARAMS[ part.substring( 0, sep ) ] =
decodeURIComponent( part.substring( sep + 1 ) );
}
}
//determine if this browser supports image alpha transparency
$.Browser.alpha = !(
$.Browser.vendor == $.BROWSERS.IE || (
$.Browser.vendor == $.BROWSERS.CHROME &&
$.Browser.version < 2
)
);
})();
//TODO: $.console is often used inside a try/catch block which generally
// prevents allowings errors to occur with detection until a debugger
// is attached. Although I've been guilty of the same anti-pattern
// I eventually was convinced that errors should naturally propogate in
// all but the most special cases.
/**
* A convenient alias for console when available, and a simple null
* function when console is unavailable.
* @static
* @private
*/
var nullfunction = function( msg ){
//document.location.hash = msg;
};
$.console = window.console || {
log: nullfunction,
debug: nullfunction,
info: nullfunction,
warn: nullfunction,
error: nullfunction
};
/** /**
* @private * @private
* @inner * @inner

View File

@ -7,9 +7,9 @@
* @param {Number} x The vector component 'x'. * @param {Number} x The vector component 'x'.
* @param {Number} y The vector component 'y'. * @param {Number} y The vector component 'y'.
* @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized * @param {OpenSeadragon.Point} bounds Where this tile fits, in normalized
* coordinates * coordinates.
* @param {Boolean} exists Is this tile a part of a sparse image? ( Also has * @param {Boolean} exists Is this tile a part of a sparse image? ( Also has
* this tile failed to load? * this tile failed to load? )
* @param {String} url The URL of this tile's image. * @param {String} url The URL of this tile's image.
* *
* @property {Number} level The zoom level this tile belongs to. * @property {Number} level The zoom level this tile belongs to.

View File

@ -35,6 +35,8 @@ $.Viewer = function( options ) {
$.EventHandler.call( this ); $.EventHandler.call( this );
//backward compatibility for positional args while prefering more
//idiomatic javascript options object as the only argument
if( !$.isPlainObject( options ) ){ if( !$.isPlainObject( options ) ){
options = { options = {
id: args[ 0 ], id: args[ 0 ],
@ -42,29 +44,29 @@ $.Viewer = function( options ) {
prefixUrl: args.length > 2 ? args[ 2 ] : undefined, prefixUrl: args.length > 2 ? args[ 2 ] : undefined,
controls: args.length > 3 ? args[ 3 ] : undefined, controls: args.length > 3 ? args[ 3 ] : undefined,
overlays: args.length > 4 ? args[ 4 ] : undefined, overlays: args.length > 4 ? args[ 4 ] : undefined,
overlayControls: args.length > 5 ? args[ 5 ] : undefined, overlayControls: args.length > 5 ? args[ 5 ] : undefined
config: {}
}; };
} }
//options.config and the general config argument are deprecated
//in favor of the more direct specification of optional settings
//being pass directly on the options object
if ( options.config ){
$.extend( true, options, options.config );
delete options.config;
}
//Allow the options object to override global defaults //Allow the options object to override global defaults
$.extend( true, this, { $.extend( true, this, {
id: options.id, id: options.id,
xmlPath: null, hash: options.id,
tileSources: null,
controls: [], controls: [],
overlays: [], overlays: [],
overlayControls: [], overlayControls: [],
config: $.DEFAULT_SETTINGS,
//These were referenced but never defined //private state properties
previousBody: [],
//These are originally not part options but declared as members
//in initialize. Its still considered idiomatic to put them here
source: null,
drawer: null,
viewport: null,
profiler: null,
//This was originally initialized in the constructor and so could never //This was originally initialized in the constructor and so could never
//have anything in it. now it can because we allow it to be specified //have anything in it. now it can because we allow it to be specified
@ -72,11 +74,18 @@ $.Viewer = function( options ) {
//this array was returned from get_controls which I find confusing //this array was returned from get_controls which I find confusing
//since this object has a controls property which is treated in other //since this object has a controls property which is treated in other
//functions like clearControls. I'm removing the accessors. //functions like clearControls. I'm removing the accessors.
customControls: [] customControls: [],
}, options ); //These are originally not part options but declared as members
//in initialize. Its still considered idiomatic to put them here
source: null,
drawer: null,
viewport: null,
profiler: null
this.element = document.getElementById( options.id ); }, $.DEFAULT_SETTINGS, options );
this.element = document.getElementById( this.id );
this.container = $.makeNeutralElement( "div" ); this.container = $.makeNeutralElement( "div" );
this.canvas = $.makeNeutralElement( "div" ); this.canvas = $.makeNeutralElement( "div" );
@ -87,9 +96,6 @@ $.Viewer = function( options ) {
this.bodyHeight = document.body.style.height; this.bodyHeight = document.body.style.height;
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.previousBody = [];
this.hash = Math.random();
THIS[ this.hash ] = { THIS[ this.hash ] = {
"fsBoundsDelta": new $.Point( 1, 1 ), "fsBoundsDelta": new $.Point( 1, 1 ),
@ -103,8 +109,8 @@ $.Viewer = function( options ) {
this.innerTracker = new $.MouseTracker({ this.innerTracker = new $.MouseTracker({
element: this.canvas, element: this.canvas,
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
clickHandler: $.delegate( this, onCanvasClick ), clickHandler: $.delegate( this, onCanvasClick ),
dragHandler: $.delegate( this, onCanvasDrag ), dragHandler: $.delegate( this, onCanvasDrag ),
releaseHandler: $.delegate( this, onCanvasRelease ), releaseHandler: $.delegate( this, onCanvasRelease ),
@ -113,8 +119,8 @@ $.Viewer = function( options ) {
this.outerTracker = new $.MouseTracker({ this.outerTracker = new $.MouseTracker({
element: this.container, element: this.container,
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
enterHandler: $.delegate( this, onContainerEnter ), enterHandler: $.delegate( this, onContainerEnter ),
exitHandler: $.delegate( this, onContainerExit ), exitHandler: $.delegate( this, onContainerExit ),
releaseHandler: $.delegate( this, onContainerRelease ) releaseHandler: $.delegate( this, onContainerRelease )
@ -180,15 +186,15 @@ $.Viewer = function( options ) {
doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ), doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ),
onHomeHandler = $.delegate( this, onHome ), onHomeHandler = $.delegate( this, onHome ),
onFullPageHandler = $.delegate( this, onFullPage ), onFullPageHandler = $.delegate( this, onFullPage ),
navImages = this.config.navImages, navImages = this.navImages,
zoomIn = new $.Button({ zoomIn = new $.Button({
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.ZoomIn" ), tooltip: $.getString( "Tooltips.ZoomIn" ),
srcRest: resolveUrl( this.config.prefixUrl, navImages.zoomIn.REST ), srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ),
srcGroup: resolveUrl( this.config.prefixUrl, navImages.zoomIn.GROUP ), srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ),
srcHover: resolveUrl( this.config.prefixUrl, navImages.zoomIn.HOVER ), srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ),
srcDown: resolveUrl( this.config.prefixUrl, navImages.zoomIn.DOWN ), srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ),
onPress: beginZoomingInHandler, onPress: beginZoomingInHandler,
onRelease: endZoomingHandler, onRelease: endZoomingHandler,
onClick: doSingleZoomInHandler, onClick: doSingleZoomInHandler,
@ -196,13 +202,13 @@ $.Viewer = function( options ) {
onExit: endZoomingHandler onExit: endZoomingHandler
}), }),
zoomOut = new $.Button({ zoomOut = new $.Button({
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.ZoomOut" ), tooltip: $.getString( "Tooltips.ZoomOut" ),
srcRest: resolveUrl( this.config.prefixUrl, navImages.zoomOut.REST ), srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ),
srcGroup: resolveUrl( this.config.prefixUrl, navImages.zoomOut.GROUP ), srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ),
srcHover: resolveUrl( this.config.prefixUrl, navImages.zoomOut.HOVER ), srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ),
srcDown: resolveUrl( this.config.prefixUrl, navImages.zoomOut.DOWN ), srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ),
onPress: beginZoomingOutHandler, onPress: beginZoomingOutHandler,
onRelease: endZoomingHandler, onRelease: endZoomingHandler,
onClick: doSingleZoomOutHandler, onClick: doSingleZoomOutHandler,
@ -210,29 +216,29 @@ $.Viewer = function( options ) {
onExit: endZoomingHandler onExit: endZoomingHandler
}), }),
goHome = new $.Button({ goHome = new $.Button({
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.Home" ), tooltip: $.getString( "Tooltips.Home" ),
srcRest: resolveUrl( this.config.prefixUrl, navImages.home.REST ), srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ),
srcGroup: resolveUrl( this.config.prefixUrl, navImages.home.GROUP ), srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ),
srcHover: resolveUrl( this.config.prefixUrl, navImages.home.HOVER ), srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ),
srcDown: resolveUrl( this.config.prefixUrl, navImages.home.DOWN ), srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ),
onRelease: onHomeHandler onRelease: onHomeHandler
}), }),
fullPage = new $.Button({ fullPage = new $.Button({
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.FullPage" ), tooltip: $.getString( "Tooltips.FullPage" ),
srcRest: resolveUrl( this.config.prefixUrl, navImages.fullpage.REST ), srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ),
srcGroup: resolveUrl( this.config.prefixUrl, navImages.fullpage.GROUP ), srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ),
srcHover: resolveUrl( this.config.prefixUrl, navImages.fullpage.HOVER ), srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ),
srcDown: resolveUrl( this.config.prefixUrl, navImages.fullpage.DOWN ), srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ),
onRelease: onFullPageHandler onRelease: onFullPageHandler
}); });
this.buttons = new $.ButtonGroup({ this.buttons = new $.ButtonGroup({
clickTimeThreshold: this.config.clickTimeThreshold, clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.config.clickDistThreshold, clickDistThreshold: this.clickDistThreshold,
buttons: [ buttons: [
zoomIn, zoomIn,
zoomOut, zoomOut,
@ -245,7 +251,7 @@ $.Viewer = function( options ) {
this.navControl[ $.SIGNAL ] = true; // hack to get our controls to fade this.navControl[ $.SIGNAL ] = true; // hack to get our controls to fade
this.addHandler( 'open', $.delegate( this, lightUp ) ); this.addHandler( 'open', $.delegate( this, lightUp ) );
if ( this.config.showNavigationControl ) { if ( this.showNavigationControl ) {
this.navControl.style.marginRight = "4px"; this.navControl.style.marginRight = "4px";
this.navControl.style.marginBottom = "4px"; this.navControl.style.marginBottom = "4px";
this.addControl( this.navControl, $.ControlAnchor.BOTTOM_RIGHT ); this.addControl( this.navControl, $.ControlAnchor.BOTTOM_RIGHT );
@ -297,7 +303,7 @@ $.Viewer = function( options ) {
initialTileSource = this.tileSources initialTileSource = this.tileSources
} }
if ( $.type( initialTileSource ) == 'string ') { if ( $.type( initialTileSource ) == 'string') {
//Standard DZI format //Standard DZI format
this.openDzi( initialTileSource ); this.openDzi( initialTileSource );
} else if ( $.isArray( initialTileSource ) ){ } else if ( $.isArray( initialTileSource ) ){
@ -309,9 +315,6 @@ $.Viewer = function( options ) {
customTileSource.getTileUrl = initialTileSource; customTileSource.getTileUrl = initialTileSource;
this.open( customTileSource ); this.open( customTileSource );
} }
} }
}; };
@ -435,14 +438,29 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, {
this.viewport = new $.Viewport({ this.viewport = new $.Viewport({
containerSize: THIS[ this.hash ].prevContainerSize, containerSize: THIS[ this.hash ].prevContainerSize,
contentSize: this.source.dimensions, contentSize: this.source.dimensions,
config: this.config springStiffness: this.springStiffness,
animationTime: this.animationTime,
minZoomImageRatio: this.minZoomImageRatio,
maxZoomPixelRatio: this.maxZoomPixelRatio,
visibilityRatio: this.visibilityRatio,
wrapHorizontal: this.wrapHorizontal,
wrapVertical: this.wrapVertical
}); });
this.drawer = new $.Drawer( this.drawer = new $.Drawer({
this.source, source: this.source,
this.viewport, viewport: this.viewport,
this.canvas element: this.canvas,
); 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.minPixelRatio
});
//this.profiler = new $.Profiler(); //this.profiler = new $.Profiler();
@ -759,17 +777,17 @@ function scheduleControlsFade( viewer ) {
//initiates an animation to hide the controls //initiates an animation to hide the controls
function beginControlsAutoHide( viewer ) { function beginControlsAutoHide( viewer ) {
if ( !viewer.config.autoHideControls ) { if ( !viewer.autoHideControls ) {
return; return;
} }
viewer.controlsShouldFade = true; viewer.controlsShouldFade = true;
viewer.controlsFadeBeginTime = viewer.controlsFadeBeginTime =
+new Date() + +new Date() +
viewer.config.controlsFadeDelay; viewer.controlsFadeDelay;
window.setTimeout( function(){ window.setTimeout( function(){
scheduleControlsFade( viewer ); scheduleControlsFade( viewer );
}, viewer.config.controlsFadeDelay ); }, viewer.controlsFadeDelay );
}; };
@ -782,7 +800,7 @@ function updateControlsFade( viewer ) {
if ( viewer.controlsShouldFade ) { if ( viewer.controlsShouldFade ) {
currentTime = new Date().getTime(); currentTime = new Date().getTime();
deltaTime = currentTime - viewer.controlsFadeBeginTime; deltaTime = currentTime - viewer.controlsFadeBeginTime;
opacity = 1.0 - deltaTime / viewer.config.controlsFadeLength; opacity = 1.0 - deltaTime / viewer.controlsFadeLength;
opacity = Math.min( 1.0, opacity ); opacity = Math.min( 1.0, opacity );
opacity = Math.max( 0.0, opacity ); opacity = Math.max( 0.0, opacity );
@ -815,7 +833,7 @@ 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
zoomPerClick = this.config.zoomPerClick; zoomPerClick = this.zoomPerClick;
factor = shift ? 1.0 / zoomPerClick : zoomPerClick; factor = shift ? 1.0 / zoomPerClick : zoomPerClick;
this.viewport.zoomBy( this.viewport.zoomBy(
factor, factor,
@ -844,7 +862,7 @@ function onCanvasRelease( tracker, position, insideElementPress, insideElementRe
function onCanvasScroll( tracker, position, scroll, shift ) { function onCanvasScroll( tracker, position, scroll, shift ) {
var factor; var factor;
if ( this.viewport ) { if ( this.viewport ) {
factor = Math.pow( this.config.zoomPerScroll, scroll ); factor = Math.pow( this.zoomPerScroll, scroll );
this.viewport.zoomBy( this.viewport.zoomBy(
factor, factor,
this.viewport.pointFromPixel( position, true ) this.viewport.pointFromPixel( position, true )
@ -963,14 +981,14 @@ function resolveUrl( prefix, url ) {
function beginZoomingIn() { function beginZoomingIn() {
THIS[ this.hash ].lastZoomTime = +new Date(); THIS[ this.hash ].lastZoomTime = +new Date();
THIS[ this.hash ].zoomFactor = this.config.zoomPerSecond; THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
THIS[ this.hash ].zooming = true; THIS[ this.hash ].zooming = true;
scheduleZoom( this ); scheduleZoom( this );
} }
function beginZoomingOut() { function beginZoomingOut() {
THIS[ this.hash ].lastZoomTime = +new Date(); THIS[ this.hash ].lastZoomTime = +new Date();
THIS[ this.hash ].zoomFactor = 1.0 / this.config.zoomPerSecond; THIS[ this.hash ].zoomFactor = 1.0 / this.zoomPerSecond;
THIS[ this.hash ].zooming = true; THIS[ this.hash ].zooming = true;
scheduleZoom( this ); scheduleZoom( this );
} }
@ -1004,7 +1022,7 @@ function doSingleZoomIn() {
if ( this.viewport ) { if ( this.viewport ) {
THIS[ this.hash ].zooming = false; THIS[ this.hash ].zooming = false;
this.viewport.zoomBy( this.viewport.zoomBy(
this.config.zoomPerClick / 1.0 this.zoomPerClick / 1.0
); );
this.viewport.applyConstraints(); this.viewport.applyConstraints();
} }
@ -1014,7 +1032,7 @@ function doSingleZoomOut() {
if ( this.viewport ) { if ( this.viewport ) {
THIS[ this.hash ].zooming = false; THIS[ this.hash ].zooming = false;
this.viewport.zoomBy( this.viewport.zoomBy(
1.0 / this.config.zoomPerClick 1.0 / this.zoomPerClick
); );
this.viewport.applyConstraints(); this.viewport.applyConstraints();
} }

View File

@ -7,43 +7,63 @@
*/ */
$.Viewport = function( options ) { $.Viewport = function( options ) {
//backward compatibility for positional args while prefering more
if( arguments.length && arguments[ 0 ] instanceof $.Point ){ //idiomatic javascript options object as the only argument
var args = arguments;
if( args.length && args[ 0 ] instanceof $.Point ){
options = { options = {
containerSize: arguments[ 0 ], containerSize: args[ 0 ],
contentSize: arguments[ 1 ], contentSize: args[ 1 ],
config: arguments[ 2 ] config: args[ 2 ]
}; };
} }
//TODO: this.config is something that should go away but currently the //options.config and the general config argument are deprecated
// Drawer references the viewport.config //in favor of the more direct specification of optional settings
this.config = options.config; //being pass directly on the options object
this.zoomPoint = null; if ( options.config ){
this.containerSize = options.containerSize; $.extend( true, options, options.config );
this.contentSize = options.contentSize; delete options.config;
}
$.extend( true, this, {
//required settings
containerSize: null,
contentSize: null,
//internal state properties
zoomPoint: null,
//configurable options
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
animationTime: $.DEFAULT_SETTINGS.animationTime,
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
maxZoomPixelRatio: $.DEFAULT_SETTINGS.maxZoomPixelRatio,
visibilityRatio: $.DEFAULT_SETTINGS.visibilityRatio,
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical
}, options );
this.contentAspect = this.contentSize.x / this.contentSize.y; this.contentAspect = this.contentSize.x / this.contentSize.y;
this.contentHeight = this.contentSize.y / this.contentSize.x; this.contentHeight = this.contentSize.y / this.contentSize.x;
this.centerSpringX = new $.Spring({ this.centerSpringX = new $.Spring({
initial: 0, initial: 0,
springStiffness: this.config.springStiffness, springStiffness: this.springStiffness,
animationTime: this.config.animationTime animationTime: this.animationTime
}); });
this.centerSpringY = new $.Spring({ this.centerSpringY = new $.Spring({
initial: 0, initial: 0,
springStiffness: this.config.springStiffness, springStiffness: this.springStiffness,
animationTime: this.config.animationTime animationTime: this.animationTime
}); });
this.zoomSpring = new $.Spring({ this.zoomSpring = new $.Spring({
initial: 1, initial: 1,
springStiffness: this.config.springStiffness, springStiffness: this.springStiffness,
animationTime: this.config.animationTime animationTime: this.animationTime
}); });
this.minZoomImageRatio = this.config.minZoomImageRatio;
this.maxZoomPixelRatio = this.config.maxZoomPixelRatio;
this.visibilityRatio = this.config.visibilityRatio;
this.wrapHorizontal = this.config.wrapHorizontal;
this.wrapVertical = this.config.wrapVertical;
this.homeBounds = new $.Rect( 0, 0, 1, this.contentHeight ); this.homeBounds = new $.Rect( 0, 0, 1, this.contentHeight );
this.goHome( true ); this.goHome( true );