diff --git a/build.properties b/build.properties
index ea445dfe..af817a35 100644
--- a/build.properties
+++ b/build.properties
@@ -6,7 +6,7 @@
PROJECT: openseadragon
BUILD_MAJOR: 0
BUILD_MINOR: 9
-BUILD_ID: 16
+BUILD_ID: 18
BUILD: ${PROJECT}.${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID}
VERSION: ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_ID}
diff --git a/openseadragon.js b/openseadragon.js
index 908b44c8..7ec55431 100644
--- a/openseadragon.js
+++ b/openseadragon.js
@@ -1,5 +1,5 @@
/**
- * @version OpenSeadragon 0.9.16
+ * @version OpenSeadragon 0.9.18
*
* @fileOverview
*
@@ -59,18 +59,138 @@
**/
/**
- * The root namespace for OpenSeadragon. All utility methods and classes
- * are defined on or below this namespace. The OpenSeadragon namespace will
- * only be defined once even if mutliple versions are loaded on the page in
- * succession.
- * @namespace
+ * The root namespace for OpenSeadragon, this function also serves as a single
+ * point of instantiation for an {@link OpenSeadragon.Viewer}, including all
+ * combinations of out-of-the-box configurable features. All utility methods
+ * and classes are defined on or below this namespace.
+ *
+ * @namespace
+ * @function
* @name 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 ){
+
+ return new OpenSeadragon.Viewer( options );
- //Taken from jquery 1.6.1
- // [[Class]] -> type pairs
+};
+
+(function( $ ){
+
+
+ /**
+ * Taken from jquery 1.6.1
+ * [[Class]] -> type pairs
+ * @private
+ */
var class2type = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
@@ -89,142 +209,118 @@ OpenSeadragon = window.OpenSeadragon || (function(){
trim = String.prototype.trim,
indexOf = Array.prototype.indexOf;
- return {
- DEFAULT_SETTINGS: {
- 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,
- 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'
- }
- }
- },
+ /**
+ * Taken from jQuery 1.6.1
+ * @name $.isFunction
+ * @function
+ * @see jQuery
+ */
+ $.isFunction = function( obj ) {
+ return $.type(obj) === "function";
+ };
- // 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 jQuery
+ */
+ $.isArray = Array.isArray || function( obj ) {
+ return $.type(obj) === "array";
+ };
- // A crude way of determining if an object is a window
- isWindow: function( obj ) {
- return obj && typeof obj === "object" && "setInterval" in obj;
- },
- type: function( obj ) {
- return obj == null ?
- String( obj ) :
- class2type[ toString.call(obj) ] || "object";
- },
+ /**
+ * A crude way of determining if an object is a window.
+ * Taken from jQuery 1.6.1
+ * @name $.isWindow
+ * @function
+ * @see jQuery
+ */
+ $.isWindow = function( obj ) {
+ return obj && typeof obj === "object" && "setInterval" in obj;
+ };
- isPlainObject: function( obj ) {
- // Must be an Object.
- // 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
- if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || OpenSeadragon.isWindow( obj ) ) {
- return false;
- }
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !hasOwn.call(obj, "constructor") &&
- !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
+ /**
+ * Taken from jQuery 1.6.1
+ * @name $.type
+ * @function
+ * @see jQuery
+ */
+ $.type = function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
+ };
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
- var key;
- for ( key in obj ) {}
-
- return key === undefined || hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- for ( var name in obj ) {
- return false;
- }
- return true;
+ /**
+ * Taken from jQuery 1.6.1
+ * @name $.isPlainObject
+ * @function
+ * @see jQuery
+ */
+ $.isPlainObject = function( obj ) {
+ // Must be an Object.
+ // 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
+ if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || $.isWindow( obj ) ) {
+ return false;
}
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
};
-}());
-
-(function( $ ){
/**
- * @static
- * @ignore
+ * Taken from jQuery 1.6.1
+ * @name $.isEmptyObject
+ * @function
+ * @see jQuery
*/
- $.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 );
- };
+ $.isEmptyObject = function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ 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( $ ){
+
/**
- * Taken from jQuery 1.6.1, see the jQuery documentation
+ * Taken from jQuery 1.6.1
+ * @see jQuery
*/
$.extend = function() {
var options,
@@ -294,152 +390,115 @@ OpenSeadragon = window.OpenSeadragon || (function(){
// Return the modified object
return target;
};
-
- //The following functions are originally from the Openseadragon Utils
- //module but have been moved to Openseadragon to avoid the 'Utils' anti-
- //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
- //orignally developed by the project.
- /**
- * An enumeration of Browser vendors including UNKNOWN, IE, FIREFOX,
- * SAFARI, CHROME, and OPERA.
- * @static
- */
- $.BROWSERS = {
- UNKNOWN: 0,
- IE: 1,
- FIREFOX: 2,
- SAFARI: 3,
- CHROME: 4,
- OPERA: 5
- };
- /**
- * The current browser vendor, version, and related information regarding
- * detected features. Features include
- * 'alpha' - Does the browser support image alpha
- * transparency.
- * @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( $, {
+ /**
+ * These are the default values for the optional settings documented
+ * 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,
+ * SAFARI, CHROME, and OPERA.
+ * @name $.BROWSERS
+ * @static
+ */
+ BROWSERS: {
+ UNKNOWN: 0,
+ IE: 1,
+ FIREFOX: 2,
+ SAFARI: 3,
+ CHROME: 4,
+ OPERA: 5
+ },
+
/**
* Returns a DOM Element for the given id or element.
@@ -455,6 +514,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element;
},
+
/**
* Determines the position of the upper-left corner of the element.
* @function
@@ -488,6 +548,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result;
},
+
/**
* Determines the height and width of the given element.
* @function
@@ -504,6 +565,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
);
},
+
/**
* Returns the CSSStyle object for the given element.
* @function
@@ -523,6 +585,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Gets the latest event, really only useful internally since its
* specific to IE behavior. TODO: Deprecate this from the api and
@@ -536,6 +599,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return event ? event : window.event;
},
+
/**
* Gets the position of the mouse on the screen for a given event.
* @function
@@ -569,6 +633,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result;
},
+
/**
* Determines the pages current scroll position.
* @function
@@ -594,6 +659,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result;
},
+
/**
* Determines the size of the browsers window.
* @function
@@ -667,6 +733,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return div;
},
+
/**
* Creates an easily positionable element of the given type that therefor
* serves as an excellent container element.
@@ -688,6 +755,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element;
},
+
/**
* Ensures an image is loaded correctly to support alpha transparency.
* Generally only IE has issues doing this correctly for formats like
@@ -731,6 +799,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element;
},
+
/**
* Sets the opacity of the specified element.
* @function
@@ -779,6 +848,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Adds an event listener for the given element, eventName and handler.
* @function
@@ -808,6 +878,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Remove a given event listener for the given element, event type and
* handler.
@@ -838,6 +909,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Cancels the default browser behavior had the event propagated all
* the way up the DOM to the window object.
@@ -858,6 +930,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
event.returnValue = false;
},
+
/**
* Stops the propagation of the event up the DOM.
* @function
@@ -874,6 +947,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
event.cancelBubble = true; // IE for stopping propagation
},
+
/**
* Similar to OpenSeadragon.delegate, but it does not immediately call
* 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.
* @function
@@ -922,6 +997,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return value ? value : null;
},
+
/**
* Makes an AJAX request.
* @function
@@ -1077,6 +1153,138 @@ OpenSeadragon = window.OpenSeadragon || (function(){
});
+
+ /**
+ * The current browser vendor, version, and related information regarding
+ * detected features. Features include
+ * 'alpha' - Does the browser support image alpha
+ * transparency.
+ * @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
* @inner
@@ -2504,6 +2712,8 @@ $.Viewer = function( options ) {
$.EventHandler.call( this );
+ //backward compatibility for positional args while prefering more
+ //idiomatic javascript options object as the only argument
if( !$.isPlainObject( options ) ){
options = {
id: args[ 0 ],
@@ -2511,29 +2721,29 @@ $.Viewer = function( options ) {
prefixUrl: args.length > 2 ? args[ 2 ] : undefined,
controls: args.length > 3 ? args[ 3 ] : undefined,
overlays: args.length > 4 ? args[ 4 ] : undefined,
- overlayControls: args.length > 5 ? args[ 5 ] : undefined,
- config: {}
+ overlayControls: args.length > 5 ? args[ 5 ] : undefined
};
}
+
+ //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
$.extend( true, this, {
+
id: options.id,
- xmlPath: null,
- tileSources: null,
+ hash: options.id,
controls: [],
overlays: [],
overlayControls: [],
- config: $.DEFAULT_SETTINGS,
- //These were referenced but never defined
-
- //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,
+ //private state properties
+ previousBody: [],
//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
@@ -2541,11 +2751,18 @@ $.Viewer = function( options ) {
//this array was returned from get_controls which I find confusing
//since this object has a controls property which is treated in other
//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.canvas = $.makeNeutralElement( "div" );
@@ -2556,9 +2773,6 @@ $.Viewer = function( options ) {
this.bodyHeight = document.body.style.height;
this.bodyOverflow = document.body.style.overflow;
this.docOverflow = document.documentElement.style.overflow;
- this.previousBody = [];
-
- this.hash = Math.random();
THIS[ this.hash ] = {
"fsBoundsDelta": new $.Point( 1, 1 ),
@@ -2572,8 +2786,8 @@ $.Viewer = function( options ) {
this.innerTracker = new $.MouseTracker({
element: this.canvas,
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
clickHandler: $.delegate( this, onCanvasClick ),
dragHandler: $.delegate( this, onCanvasDrag ),
releaseHandler: $.delegate( this, onCanvasRelease ),
@@ -2582,8 +2796,8 @@ $.Viewer = function( options ) {
this.outerTracker = new $.MouseTracker({
element: this.container,
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
enterHandler: $.delegate( this, onContainerEnter ),
exitHandler: $.delegate( this, onContainerExit ),
releaseHandler: $.delegate( this, onContainerRelease )
@@ -2649,15 +2863,15 @@ $.Viewer = function( options ) {
doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ),
onHomeHandler = $.delegate( this, onHome ),
onFullPageHandler = $.delegate( this, onFullPage ),
- navImages = this.config.navImages,
+ navImages = this.navImages,
zoomIn = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.ZoomIn" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.zoomIn.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.zoomIn.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.zoomIn.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.zoomIn.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ),
onPress: beginZoomingInHandler,
onRelease: endZoomingHandler,
onClick: doSingleZoomInHandler,
@@ -2665,13 +2879,13 @@ $.Viewer = function( options ) {
onExit: endZoomingHandler
}),
zoomOut = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.ZoomOut" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.zoomOut.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.zoomOut.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.zoomOut.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.zoomOut.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ),
onPress: beginZoomingOutHandler,
onRelease: endZoomingHandler,
onClick: doSingleZoomOutHandler,
@@ -2679,29 +2893,29 @@ $.Viewer = function( options ) {
onExit: endZoomingHandler
}),
goHome = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.Home" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.home.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.home.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.home.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.home.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ),
onRelease: onHomeHandler
}),
fullPage = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.FullPage" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.fullpage.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.fullpage.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.fullpage.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.fullpage.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ),
onRelease: onFullPageHandler
});
this.buttons = new $.ButtonGroup({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
buttons: [
zoomIn,
zoomOut,
@@ -2714,7 +2928,7 @@ $.Viewer = function( options ) {
this.navControl[ $.SIGNAL ] = true; // hack to get our controls to fade
this.addHandler( 'open', $.delegate( this, lightUp ) );
- if ( this.config.showNavigationControl ) {
+ if ( this.showNavigationControl ) {
this.navControl.style.marginRight = "4px";
this.navControl.style.marginBottom = "4px";
this.addControl( this.navControl, $.ControlAnchor.BOTTOM_RIGHT );
@@ -2766,7 +2980,7 @@ $.Viewer = function( options ) {
initialTileSource = this.tileSources
}
- if ( $.type( initialTileSource ) == 'string ') {
+ if ( $.type( initialTileSource ) == 'string') {
//Standard DZI format
this.openDzi( initialTileSource );
} else if ( $.isArray( initialTileSource ) ){
@@ -2778,9 +2992,6 @@ $.Viewer = function( options ) {
customTileSource.getTileUrl = initialTileSource;
this.open( customTileSource );
}
-
-
-
}
};
@@ -2902,16 +3113,31 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, {
}
this.viewport = new $.Viewport({
- containerSize: THIS[ this.hash ].prevContainerSize,
- contentSize: this.source.dimensions,
- config: this.config
+ 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
});
- this.drawer = new $.Drawer(
- this.source,
- this.viewport,
- this.canvas
- );
+ this.drawer = new $.Drawer({
+ source: this.source,
+ viewport: this.viewport,
+ 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();
@@ -3228,17 +3454,17 @@ function scheduleControlsFade( viewer ) {
//initiates an animation to hide the controls
function beginControlsAutoHide( viewer ) {
- if ( !viewer.config.autoHideControls ) {
+ if ( !viewer.autoHideControls ) {
return;
}
viewer.controlsShouldFade = true;
viewer.controlsFadeBeginTime =
+new Date() +
- viewer.config.controlsFadeDelay;
+ viewer.controlsFadeDelay;
window.setTimeout( function(){
scheduleControlsFade( viewer );
- }, viewer.config.controlsFadeDelay );
+ }, viewer.controlsFadeDelay );
};
@@ -3251,7 +3477,7 @@ function updateControlsFade( viewer ) {
if ( viewer.controlsShouldFade ) {
currentTime = new Date().getTime();
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.max( 0.0, opacity );
@@ -3284,7 +3510,7 @@ function onCanvasClick( tracker, position, quick, shift ) {
var zoomPreClick,
factor;
if ( this.viewport && quick ) { // ignore clicks where mouse moved
- zoomPerClick = this.config.zoomPerClick;
+ zoomPerClick = this.zoomPerClick;
factor = shift ? 1.0 / zoomPerClick : zoomPerClick;
this.viewport.zoomBy(
factor,
@@ -3313,7 +3539,7 @@ function onCanvasRelease( tracker, position, insideElementPress, insideElementRe
function onCanvasScroll( tracker, position, scroll, shift ) {
var factor;
if ( this.viewport ) {
- factor = Math.pow( this.config.zoomPerScroll, scroll );
+ factor = Math.pow( this.zoomPerScroll, scroll );
this.viewport.zoomBy(
factor,
this.viewport.pointFromPixel( position, true )
@@ -3432,14 +3658,14 @@ function resolveUrl( prefix, url ) {
function beginZoomingIn() {
THIS[ this.hash ].lastZoomTime = +new Date();
- THIS[ this.hash ].zoomFactor = this.config.zoomPerSecond;
+ THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
THIS[ this.hash ].zooming = true;
scheduleZoom( this );
}
function beginZoomingOut() {
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;
scheduleZoom( this );
}
@@ -3473,7 +3699,7 @@ function doSingleZoomIn() {
if ( this.viewport ) {
THIS[ this.hash ].zooming = false;
this.viewport.zoomBy(
- this.config.zoomPerClick / 1.0
+ this.zoomPerClick / 1.0
);
this.viewport.applyConstraints();
}
@@ -3483,7 +3709,7 @@ function doSingleZoomOut() {
if ( this.viewport ) {
THIS[ this.hash ].zooming = false;
this.viewport.zoomBy(
- 1.0 / this.config.zoomPerClick
+ 1.0 / this.zoomPerClick
);
this.viewport.applyConstraints();
}
@@ -4794,18 +5020,18 @@ function transform( stiffness, x ) {
* @param {Number} x The vector component 'x'.
* @param {Number} y The vector component 'y'.
* @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
- * this tile failed to load?
+ * this tile failed to load? )
* @param {String} url The URL of this tile's image.
*
* @property {Number} level The zoom level this tile belongs to.
* @property {Number} x The vector component 'x'.
* @property {Number} y The vector component 'y'.
* @property {OpenSeadragon.Point} bounds Where this tile fits, in normalized
- * coordinates
+ * coordinates
* @property {Boolean} exists Is this tile a part of a sparse image? ( Also has
- * this tile failed to load?
+ * this tile failed to load?
* @property {String} url The URL of this tile's image.
* @property {Boolean} loaded Is this tile loaded?
* @property {Boolean} loading Is this tile loading
@@ -5113,12 +5339,7 @@ $.Tile.prototype = {
(function( $ ){
- // the max number of images we should keep in memory
-var QUOTA = 100,
- // the most shrunk a tile should be
- MIN_PIXEL_RATIO = 0.5,
- //TODO: make TIMEOUT configurable
- TIMEOUT = 5000,
+var TIMEOUT = 5000,
BROWSER = $.Browser.vendor,
BROWSER_VERSION = $.Browser.version,
@@ -5128,11 +5349,13 @@ var QUOTA = 100,
( BROWSER == $.BROWSERS.OPERA ) ||
( BROWSER == $.BROWSERS.SAFARI && BROWSER_VERSION >= 4 ) ||
( BROWSER == $.BROWSERS.CHROME && BROWSER_VERSION >= 2 )
- ),
+ ) && ( !navigator.appVersion.match( 'Mobile' ) ),
USE_CANVAS = $.isFunction( document.createElement( "canvas" ).getContext ) &&
SUBPIXEL_RENDERING;
+//console.error( 'USE_CANVAS ' + USE_CANVAS );
+
/**
* @class
* @param {OpenSeadragon.TileSource} source - Reference to Viewer tile source.
@@ -5156,26 +5379,54 @@ var QUOTA = 100,
* @property {Boolean} updateAgain - Does the drawer need to update the viewort again?
* @property {Element} element - DEPRECATED Alias for container.
*/
-$.Drawer = function( source, viewport, element ) {
+$.Drawer = function( options ) {
+
+ //backward compatibility for positional args while prefering more
+ //idiomatic javascript options object as the only argument
+ var args = arguments;
+ if( !$.isPlainObject( options ) ){
+ options = {
+ source: args[ 0 ],
+ viewport: args[ 1 ],
+ element: args[ 2 ]
+ };
+ }
- this.viewport = viewport;
- this.source = source;
- this.container = $.getElement( element );
+ $.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.context = USE_CANVAS ? this.canvas.getContext( "2d" ) : null;
- this.config = this.viewport.config;
- this.normHeight = source.dimensions.y / source.dimensions.x;
+ this.normHeight = this.source.dimensions.y / this.source.dimensions.x;
+ this.element = this.container;
- 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.canvas.style.width = "100%";
this.canvas.style.height = "100%";
@@ -5320,7 +5571,7 @@ $.Drawer.prototype = {
* the local cache to optimize user experience in certain cases. Because
* the number of parallel image loads is configurable, if too many images
* 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.
* @method
* @param {String} src - The url of the image to load.
@@ -5329,7 +5580,7 @@ $.Drawer.prototype = {
* For now this means the callback is expected to distinguish between
* error and success conditions by inspecting the Image object.
* @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 ) {
var _this = this,
@@ -5338,8 +5589,8 @@ $.Drawer.prototype = {
jobid,
complete;
- if ( !this.config.imageLoaderLimit ||
- this.downloading < this.config.imageLoaderLimit ) {
+ if ( !this.imageLoaderLimit ||
+ this.downloading < this.imageLoaderLimit ) {
this.downloading++;
@@ -5409,14 +5660,14 @@ function updateViewport( drawer ) {
lowestLevel = Math.max(
drawer.source.minLevel,
Math.floor(
- Math.log( drawer.config.minZoomImageRatio ) /
+ Math.log( drawer.minZoomImageRatio ) /
Math.log( 2 )
)
),
highestLevel = Math.min(
drawer.source.maxLevel,
Math.floor(
- Math.log( zeroRatioC / MIN_PIXEL_RATIO ) /
+ Math.log( zeroRatioC / drawer.minPixelRatio ) /
Math.log( 2 )
)
),
@@ -5442,21 +5693,21 @@ function updateViewport( drawer ) {
}
//TODO
- if ( !drawer.config.wrapHorizontal &&
+ if ( !drawer.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return;
} else if
- ( !drawer.config.wrapVertical &&
+ ( !drawer.wrapVertical &&
( viewportBR.y < 0 || viewportTL.y > drawer.normHeight ) ) {
return;
}
//TODO
- if ( !drawer.config.wrapHorizontal ) {
+ if ( !drawer.wrapHorizontal ) {
viewportTL.x = Math.max( viewportTL.x, 0 );
viewportBR.x = Math.min( viewportBR.x, 1 );
}
- if ( !drawer.config.wrapVertical ) {
+ if ( !drawer.wrapVertical ) {
viewportTL.y = Math.max( viewportTL.y, 0 );
viewportBR.y = Math.min( viewportBR.y, drawer.normHeight );
}
@@ -5473,7 +5724,7 @@ function updateViewport( drawer ) {
true
).x;
- if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) ||
+ if ( ( !haveDrawn && renderPixelRatioC >= drawer.minPixelRatio ) ||
( level == lowestLevel ) ) {
drawLevel = true;
haveDrawn = true;
@@ -5491,7 +5742,7 @@ function updateViewport( drawer ) {
false
).x;
- optimalRatio = drawer.config.immediateRender ?
+ optimalRatio = drawer.immediateRender ?
1 :
zeroRatioT;
@@ -5549,10 +5800,10 @@ function updateLevel( drawer, haveDrawn, level, levelOpacity, levelVisibility, v
resetCoverage( drawer.coverage, level );
- if ( !drawer.config.wrapHorizontal ) {
+ if ( !drawer.wrapHorizontal ) {
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 );
}
@@ -5721,7 +5972,7 @@ function onTileLoad( drawer, tile, time, image ) {
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 ) );
worstTile = null;
@@ -5783,7 +6034,7 @@ function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility
function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
- var blendTimeMillis = 1000 * drawer.config.blendTime,
+ var blendTimeMillis = 1000 * drawer.blendTime,
deltaTime,
opacity;
@@ -5794,7 +6045,7 @@ function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / blendTimeMillis );
- if ( drawer.config.alwaysBlend ) {
+ if ( drawer.alwaysBlend ) {
opacity *= levelOpacity;
}
@@ -6017,44 +6268,64 @@ function drawTiles( drawer, lastDrawn ){
*/
$.Viewport = function( options ) {
-
- if( arguments.length && arguments[ 0 ] instanceof $.Point ){
+ //backward compatibility for positional args while prefering more
+ //idiomatic javascript options object as the only argument
+ var args = arguments;
+ if( args.length && args[ 0 ] instanceof $.Point ){
options = {
- containerSize: arguments[ 0 ],
- contentSize: arguments[ 1 ],
- config: arguments[ 2 ]
+ containerSize: args[ 0 ],
+ contentSize: args[ 1 ],
+ config: args[ 2 ]
};
}
- //TODO: this.config is something that should go away but currently the
- // Drawer references the viewport.config
- this.config = options.config;
- this.zoomPoint = null;
- this.containerSize = options.containerSize;
- this.contentSize = options.contentSize;
+ //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;
+ }
+
+ $.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.contentHeight = this.contentSize.y / this.contentSize.x;
this.centerSpringX = new $.Spring({
initial: 0,
- springStiffness: this.config.springStiffness,
- animationTime: this.config.animationTime
+ springStiffness: this.springStiffness,
+ animationTime: this.animationTime
});
this.centerSpringY = new $.Spring({
initial: 0,
- springStiffness: this.config.springStiffness,
- animationTime: this.config.animationTime
+ springStiffness: this.springStiffness,
+ animationTime: this.animationTime
});
this.zoomSpring = new $.Spring({
initial: 1,
- springStiffness: this.config.springStiffness,
- animationTime: this.config.animationTime
+ springStiffness: this.springStiffness,
+ 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.update();
diff --git a/src/drawer.js b/src/drawer.js
index 65c60eb1..62a78e3c 100644
--- a/src/drawer.js
+++ b/src/drawer.js
@@ -1,12 +1,7 @@
(function( $ ){
- // the max number of images we should keep in memory
-var QUOTA = 100,
- // the most shrunk a tile should be
- MIN_PIXEL_RATIO = 0.5,
- //TODO: make TIMEOUT configurable
- TIMEOUT = 5000,
+var TIMEOUT = 5000,
BROWSER = $.Browser.vendor,
BROWSER_VERSION = $.Browser.version,
@@ -16,11 +11,13 @@ var QUOTA = 100,
( BROWSER == $.BROWSERS.OPERA ) ||
( BROWSER == $.BROWSERS.SAFARI && BROWSER_VERSION >= 4 ) ||
( BROWSER == $.BROWSERS.CHROME && BROWSER_VERSION >= 2 )
- ),
+ ) && ( !navigator.appVersion.match( 'Mobile' ) ),
USE_CANVAS = $.isFunction( document.createElement( "canvas" ).getContext ) &&
SUBPIXEL_RENDERING;
+//console.error( 'USE_CANVAS ' + USE_CANVAS );
+
/**
* @class
* @param {OpenSeadragon.TileSource} source - Reference to Viewer tile source.
@@ -44,26 +41,54 @@ var QUOTA = 100,
* @property {Boolean} updateAgain - Does the drawer need to update the viewort again?
* @property {Element} element - DEPRECATED Alias for container.
*/
-$.Drawer = function( source, viewport, element ) {
+$.Drawer = function( options ) {
+
+ //backward compatibility for positional args while prefering more
+ //idiomatic javascript options object as the only argument
+ var args = arguments;
+ if( !$.isPlainObject( options ) ){
+ options = {
+ source: args[ 0 ],
+ viewport: args[ 1 ],
+ element: args[ 2 ]
+ };
+ }
- this.viewport = viewport;
- this.source = source;
- this.container = $.getElement( element );
+ $.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.context = USE_CANVAS ? this.canvas.getContext( "2d" ) : null;
- this.config = this.viewport.config;
- this.normHeight = source.dimensions.y / source.dimensions.x;
+ this.normHeight = this.source.dimensions.y / this.source.dimensions.x;
+ this.element = this.container;
- 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.canvas.style.width = "100%";
this.canvas.style.height = "100%";
@@ -208,7 +233,7 @@ $.Drawer.prototype = {
* the local cache to optimize user experience in certain cases. Because
* the number of parallel image loads is configurable, if too many images
* 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.
* @method
* @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
* error and success conditions by inspecting the Image object.
* @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 ) {
var _this = this,
@@ -226,8 +251,8 @@ $.Drawer.prototype = {
jobid,
complete;
- if ( !this.config.imageLoaderLimit ||
- this.downloading < this.config.imageLoaderLimit ) {
+ if ( !this.imageLoaderLimit ||
+ this.downloading < this.imageLoaderLimit ) {
this.downloading++;
@@ -297,14 +322,14 @@ function updateViewport( drawer ) {
lowestLevel = Math.max(
drawer.source.minLevel,
Math.floor(
- Math.log( drawer.config.minZoomImageRatio ) /
+ Math.log( drawer.minZoomImageRatio ) /
Math.log( 2 )
)
),
highestLevel = Math.min(
drawer.source.maxLevel,
Math.floor(
- Math.log( zeroRatioC / MIN_PIXEL_RATIO ) /
+ Math.log( zeroRatioC / drawer.minPixelRatio ) /
Math.log( 2 )
)
),
@@ -330,21 +355,21 @@ function updateViewport( drawer ) {
}
//TODO
- if ( !drawer.config.wrapHorizontal &&
+ if ( !drawer.wrapHorizontal &&
( viewportBR.x < 0 || viewportTL.x > 1 ) ) {
return;
} else if
- ( !drawer.config.wrapVertical &&
+ ( !drawer.wrapVertical &&
( viewportBR.y < 0 || viewportTL.y > drawer.normHeight ) ) {
return;
}
//TODO
- if ( !drawer.config.wrapHorizontal ) {
+ if ( !drawer.wrapHorizontal ) {
viewportTL.x = Math.max( viewportTL.x, 0 );
viewportBR.x = Math.min( viewportBR.x, 1 );
}
- if ( !drawer.config.wrapVertical ) {
+ if ( !drawer.wrapVertical ) {
viewportTL.y = Math.max( viewportTL.y, 0 );
viewportBR.y = Math.min( viewportBR.y, drawer.normHeight );
}
@@ -361,7 +386,7 @@ function updateViewport( drawer ) {
true
).x;
- if ( ( !haveDrawn && renderPixelRatioC >= MIN_PIXEL_RATIO ) ||
+ if ( ( !haveDrawn && renderPixelRatioC >= drawer.minPixelRatio ) ||
( level == lowestLevel ) ) {
drawLevel = true;
haveDrawn = true;
@@ -379,7 +404,7 @@ function updateViewport( drawer ) {
false
).x;
- optimalRatio = drawer.config.immediateRender ?
+ optimalRatio = drawer.immediateRender ?
1 :
zeroRatioT;
@@ -437,10 +462,10 @@ function updateLevel( drawer, haveDrawn, level, levelOpacity, levelVisibility, v
resetCoverage( drawer.coverage, level );
- if ( !drawer.config.wrapHorizontal ) {
+ if ( !drawer.wrapHorizontal ) {
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 );
}
@@ -609,7 +634,7 @@ function onTileLoad( drawer, tile, time, image ) {
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 ) );
worstTile = null;
@@ -671,7 +696,7 @@ function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility
function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
- var blendTimeMillis = 1000 * drawer.config.blendTime,
+ var blendTimeMillis = 1000 * drawer.blendTime,
deltaTime,
opacity;
@@ -682,7 +707,7 @@ function blendTile( drawer, tile, x, y, level, levelOpacity, currentTime ){
deltaTime = currentTime - tile.blendStart;
opacity = Math.min( 1, deltaTime / blendTimeMillis );
- if ( drawer.config.alwaysBlend ) {
+ if ( drawer.alwaysBlend ) {
opacity *= levelOpacity;
}
diff --git a/src/openseadragon.js b/src/openseadragon.js
index b5aa8c29..99c51611 100644
--- a/src/openseadragon.js
+++ b/src/openseadragon.js
@@ -59,18 +59,138 @@
**/
/**
- * The root namespace for OpenSeadragon. All utility methods and classes
- * are defined on or below this namespace. The OpenSeadragon namespace will
- * only be defined once even if mutliple versions are loaded on the page in
- * succession.
- * @namespace
+ * The root namespace for OpenSeadragon, this function also serves as a single
+ * point of instantiation for an {@link OpenSeadragon.Viewer}, including all
+ * combinations of out-of-the-box configurable features. All utility methods
+ * and classes are defined on or below this namespace.
+ *
+ * @namespace
+ * @function
* @name 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 ){
+
+ return new OpenSeadragon.Viewer( options );
- //Taken from jquery 1.6.1
- // [[Class]] -> type pairs
+};
+
+(function( $ ){
+
+
+ /**
+ * Taken from jquery 1.6.1
+ * [[Class]] -> type pairs
+ * @private
+ */
var class2type = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
@@ -89,142 +209,118 @@ OpenSeadragon = window.OpenSeadragon || (function(){
trim = String.prototype.trim,
indexOf = Array.prototype.indexOf;
- return {
- DEFAULT_SETTINGS: {
- 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,
- 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'
- }
- }
- },
+ /**
+ * Taken from jQuery 1.6.1
+ * @name $.isFunction
+ * @function
+ * @see jQuery
+ */
+ $.isFunction = function( obj ) {
+ return $.type(obj) === "function";
+ };
- // 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 jQuery
+ */
+ $.isArray = Array.isArray || function( obj ) {
+ return $.type(obj) === "array";
+ };
- // A crude way of determining if an object is a window
- isWindow: function( obj ) {
- return obj && typeof obj === "object" && "setInterval" in obj;
- },
- type: function( obj ) {
- return obj == null ?
- String( obj ) :
- class2type[ toString.call(obj) ] || "object";
- },
+ /**
+ * A crude way of determining if an object is a window.
+ * Taken from jQuery 1.6.1
+ * @name $.isWindow
+ * @function
+ * @see jQuery
+ */
+ $.isWindow = function( obj ) {
+ return obj && typeof obj === "object" && "setInterval" in obj;
+ };
- isPlainObject: function( obj ) {
- // Must be an Object.
- // 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
- if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || OpenSeadragon.isWindow( obj ) ) {
- return false;
- }
- // Not own constructor property must be Object
- if ( obj.constructor &&
- !hasOwn.call(obj, "constructor") &&
- !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
- return false;
- }
+ /**
+ * Taken from jQuery 1.6.1
+ * @name $.type
+ * @function
+ * @see jQuery
+ */
+ $.type = function( obj ) {
+ return obj == null ?
+ String( obj ) :
+ class2type[ toString.call(obj) ] || "object";
+ };
- // Own properties are enumerated firstly, so to speed up,
- // if last one is own, then all properties are own.
- var key;
- for ( key in obj ) {}
-
- return key === undefined || hasOwn.call( obj, key );
- },
-
- isEmptyObject: function( obj ) {
- for ( var name in obj ) {
- return false;
- }
- return true;
+ /**
+ * Taken from jQuery 1.6.1
+ * @name $.isPlainObject
+ * @function
+ * @see jQuery
+ */
+ $.isPlainObject = function( obj ) {
+ // Must be an Object.
+ // 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
+ if ( !obj || OpenSeadragon.type(obj) !== "object" || obj.nodeType || $.isWindow( obj ) ) {
+ return false;
}
+ // Not own constructor property must be Object
+ if ( obj.constructor &&
+ !hasOwn.call(obj, "constructor") &&
+ !hasOwn.call(obj.constructor.prototype, "isPrototypeOf") ) {
+ return false;
+ }
+
+ // Own properties are enumerated firstly, so to speed up,
+ // if last one is own, then all properties are own.
+
+ var key;
+ for ( key in obj ) {}
+
+ return key === undefined || hasOwn.call( obj, key );
};
-}());
-
-(function( $ ){
/**
- * @static
- * @ignore
+ * Taken from jQuery 1.6.1
+ * @name $.isEmptyObject
+ * @function
+ * @see jQuery
*/
- $.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 );
- };
+ $.isEmptyObject = function( obj ) {
+ for ( var name in obj ) {
+ return false;
+ }
+ 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( $ ){
+
/**
- * Taken from jQuery 1.6.1, see the jQuery documentation
+ * Taken from jQuery 1.6.1
+ * @see jQuery
*/
$.extend = function() {
var options,
@@ -294,152 +390,115 @@ OpenSeadragon = window.OpenSeadragon || (function(){
// Return the modified object
return target;
};
-
- //The following functions are originally from the Openseadragon Utils
- //module but have been moved to Openseadragon to avoid the 'Utils' anti-
- //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
- //orignally developed by the project.
- /**
- * An enumeration of Browser vendors including UNKNOWN, IE, FIREFOX,
- * SAFARI, CHROME, and OPERA.
- * @static
- */
- $.BROWSERS = {
- UNKNOWN: 0,
- IE: 1,
- FIREFOX: 2,
- SAFARI: 3,
- CHROME: 4,
- OPERA: 5
- };
- /**
- * The current browser vendor, version, and related information regarding
- * detected features. Features include
- * 'alpha' - Does the browser support image alpha
- * transparency.
- * @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( $, {
+ /**
+ * These are the default values for the optional settings documented
+ * 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,
+ * SAFARI, CHROME, and OPERA.
+ * @name $.BROWSERS
+ * @static
+ */
+ BROWSERS: {
+ UNKNOWN: 0,
+ IE: 1,
+ FIREFOX: 2,
+ SAFARI: 3,
+ CHROME: 4,
+ OPERA: 5
+ },
+
/**
* Returns a DOM Element for the given id or element.
@@ -455,6 +514,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element;
},
+
/**
* Determines the position of the upper-left corner of the element.
* @function
@@ -488,6 +548,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result;
},
+
/**
* Determines the height and width of the given element.
* @function
@@ -504,6 +565,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
);
},
+
/**
* Returns the CSSStyle object for the given element.
* @function
@@ -523,6 +585,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Gets the latest event, really only useful internally since its
* specific to IE behavior. TODO: Deprecate this from the api and
@@ -536,6 +599,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return event ? event : window.event;
},
+
/**
* Gets the position of the mouse on the screen for a given event.
* @function
@@ -569,6 +633,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result;
},
+
/**
* Determines the pages current scroll position.
* @function
@@ -594,6 +659,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return result;
},
+
/**
* Determines the size of the browsers window.
* @function
@@ -667,6 +733,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return div;
},
+
/**
* Creates an easily positionable element of the given type that therefor
* serves as an excellent container element.
@@ -688,6 +755,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element;
},
+
/**
* Ensures an image is loaded correctly to support alpha transparency.
* Generally only IE has issues doing this correctly for formats like
@@ -731,6 +799,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return element;
},
+
/**
* Sets the opacity of the specified element.
* @function
@@ -779,6 +848,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Adds an event listener for the given element, eventName and handler.
* @function
@@ -808,6 +878,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Remove a given event listener for the given element, event type and
* handler.
@@ -838,6 +909,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
}
},
+
/**
* Cancels the default browser behavior had the event propagated all
* the way up the DOM to the window object.
@@ -858,6 +930,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
event.returnValue = false;
},
+
/**
* Stops the propagation of the event up the DOM.
* @function
@@ -874,6 +947,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
event.cancelBubble = true; // IE for stopping propagation
},
+
/**
* Similar to OpenSeadragon.delegate, but it does not immediately call
* 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.
* @function
@@ -922,6 +997,7 @@ OpenSeadragon = window.OpenSeadragon || (function(){
return value ? value : null;
},
+
/**
* Makes an AJAX request.
* @function
@@ -1077,6 +1153,138 @@ OpenSeadragon = window.OpenSeadragon || (function(){
});
+
+ /**
+ * The current browser vendor, version, and related information regarding
+ * detected features. Features include
+ * 'alpha' - Does the browser support image alpha
+ * transparency.
+ * @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
* @inner
diff --git a/src/tile.js b/src/tile.js
index c82d04ff..d677153e 100644
--- a/src/tile.js
+++ b/src/tile.js
@@ -7,18 +7,18 @@
* @param {Number} x The vector component 'x'.
* @param {Number} y The vector component 'y'.
* @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
- * this tile failed to load?
+ * this tile failed to load? )
* @param {String} url The URL of this tile's image.
*
* @property {Number} level The zoom level this tile belongs to.
* @property {Number} x The vector component 'x'.
* @property {Number} y The vector component 'y'.
* @property {OpenSeadragon.Point} bounds Where this tile fits, in normalized
- * coordinates
+ * coordinates
* @property {Boolean} exists Is this tile a part of a sparse image? ( Also has
- * this tile failed to load?
+ * this tile failed to load?
* @property {String} url The URL of this tile's image.
* @property {Boolean} loaded Is this tile loaded?
* @property {Boolean} loading Is this tile loading
diff --git a/src/viewer.js b/src/viewer.js
index 6f948b0e..61b0494f 100644
--- a/src/viewer.js
+++ b/src/viewer.js
@@ -35,6 +35,8 @@ $.Viewer = function( options ) {
$.EventHandler.call( this );
+ //backward compatibility for positional args while prefering more
+ //idiomatic javascript options object as the only argument
if( !$.isPlainObject( options ) ){
options = {
id: args[ 0 ],
@@ -42,29 +44,29 @@ $.Viewer = function( options ) {
prefixUrl: args.length > 2 ? args[ 2 ] : undefined,
controls: args.length > 3 ? args[ 3 ] : undefined,
overlays: args.length > 4 ? args[ 4 ] : undefined,
- overlayControls: args.length > 5 ? args[ 5 ] : undefined,
- config: {}
+ overlayControls: args.length > 5 ? args[ 5 ] : undefined
};
}
+
+ //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
$.extend( true, this, {
+
id: options.id,
- xmlPath: null,
- tileSources: null,
+ hash: options.id,
controls: [],
overlays: [],
overlayControls: [],
- config: $.DEFAULT_SETTINGS,
- //These were referenced but never defined
-
- //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,
+ //private state properties
+ previousBody: [],
//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
@@ -72,11 +74,18 @@ $.Viewer = function( options ) {
//this array was returned from get_controls which I find confusing
//since this object has a controls property which is treated in other
//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.canvas = $.makeNeutralElement( "div" );
@@ -87,9 +96,6 @@ $.Viewer = function( options ) {
this.bodyHeight = document.body.style.height;
this.bodyOverflow = document.body.style.overflow;
this.docOverflow = document.documentElement.style.overflow;
- this.previousBody = [];
-
- this.hash = Math.random();
THIS[ this.hash ] = {
"fsBoundsDelta": new $.Point( 1, 1 ),
@@ -103,8 +109,8 @@ $.Viewer = function( options ) {
this.innerTracker = new $.MouseTracker({
element: this.canvas,
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
clickHandler: $.delegate( this, onCanvasClick ),
dragHandler: $.delegate( this, onCanvasDrag ),
releaseHandler: $.delegate( this, onCanvasRelease ),
@@ -113,8 +119,8 @@ $.Viewer = function( options ) {
this.outerTracker = new $.MouseTracker({
element: this.container,
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
enterHandler: $.delegate( this, onContainerEnter ),
exitHandler: $.delegate( this, onContainerExit ),
releaseHandler: $.delegate( this, onContainerRelease )
@@ -180,15 +186,15 @@ $.Viewer = function( options ) {
doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ),
onHomeHandler = $.delegate( this, onHome ),
onFullPageHandler = $.delegate( this, onFullPage ),
- navImages = this.config.navImages,
+ navImages = this.navImages,
zoomIn = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.ZoomIn" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.zoomIn.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.zoomIn.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.zoomIn.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.zoomIn.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.zoomIn.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.zoomIn.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.zoomIn.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.zoomIn.DOWN ),
onPress: beginZoomingInHandler,
onRelease: endZoomingHandler,
onClick: doSingleZoomInHandler,
@@ -196,13 +202,13 @@ $.Viewer = function( options ) {
onExit: endZoomingHandler
}),
zoomOut = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.ZoomOut" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.zoomOut.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.zoomOut.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.zoomOut.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.zoomOut.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.zoomOut.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.zoomOut.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.zoomOut.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.zoomOut.DOWN ),
onPress: beginZoomingOutHandler,
onRelease: endZoomingHandler,
onClick: doSingleZoomOutHandler,
@@ -210,29 +216,29 @@ $.Viewer = function( options ) {
onExit: endZoomingHandler
}),
goHome = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.Home" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.home.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.home.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.home.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.home.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.home.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.home.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.home.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.home.DOWN ),
onRelease: onHomeHandler
}),
fullPage = new $.Button({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.FullPage" ),
- srcRest: resolveUrl( this.config.prefixUrl, navImages.fullpage.REST ),
- srcGroup: resolveUrl( this.config.prefixUrl, navImages.fullpage.GROUP ),
- srcHover: resolveUrl( this.config.prefixUrl, navImages.fullpage.HOVER ),
- srcDown: resolveUrl( this.config.prefixUrl, navImages.fullpage.DOWN ),
+ srcRest: resolveUrl( this.prefixUrl, navImages.fullpage.REST ),
+ srcGroup: resolveUrl( this.prefixUrl, navImages.fullpage.GROUP ),
+ srcHover: resolveUrl( this.prefixUrl, navImages.fullpage.HOVER ),
+ srcDown: resolveUrl( this.prefixUrl, navImages.fullpage.DOWN ),
onRelease: onFullPageHandler
});
this.buttons = new $.ButtonGroup({
- clickTimeThreshold: this.config.clickTimeThreshold,
- clickDistThreshold: this.config.clickDistThreshold,
+ clickTimeThreshold: this.clickTimeThreshold,
+ clickDistThreshold: this.clickDistThreshold,
buttons: [
zoomIn,
zoomOut,
@@ -245,7 +251,7 @@ $.Viewer = function( options ) {
this.navControl[ $.SIGNAL ] = true; // hack to get our controls to fade
this.addHandler( 'open', $.delegate( this, lightUp ) );
- if ( this.config.showNavigationControl ) {
+ if ( this.showNavigationControl ) {
this.navControl.style.marginRight = "4px";
this.navControl.style.marginBottom = "4px";
this.addControl( this.navControl, $.ControlAnchor.BOTTOM_RIGHT );
@@ -297,7 +303,7 @@ $.Viewer = function( options ) {
initialTileSource = this.tileSources
}
- if ( $.type( initialTileSource ) == 'string ') {
+ if ( $.type( initialTileSource ) == 'string') {
//Standard DZI format
this.openDzi( initialTileSource );
} else if ( $.isArray( initialTileSource ) ){
@@ -309,9 +315,6 @@ $.Viewer = function( options ) {
customTileSource.getTileUrl = initialTileSource;
this.open( customTileSource );
}
-
-
-
}
};
@@ -433,16 +436,31 @@ $.extend( $.Viewer.prototype, $.EventHandler.prototype, {
}
this.viewport = new $.Viewport({
- containerSize: THIS[ this.hash ].prevContainerSize,
- contentSize: this.source.dimensions,
- config: this.config
+ 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
});
- this.drawer = new $.Drawer(
- this.source,
- this.viewport,
- this.canvas
- );
+ this.drawer = new $.Drawer({
+ source: this.source,
+ viewport: this.viewport,
+ 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();
@@ -759,17 +777,17 @@ function scheduleControlsFade( viewer ) {
//initiates an animation to hide the controls
function beginControlsAutoHide( viewer ) {
- if ( !viewer.config.autoHideControls ) {
+ if ( !viewer.autoHideControls ) {
return;
}
viewer.controlsShouldFade = true;
viewer.controlsFadeBeginTime =
+new Date() +
- viewer.config.controlsFadeDelay;
+ viewer.controlsFadeDelay;
window.setTimeout( function(){
scheduleControlsFade( viewer );
- }, viewer.config.controlsFadeDelay );
+ }, viewer.controlsFadeDelay );
};
@@ -782,7 +800,7 @@ function updateControlsFade( viewer ) {
if ( viewer.controlsShouldFade ) {
currentTime = new Date().getTime();
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.max( 0.0, opacity );
@@ -815,7 +833,7 @@ function onCanvasClick( tracker, position, quick, shift ) {
var zoomPreClick,
factor;
if ( this.viewport && quick ) { // ignore clicks where mouse moved
- zoomPerClick = this.config.zoomPerClick;
+ zoomPerClick = this.zoomPerClick;
factor = shift ? 1.0 / zoomPerClick : zoomPerClick;
this.viewport.zoomBy(
factor,
@@ -844,7 +862,7 @@ function onCanvasRelease( tracker, position, insideElementPress, insideElementRe
function onCanvasScroll( tracker, position, scroll, shift ) {
var factor;
if ( this.viewport ) {
- factor = Math.pow( this.config.zoomPerScroll, scroll );
+ factor = Math.pow( this.zoomPerScroll, scroll );
this.viewport.zoomBy(
factor,
this.viewport.pointFromPixel( position, true )
@@ -963,14 +981,14 @@ function resolveUrl( prefix, url ) {
function beginZoomingIn() {
THIS[ this.hash ].lastZoomTime = +new Date();
- THIS[ this.hash ].zoomFactor = this.config.zoomPerSecond;
+ THIS[ this.hash ].zoomFactor = this.zoomPerSecond;
THIS[ this.hash ].zooming = true;
scheduleZoom( this );
}
function beginZoomingOut() {
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;
scheduleZoom( this );
}
@@ -1004,7 +1022,7 @@ function doSingleZoomIn() {
if ( this.viewport ) {
THIS[ this.hash ].zooming = false;
this.viewport.zoomBy(
- this.config.zoomPerClick / 1.0
+ this.zoomPerClick / 1.0
);
this.viewport.applyConstraints();
}
@@ -1014,7 +1032,7 @@ function doSingleZoomOut() {
if ( this.viewport ) {
THIS[ this.hash ].zooming = false;
this.viewport.zoomBy(
- 1.0 / this.config.zoomPerClick
+ 1.0 / this.zoomPerClick
);
this.viewport.applyConstraints();
}
diff --git a/src/viewport.js b/src/viewport.js
index 8f3cdb16..b00e1093 100644
--- a/src/viewport.js
+++ b/src/viewport.js
@@ -7,44 +7,64 @@
*/
$.Viewport = function( options ) {
-
- if( arguments.length && arguments[ 0 ] instanceof $.Point ){
+ //backward compatibility for positional args while prefering more
+ //idiomatic javascript options object as the only argument
+ var args = arguments;
+ if( args.length && args[ 0 ] instanceof $.Point ){
options = {
- containerSize: arguments[ 0 ],
- contentSize: arguments[ 1 ],
- config: arguments[ 2 ]
+ containerSize: args[ 0 ],
+ contentSize: args[ 1 ],
+ config: args[ 2 ]
};
}
- //TODO: this.config is something that should go away but currently the
- // Drawer references the viewport.config
- this.config = options.config;
- this.zoomPoint = null;
- this.containerSize = options.containerSize;
- this.contentSize = options.contentSize;
+ //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;
+ }
+
+ $.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.contentHeight = this.contentSize.y / this.contentSize.x;
this.centerSpringX = new $.Spring({
initial: 0,
- springStiffness: this.config.springStiffness,
- animationTime: this.config.animationTime
+ springStiffness: this.springStiffness,
+ animationTime: this.animationTime
});
this.centerSpringY = new $.Spring({
initial: 0,
- springStiffness: this.config.springStiffness,
- animationTime: this.config.animationTime
+ springStiffness: this.springStiffness,
+ animationTime: this.animationTime
});
this.zoomSpring = new $.Spring({
initial: 1,
- springStiffness: this.config.springStiffness,
- animationTime: this.config.animationTime
+ springStiffness: this.springStiffness,
+ 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.update();