mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 14:46:10 +03:00
parent
6ca934d0ca
commit
04a0197dc7
@ -32,123 +32,125 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
(function($){
|
||||
|
||||
/**
|
||||
* For use by classes which want to support custom, non-browser events.
|
||||
* TODO: This is an aweful name! This thing represents an "event source",
|
||||
* not an "event handler". PLEASE change the to EventSource. Also please
|
||||
* change 'addHandler', 'removeHandler' and 'raiseEvent' to 'bind',
|
||||
* 'unbind', and 'trigger' respectively. Finally add a method 'one' which
|
||||
* automatically unbinds a listener after the first triggered event that
|
||||
* matches.
|
||||
* @class
|
||||
*/
|
||||
$.EventHandler = function() {
|
||||
this.events = {};
|
||||
};
|
||||
|
||||
$.EventHandler.prototype = {
|
||||
(function ($) {
|
||||
|
||||
/**
|
||||
* Add an event handler for a given event.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event to register.
|
||||
* @param {Function} handler - Function to call when event is triggered.
|
||||
*/
|
||||
addHandler: function( eventName, handler ) {
|
||||
var events = this.events[ eventName ];
|
||||
if( !events ){
|
||||
this.events[ eventName ] = events = [];
|
||||
}
|
||||
if( handler && $.isFunction( handler ) ){
|
||||
events[ events.length ] = handler;
|
||||
}
|
||||
},
|
||||
* For use by classes which want to support custom, non-browser events.
|
||||
* TODO: This is an awful name! This thing represents an "event source",
|
||||
* not an "event handler". PLEASE change the to EventSource. Also please
|
||||
* change 'addHandler', 'removeHandler' and 'raiseEvent' to 'bind',
|
||||
* 'unbind', and 'trigger' respectively. Finally add a method 'one' which
|
||||
* automatically unbinds a listener after the first triggered event that
|
||||
* matches.
|
||||
* @class
|
||||
*/
|
||||
$.EventHandler = function () {
|
||||
this.events = {};
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a specific event handler for a given event.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event for which the handler is to be removed.
|
||||
* @param {Function} handler - Function to be removed.
|
||||
*/
|
||||
removeHandler: function( eventName, handler ) {
|
||||
var events = this.events[ eventName ],
|
||||
$.EventHandler.prototype = {
|
||||
|
||||
/**
|
||||
* Add an event handler for a given event.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event to register.
|
||||
* @param {Function} handler - Function to call when event is triggered.
|
||||
* @param {Object} optional userData - Arbitrary object to be passed to the handler.
|
||||
*/
|
||||
addHandler: function (eventName, handler, userData) {
|
||||
var events = this.events[eventName];
|
||||
if (!events) {
|
||||
this.events[eventName] = events = [];
|
||||
}
|
||||
if (handler && $.isFunction(handler)) {
|
||||
events[events.length] = { handler: handler, userData: userData || null };
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove a specific event handler for a given event.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event for which the handler is to be removed.
|
||||
* @param {Function} handler - Function to be removed.
|
||||
*/
|
||||
removeHandler: function (eventName, handler) {
|
||||
var events = this.events[eventName],
|
||||
handlers = [],
|
||||
i;
|
||||
if ( !events ){
|
||||
return;
|
||||
}
|
||||
if( $.isArray( events ) ){
|
||||
for( i = 0; i < events.length; i++ ){
|
||||
if( events[ i ] !== handler ){
|
||||
handlers.push( events[ i ] );
|
||||
if (!events) {
|
||||
return;
|
||||
}
|
||||
if ($.isArray(events)) {
|
||||
for (i = 0; i < events.length; i++) {
|
||||
if (events[i].handler !== handler) {
|
||||
handlers.push(events[i]);
|
||||
}
|
||||
}
|
||||
this.events[eventName] = handlers;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Remove all event handlers for a given event type. If no type is given all
|
||||
* event handlers for every event type are removed.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event for which all handlers are to be removed.
|
||||
*/
|
||||
removeAllHandlers: function (eventName) {
|
||||
if (eventName) {
|
||||
this.events[eventName] = [];
|
||||
} else {
|
||||
for (var eventType in this.events) {
|
||||
this.events[eventType] = [];
|
||||
}
|
||||
}
|
||||
this.events[ eventName ] = handlers;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Remove all event handlers for a given event type. If no type is given all
|
||||
* event handlers for every event type are removed.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event for which all handlers are to be removed.
|
||||
*/
|
||||
removeAllHandlers: function( eventName ) {
|
||||
if (eventName){
|
||||
this.events[ eventName ] = [];
|
||||
} else{
|
||||
for (var eventType in this.events) {
|
||||
this.events[eventType] = [];
|
||||
/**
|
||||
* Retrieve the list of all handlers registered for a given event.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event to get handlers for.
|
||||
*/
|
||||
getHandler: function (eventName) {
|
||||
var events = this.events[eventName];
|
||||
if (!events || !events.length) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrive the list of all handlers registered for a given event.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event to get handlers for.
|
||||
*/
|
||||
getHandler: function( eventName ) {
|
||||
var events = this.events[ eventName ];
|
||||
if ( !events || !events.length ){
|
||||
return null;
|
||||
}
|
||||
events = events.length === 1 ?
|
||||
[ events[ 0 ] ] :
|
||||
Array.apply( null, events );
|
||||
return function( source, args ) {
|
||||
var i,
|
||||
events = events.length === 1 ?
|
||||
[events[0]] :
|
||||
Array.apply(null, events);
|
||||
return function (source, args) {
|
||||
var i,
|
||||
length = events.length;
|
||||
for ( i = 0; i < length; i++ ) {
|
||||
if( events[ i ] ){
|
||||
events[ i ]( source, args );
|
||||
for (i = 0; i < length; i++) {
|
||||
if (events[i]) {
|
||||
args.userData = events[i].userData;
|
||||
events[i].handler(source, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger an event, optionally passing additional information.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event to register.
|
||||
* @param {Function} handler - Function to call when event is triggered.
|
||||
*/
|
||||
raiseEvent: function (eventName, eventArgs) {
|
||||
//uncomment if you want to get a log of all events
|
||||
//$.console.log( eventName );
|
||||
var handler = this.getHandler(eventName);
|
||||
|
||||
if (handler) {
|
||||
if (!eventArgs) {
|
||||
eventArgs = {};
|
||||
}
|
||||
|
||||
handler(this, eventArgs);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Trigger an event, optionally passing additional information.
|
||||
* @function
|
||||
* @param {String} eventName - Name of event to register.
|
||||
* @param {Function} handler - Function to call when event is triggered.
|
||||
*/
|
||||
raiseEvent: function( eventName, eventArgs ) {
|
||||
//uncomment if you want to get a log of all events
|
||||
//$.console.log( eventName );
|
||||
var handler = this.getHandler( eventName );
|
||||
|
||||
if ( handler ) {
|
||||
if ( !eventArgs ) {
|
||||
eventArgs = {};
|
||||
}
|
||||
|
||||
handler( this, eventArgs );
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
}( OpenSeadragon ));
|
||||
} (OpenSeadragon));
|
||||
|
@ -32,267 +32,278 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
(function( $ ){
|
||||
(function ($) {
|
||||
|
||||
/**
|
||||
* The LegacyTileSource allows simple, traditional image pyramids to be loaded
|
||||
* into an OpenSeadragon Viewer. Basically, this translates to the historically
|
||||
* common practice of starting with a 'master' image, maybe a tiff for example,
|
||||
* and generating a set of 'service' images like one or more thumbnails, a medium
|
||||
* resolution image and a high resolution image in standard web formats like
|
||||
* png or jpg.
|
||||
* @class
|
||||
* @extends OpenSeadragon.TileSource
|
||||
* @param {Array} levels An array of file descriptions, each is an object with
|
||||
* a 'url', a 'width', and a 'height'. Overriding classes can expect more
|
||||
* properties but these properties are sufficient for this implementation.
|
||||
* Additionally, the levels are required to be listed in order from
|
||||
* smallest to largest.
|
||||
* @property {Number} aspectRatio
|
||||
* @property {Number} dimensions
|
||||
* @property {Number} tileSize
|
||||
* @property {Number} tileOverlap
|
||||
* @property {Number} minLevel
|
||||
* @property {Number} maxLevel
|
||||
* @property {Array} levels
|
||||
*/
|
||||
$.LegacyTileSource = function( levels ) {
|
||||
/**
|
||||
* The LegacyTileSource allows simple, traditional image pyramids to be loaded
|
||||
* into an OpenSeadragon Viewer. Basically, this translates to the historically
|
||||
* common practice of starting with a 'master' image, maybe a tiff for example,
|
||||
* and generating a set of 'service' images like one or more thumbnails, a medium
|
||||
* resolution image and a high resolution image in standard web formats like
|
||||
* png or jpg.
|
||||
* @class
|
||||
* @extends OpenSeadragon.TileSource
|
||||
* @param {Array} levels An array of file descriptions, each is an object with
|
||||
* a 'url', a 'width', and a 'height'. Overriding classes can expect more
|
||||
* properties but these properties are sufficient for this implementation.
|
||||
* Additionally, the levels are required to be listed in order from
|
||||
* smallest to largest.
|
||||
* @property {Number} aspectRatio
|
||||
* @property {Number} dimensions
|
||||
* @property {Number} tileSize
|
||||
* @property {Number} tileOverlap
|
||||
* @property {Number} minLevel
|
||||
* @property {Number} maxLevel
|
||||
* @property {Array} levels
|
||||
*/
|
||||
$.LegacyTileSource = function (levels) {
|
||||
|
||||
var options,
|
||||
var options,
|
||||
width,
|
||||
height;
|
||||
|
||||
if( $.isArray( levels ) ){
|
||||
options = {
|
||||
type: 'legacy-image-pyramid',
|
||||
levels: levels
|
||||
};
|
||||
}
|
||||
if ($.isArray(levels)) {
|
||||
options = {
|
||||
type: 'legacy-image-pyramid',
|
||||
levels: levels
|
||||
};
|
||||
}
|
||||
|
||||
//clean up the levels to make sure we support all formats
|
||||
options.levels = filterFiles( options.levels );
|
||||
width = options.levels[ options.levels.length - 1 ].width;
|
||||
height = options.levels[ options.levels.length - 1 ].height;
|
||||
//clean up the levels to make sure we support all formats
|
||||
options.levels = filterFiles(options.levels);
|
||||
|
||||
$.extend( true, options, {
|
||||
width: width,
|
||||
height: height,
|
||||
tileSize: Math.max( height, width ),
|
||||
tileOverlap: 0,
|
||||
minLevel: 0,
|
||||
maxLevel: options.levels.length - 1
|
||||
});
|
||||
if (options.levels.length > 0) {
|
||||
width = options.levels[options.levels.length - 1].width;
|
||||
height = options.levels[options.levels.length - 1].height;
|
||||
}
|
||||
else {
|
||||
width = 0;
|
||||
height = 0;
|
||||
$.console.error("No supported image formats found");
|
||||
}
|
||||
|
||||
$.TileSource.apply( this, [ options ] );
|
||||
$.extend(true, options, {
|
||||
width: width,
|
||||
height: height,
|
||||
tileSize: Math.max(height, width),
|
||||
tileOverlap: 0,
|
||||
minLevel: 0,
|
||||
maxLevel: options.levels.length > 0 ? options.levels.length - 1 : 0
|
||||
});
|
||||
|
||||
this.levels = options.levels;
|
||||
};
|
||||
$.TileSource.apply(this, [options]);
|
||||
|
||||
$.extend( $.LegacyTileSource.prototype, $.TileSource.prototype, {
|
||||
/**
|
||||
* Determine if the data and/or url imply the image service is supported by
|
||||
* this tile source.
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.supports
|
||||
* @param {Object|Array} data
|
||||
* @param {String} optional - url
|
||||
*/
|
||||
supports: function( data, url ){
|
||||
return (
|
||||
this.levels = options.levels;
|
||||
};
|
||||
|
||||
$.extend($.LegacyTileSource.prototype, $.TileSource.prototype, {
|
||||
/**
|
||||
* Determine if the data and/or url imply the image service is supported by
|
||||
* this tile source.
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.supports
|
||||
* @param {Object|Array} data
|
||||
* @param {String} optional - url
|
||||
*/
|
||||
supports: function (data, url) {
|
||||
return (
|
||||
data.type &&
|
||||
"legacy-image-pyramid" == data.type
|
||||
) || (
|
||||
data.documentElement &&
|
||||
"legacy-image-pyramid" == data.documentElement.getAttribute('type')
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.configure
|
||||
* @param {Object|XMLDocument} configuration - the raw configuration
|
||||
* @param {String} dataUrl - the url the data was retreived from if any.
|
||||
* @return {Object} options - A dictionary of keyword arguments sufficient
|
||||
* to configure this tile sources constructor.
|
||||
*/
|
||||
configure: function( configuration, dataUrl ){
|
||||
/**
|
||||
*
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.configure
|
||||
* @param {Object|XMLDocument} configuration - the raw configuration
|
||||
* @param {String} dataUrl - the url the data was retreived from if any.
|
||||
* @return {Object} options - A dictionary of keyword arguments sufficient
|
||||
* to configure this tile sources constructor.
|
||||
*/
|
||||
configure: function (configuration, dataUrl) {
|
||||
|
||||
var options;
|
||||
var options;
|
||||
|
||||
if( !$.isPlainObject(configuration) ){
|
||||
if (!$.isPlainObject(configuration)) {
|
||||
|
||||
options = configureFromXML( this, configuration );
|
||||
options = configureFromXML(this, configuration);
|
||||
|
||||
}else{
|
||||
} else {
|
||||
|
||||
options = configureFromObject( this, configuration );
|
||||
options = configureFromObject(this, configuration);
|
||||
}
|
||||
|
||||
return options;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getLevelScale
|
||||
* @param {Number} level
|
||||
*/
|
||||
getLevelScale: function (level) {
|
||||
var levelScale = NaN;
|
||||
if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) {
|
||||
levelScale =
|
||||
this.levels[level].width /
|
||||
this.levels[this.maxLevel].width;
|
||||
}
|
||||
return levelScale;
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getNumTiles
|
||||
* @param {Number} level
|
||||
*/
|
||||
getNumTiles: function (level) {
|
||||
var scale = this.getLevelScale(level);
|
||||
if (scale) {
|
||||
return new $.Point(1, 1);
|
||||
} else {
|
||||
return new $.Point(0, 0);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getTileAtPoint
|
||||
* @param {Number} level
|
||||
* @param {OpenSeadragon.Point} point
|
||||
*/
|
||||
getTileAtPoint: function (level, point) {
|
||||
return new $.Point(0, 0);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* This method is not implemented by this class other than to throw an Error
|
||||
* announcing you have to implement it. Because of the variety of tile
|
||||
* server technologies, and various specifications for building image
|
||||
* pyramids, this method is here to allow easy integration.
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getTileUrl
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @throws {Error}
|
||||
*/
|
||||
getTileUrl: function (level, x, y) {
|
||||
var url = null;
|
||||
if (this.levels.length > 0 && level >= this.minLevel && level <= this.maxLevel) {
|
||||
url = this.levels[level].url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
return options;
|
||||
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getLevelScale
|
||||
* @param {Number} level
|
||||
*/
|
||||
getLevelScale: function( level ) {
|
||||
var levelScale = NaN;
|
||||
if ( level >= this.minLevel && level <= this.maxLevel ){
|
||||
levelScale =
|
||||
this.levels[ level ].width /
|
||||
this.levels[ this.maxLevel ].width;
|
||||
}
|
||||
return levelScale;
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getNumTiles
|
||||
* @param {Number} level
|
||||
*/
|
||||
getNumTiles: function( level ) {
|
||||
var scale = this.getLevelScale( level );
|
||||
if ( scale ){
|
||||
return new $.Point( 1, 1 );
|
||||
} else {
|
||||
return new $.Point( 0, 0 );
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getTileAtPoint
|
||||
* @param {Number} level
|
||||
* @param {OpenSeadragon.Point} point
|
||||
*/
|
||||
getTileAtPoint: function( level, point ) {
|
||||
return new $.Point( 0, 0 );
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* This method is not implemented by this class other than to throw an Error
|
||||
* announcing you have to implement it. Because of the variety of tile
|
||||
* server technologies, and various specifications for building image
|
||||
* pyramids, this method is here to allow easy integration.
|
||||
* @function
|
||||
* @name OpenSeadragon.LegacyTileSource.prototype.getTileUrl
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @throws {Error}
|
||||
*/
|
||||
getTileUrl: function( level, x, y ) {
|
||||
var url = null;
|
||||
if( level >= this.minLevel && level <= this.maxLevel ){
|
||||
url = this.levels[ level ].url;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* This method removes any files from the Array which dont conform to our
|
||||
* basic requirements for a 'level' in the LegacyTileSource.
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function filterFiles( files ){
|
||||
var filtered = [],
|
||||
* This method removes any files from the Array which dont conform to our
|
||||
* basic requirements for a 'level' in the LegacyTileSource.
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function filterFiles(files) {
|
||||
var filtered = [],
|
||||
file,
|
||||
i;
|
||||
for( i = 0; i < files.length; i++ ){
|
||||
file = files[ i ];
|
||||
if( file.height &&
|
||||
for (i = 0; i < files.length; i++) {
|
||||
file = files[i];
|
||||
if (file.height &&
|
||||
file.width &&
|
||||
file.url && (
|
||||
file.url.toLowerCase().match(/^.*\.(png|jpg|jpeg|gif)$/) || (
|
||||
file.mimetype &&
|
||||
file.mimetype.toLowerCase().match(/^.*\/(png|jpg|jpeg|gif)$/)
|
||||
)
|
||||
) ){
|
||||
//This is sufficient to serve as a level
|
||||
filtered.push({
|
||||
url: file.url,
|
||||
width: Number( file.width ),
|
||||
height: Number( file.height )
|
||||
});
|
||||
)) {
|
||||
//This is sufficient to serve as a level
|
||||
filtered.push({
|
||||
url: file.url,
|
||||
width: Number(file.width),
|
||||
height: Number(file.height)
|
||||
});
|
||||
}
|
||||
else {
|
||||
$.console.error('Unsupported image format: %s', file.url ? file.url : '<no URL>');
|
||||
}
|
||||
}
|
||||
|
||||
return filtered.sort(function (a, b) {
|
||||
return a.height - b.height;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return filtered.sort(function(a,b){
|
||||
return a.height - b.height;
|
||||
});
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function configureFromXML(tileSource, xmlDoc) {
|
||||
|
||||
}
|
||||
if (!xmlDoc || !xmlDoc.documentElement) {
|
||||
throw new Error($.getString("Errors.Xml"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function configureFromXML( tileSource, xmlDoc ){
|
||||
|
||||
if ( !xmlDoc || !xmlDoc.documentElement ) {
|
||||
throw new Error( $.getString( "Errors.Xml" ) );
|
||||
}
|
||||
|
||||
var root = xmlDoc.documentElement,
|
||||
rootName = root.tagName,
|
||||
conf = null,
|
||||
levels = [],
|
||||
var root = xmlDoc.documentElement,
|
||||
rootName = root.tagName,
|
||||
conf = null,
|
||||
levels = [],
|
||||
level,
|
||||
i;
|
||||
|
||||
if ( rootName == "image" ) {
|
||||
if (rootName == "image") {
|
||||
|
||||
try {
|
||||
conf = {
|
||||
type: root.getAttribute( "type" ),
|
||||
levels: []
|
||||
};
|
||||
try {
|
||||
conf = {
|
||||
type: root.getAttribute("type"),
|
||||
levels: []
|
||||
};
|
||||
|
||||
levels = root.getElementsByTagName( "level" );
|
||||
for ( i = 0; i < levels.length; i++ ) {
|
||||
level = levels[ i ];
|
||||
levels = root.getElementsByTagName("level");
|
||||
for (i = 0; i < levels.length; i++) {
|
||||
level = levels[i];
|
||||
|
||||
conf.levels .push({
|
||||
url: level.getAttribute( "url" ),
|
||||
width: parseInt( level.getAttribute( "width" ), 10 ),
|
||||
height: parseInt( level.getAttribute( "height" ), 10 )
|
||||
});
|
||||
}
|
||||
conf.levels.push({
|
||||
url: level.getAttribute("url"),
|
||||
width: parseInt(level.getAttribute("width"), 10),
|
||||
height: parseInt(level.getAttribute("height"), 10)
|
||||
});
|
||||
}
|
||||
|
||||
return configureFromObject( tileSource, conf );
|
||||
return configureFromObject(tileSource, conf);
|
||||
|
||||
} catch ( e ) {
|
||||
throw (e instanceof Error) ?
|
||||
} catch (e) {
|
||||
throw (e instanceof Error) ?
|
||||
e :
|
||||
new Error( 'Unknown error parsing Legacy Image Pyramid XML.' );
|
||||
new Error('Unknown error parsing Legacy Image Pyramid XML.');
|
||||
}
|
||||
} else if (rootName == "collection") {
|
||||
throw new Error('Legacy Image Pyramid Collections not yet supported.');
|
||||
} else if (rootName == "error") {
|
||||
throw new Error('Error: ' + xmlDoc);
|
||||
}
|
||||
} else if ( rootName == "collection" ) {
|
||||
throw new Error( 'Legacy Image Pyramid Collections not yet supported.' );
|
||||
} else if ( rootName == "error" ) {
|
||||
throw new Error( 'Error: ' + xmlDoc );
|
||||
|
||||
throw new Error('Unknown element ' + rootName);
|
||||
}
|
||||
|
||||
throw new Error( 'Unknown element ' + rootName );
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function configureFromObject(tileSource, configuration) {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @inner
|
||||
* @function
|
||||
*/
|
||||
function configureFromObject( tileSource, configuration ){
|
||||
return configuration.levels;
|
||||
|
||||
return configuration.levels;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}( OpenSeadragon ));
|
||||
} (OpenSeadragon));
|
||||
|
@ -32,247 +32,247 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
(function( $ ){
|
||||
(function ($) {
|
||||
|
||||
|
||||
/**
|
||||
* The TileSource contains the most basic implementation required to create a
|
||||
* smooth transition between layer in an image pyramid. It has only a single key
|
||||
* interface that must be implemented to complete it key functionality:
|
||||
* 'getTileUrl'. It also has several optional interfaces that can be
|
||||
* implemented if a new TileSource wishes to support configuration via a simple
|
||||
* object or array ('configure') and if the tile source supports or requires
|
||||
* configuration via retreival of a document on the network ala AJAX or JSONP,
|
||||
* ('getImageInfo').
|
||||
* <br/>
|
||||
* By default the image pyramid is split into N layers where the images longest
|
||||
* side in M (in pixels), where N is the smallest integer which satisfies
|
||||
* <strong>2^(N+1) >= M</strong>.
|
||||
* @class
|
||||
* @extends OpenSeadragon.EventHandler
|
||||
* @param {Number|Object|Array|String} width
|
||||
* If more than a single argument is supplied, the traditional use of
|
||||
* positional parameters is supplied and width is expected to be the width
|
||||
* source image at it's max resolution in pixels. If a single argument is supplied and
|
||||
* it is an Object or Array, the construction is assumed to occur through
|
||||
* the extending classes implementation of 'configure'. Finally if only a
|
||||
* single argument is supplied and it is a String, the extending class is
|
||||
* expected to implement 'getImageInfo' and 'configure'.
|
||||
* @param {Number} height
|
||||
* Width of the source image at max resolution in pixels.
|
||||
* @param {Number} tileSize
|
||||
* The size of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* Tile size determines the point at which the image pyramid must be
|
||||
* divided into a matrix of smaller images.
|
||||
* @param {Number} tileOverlap
|
||||
* The number of pixels each tile is expected to overlap touching tiles.
|
||||
* @param {Number} minLevel
|
||||
* The minimum level to attempt to load.
|
||||
* @param {Number} maxLevel
|
||||
* The maximum level to attempt to load.
|
||||
* @property {Number} aspectRatio
|
||||
* Ratio of width to height
|
||||
* @property {OpenSeadragon.Point} dimensions
|
||||
* Vector storing x and y dimensions ( width and height respectively ).
|
||||
* @property {Number} tileSize
|
||||
* The size of the image tiles used to compose the image.
|
||||
* @property {Number} tileOverlap
|
||||
* The overlap in pixels each tile shares with it's adjacent neighbors.
|
||||
* @property {Number} minLevel
|
||||
* The minimum pyramid level this tile source supports or should attempt to load.
|
||||
* @property {Number} maxLevel
|
||||
* The maximum pyramid level this tile source supports or should attempt to load.
|
||||
*/
|
||||
$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {
|
||||
var callback = null,
|
||||
/**
|
||||
* The TileSource contains the most basic implementation required to create a
|
||||
* smooth transition between layer in an image pyramid. It has only a single key
|
||||
* interface that must be implemented to complete it key functionality:
|
||||
* 'getTileUrl'. It also has several optional interfaces that can be
|
||||
* implemented if a new TileSource wishes to support configuration via a simple
|
||||
* object or array ('configure') and if the tile source supports or requires
|
||||
* configuration via retreival of a document on the network ala AJAX or JSONP,
|
||||
* ('getImageInfo').
|
||||
* <br/>
|
||||
* By default the image pyramid is split into N layers where the images longest
|
||||
* side in M (in pixels), where N is the smallest integer which satisfies
|
||||
* <strong>2^(N+1) >= M</strong>.
|
||||
* @class
|
||||
* @extends OpenSeadragon.EventHandler
|
||||
* @param {Number|Object|Array|String} width
|
||||
* If more than a single argument is supplied, the traditional use of
|
||||
* positional parameters is supplied and width is expected to be the width
|
||||
* source image at it's max resolution in pixels. If a single argument is supplied and
|
||||
* it is an Object or Array, the construction is assumed to occur through
|
||||
* the extending classes implementation of 'configure'. Finally if only a
|
||||
* single argument is supplied and it is a String, the extending class is
|
||||
* expected to implement 'getImageInfo' and 'configure'.
|
||||
* @param {Number} height
|
||||
* Width of the source image at max resolution in pixels.
|
||||
* @param {Number} tileSize
|
||||
* The size of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* Tile size determines the point at which the image pyramid must be
|
||||
* divided into a matrix of smaller images.
|
||||
* @param {Number} tileOverlap
|
||||
* The number of pixels each tile is expected to overlap touching tiles.
|
||||
* @param {Number} minLevel
|
||||
* The minimum level to attempt to load.
|
||||
* @param {Number} maxLevel
|
||||
* The maximum level to attempt to load.
|
||||
* @property {Number} aspectRatio
|
||||
* Ratio of width to height
|
||||
* @property {OpenSeadragon.Point} dimensions
|
||||
* Vector storing x and y dimensions ( width and height respectively ).
|
||||
* @property {Number} tileSize
|
||||
* The size of the image tiles used to compose the image.
|
||||
* @property {Number} tileOverlap
|
||||
* The overlap in pixels each tile shares with it's adjacent neighbors.
|
||||
* @property {Number} minLevel
|
||||
* The minimum pyramid level this tile source supports or should attempt to load.
|
||||
* @property {Number} maxLevel
|
||||
* The maximum pyramid level this tile source supports or should attempt to load.
|
||||
*/
|
||||
$.TileSource = function (width, height, tileSize, tileOverlap, minLevel, maxLevel) {
|
||||
var callback = null,
|
||||
args = arguments,
|
||||
options,
|
||||
i;
|
||||
|
||||
if( $.isPlainObject( width ) ){
|
||||
options = width;
|
||||
}else{
|
||||
options = {
|
||||
width: args[0],
|
||||
height: args[1],
|
||||
tileSize: args[2],
|
||||
tileOverlap: args[3],
|
||||
minLevel: args[4],
|
||||
maxLevel: args[5]
|
||||
};
|
||||
}
|
||||
|
||||
//Tile sources supply some events, namely 'ready' when they must be configured
|
||||
//by asyncronously fetching their configuration data.
|
||||
$.EventHandler.call( this );
|
||||
|
||||
//we allow options to override anything we dont treat as
|
||||
//required via idiomatic options or which is functionally
|
||||
//set depending on the state of the readiness of this tile
|
||||
//source
|
||||
$.extend( true, this, options );
|
||||
|
||||
//Any functions that are passed as arguments are bound to the ready callback
|
||||
/*jshint loopfunc:true*/
|
||||
for( i = 0; i < arguments.length; i++ ){
|
||||
if( $.isFunction( arguments[i] ) ){
|
||||
callback = arguments[ i ];
|
||||
this.addHandler( 'ready', function( placeHolderSource, readySource ){
|
||||
callback( readySource );
|
||||
});
|
||||
//only one callback per constructor
|
||||
break;
|
||||
if ($.isPlainObject(width)) {
|
||||
options = width;
|
||||
} else {
|
||||
options = {
|
||||
width: args[0],
|
||||
height: args[1],
|
||||
tileSize: args[2],
|
||||
tileOverlap: args[3],
|
||||
minLevel: args[4],
|
||||
maxLevel: args[5]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if( 'string' == $.type( arguments[ 0 ] ) ){
|
||||
//in case the getImageInfo method is overriden and/or implies an
|
||||
//async mechanism set some safe defaults first
|
||||
this.aspectRatio = 1;
|
||||
this.dimensions = new $.Point( 10, 10 );
|
||||
this.tileSize = 0;
|
||||
this.tileOverlap = 0;
|
||||
this.minLevel = 0;
|
||||
this.maxLevel = 0;
|
||||
this.ready = false;
|
||||
//configuration via url implies the extending class
|
||||
//implements and 'configure'
|
||||
this.getImageInfo( arguments[ 0 ] );
|
||||
//Tile sources supply some events, namely 'ready' when they must be configured
|
||||
//by asyncronously fetching their configuration data.
|
||||
$.EventHandler.call(this);
|
||||
|
||||
} else {
|
||||
//we allow options to override anything we dont treat as
|
||||
//required via idiomatic options or which is functionally
|
||||
//set depending on the state of the readiness of this tile
|
||||
//source
|
||||
$.extend(true, this, options);
|
||||
|
||||
//explicit configuration via positional args in constructor
|
||||
//or the more idiomatic 'options' object
|
||||
this.ready = true;
|
||||
this.aspectRatio = ( options.width && options.height ) ?
|
||||
( options.width / options.height ) : 1;
|
||||
this.dimensions = new $.Point( options.width, options.height );
|
||||
this.tileSize = options.tileSize ? options.tileSize : 0;
|
||||
this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;
|
||||
this.minLevel = options.minLevel ? options.minLevel : 0;
|
||||
this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?
|
||||
options.maxLevel : (
|
||||
( options.width && options.height ) ? Math.ceil(
|
||||
Math.log( Math.max( options.width, options.height ) ) /
|
||||
Math.log( 2 )
|
||||
) : 0
|
||||
);
|
||||
if( callback && $.isFunction( callback ) ){
|
||||
callback( this );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
$.TileSource.prototype = {
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getLevelScale: function( level ) {
|
||||
|
||||
// see https://github.com/openseadragon/openseadragon/issues/22
|
||||
// we use the tilesources implementation of getLevelScale to generate
|
||||
// a memoized re-implementation
|
||||
var levelScaleCache = {},
|
||||
i;
|
||||
for( i = 0; i <= this.maxLevel; i++ ){
|
||||
levelScaleCache[ i ] = 1 / Math.pow(2, this.maxLevel - i);
|
||||
}
|
||||
this.getLevelScale = function( _level ){
|
||||
return levelScaleCache[ _level ];
|
||||
};
|
||||
return this.getLevelScale( level );
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getNumTiles: function( level ) {
|
||||
var scale = this.getLevelScale( level ),
|
||||
x = Math.ceil( scale * this.dimensions.x / this.tileSize ),
|
||||
y = Math.ceil( scale * this.dimensions.y / this.tileSize );
|
||||
|
||||
return new $.Point( x, y );
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getPixelRatio: function( level ) {
|
||||
var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
rx = 1.0 / imageSizeScaled.x,
|
||||
ry = 1.0 / imageSizeScaled.y;
|
||||
|
||||
return new $.Point(rx, ry);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getClosestLevel: function( rect ) {
|
||||
var i,
|
||||
tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.tileSize ),
|
||||
tiles;
|
||||
for( i = this.minLevel; i < this.maxLevel; i++ ){
|
||||
tiles = this.getNumTiles( i );
|
||||
if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){
|
||||
//Any functions that are passed as arguments are bound to the ready callback
|
||||
/*jshint loopfunc:true*/
|
||||
for (i = 0; i < arguments.length; i++) {
|
||||
if ($.isFunction(arguments[i])) {
|
||||
callback = arguments[i];
|
||||
this.addHandler('ready', function (placeHolderSource, placeHolderArgs) {
|
||||
callback(placeHolderArgs.tileSource);
|
||||
});
|
||||
//only one callback per constructor
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Math.max( 0, i - 1 );
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {OpenSeadragon.Point} point
|
||||
*/
|
||||
getTileAtPoint: function( level, point ) {
|
||||
var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level ) ),
|
||||
tx = Math.floor( pixel.x / this.tileSize ),
|
||||
ty = Math.floor( pixel.y / this.tileSize );
|
||||
if ('string' == $.type(arguments[0])) {
|
||||
//in case the getImageInfo method is overriden and/or implies an
|
||||
//async mechanism set some safe defaults first
|
||||
this.aspectRatio = 1;
|
||||
this.dimensions = new $.Point(10, 10);
|
||||
this.tileSize = 0;
|
||||
this.tileOverlap = 0;
|
||||
this.minLevel = 0;
|
||||
this.maxLevel = 0;
|
||||
this.ready = false;
|
||||
//configuration via url implies the extending class
|
||||
//implements and 'configure'
|
||||
this.getImageInfo(arguments[0]);
|
||||
|
||||
return new $.Point( tx, ty );
|
||||
},
|
||||
} else {
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
getTileBounds: function( level, x, y ) {
|
||||
var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
px = ( x === 0 ) ? 0 : this.tileSize * x - this.tileOverlap,
|
||||
py = ( y === 0 ) ? 0 : this.tileSize * y - this.tileOverlap,
|
||||
sx = this.tileSize + ( x === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
sy = this.tileSize + ( y === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
//explicit configuration via positional args in constructor
|
||||
//or the more idiomatic 'options' object
|
||||
this.ready = true;
|
||||
this.aspectRatio = (options.width && options.height) ?
|
||||
(options.width / options.height) : 1;
|
||||
this.dimensions = new $.Point(options.width, options.height);
|
||||
this.tileSize = options.tileSize ? options.tileSize : 0;
|
||||
this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;
|
||||
this.minLevel = options.minLevel ? options.minLevel : 0;
|
||||
this.maxLevel = (undefined !== options.maxLevel && null !== options.maxLevel) ?
|
||||
options.maxLevel : (
|
||||
(options.width && options.height) ? Math.ceil(
|
||||
Math.log(Math.max(options.width, options.height)) /
|
||||
Math.log(2)
|
||||
) : 0
|
||||
);
|
||||
if (callback && $.isFunction(callback)) {
|
||||
callback(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
$.TileSource.prototype = {
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getLevelScale: function (level) {
|
||||
|
||||
// see https://github.com/openseadragon/openseadragon/issues/22
|
||||
// we use the tilesources implementation of getLevelScale to generate
|
||||
// a memoized re-implementation
|
||||
var levelScaleCache = {},
|
||||
i;
|
||||
for (i = 0; i <= this.maxLevel; i++) {
|
||||
levelScaleCache[i] = 1 / Math.pow(2, this.maxLevel - i);
|
||||
}
|
||||
this.getLevelScale = function (_level) {
|
||||
return levelScaleCache[_level];
|
||||
};
|
||||
return this.getLevelScale(level);
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getNumTiles: function (level) {
|
||||
var scale = this.getLevelScale(level),
|
||||
x = Math.ceil(scale * this.dimensions.x / this.tileSize),
|
||||
y = Math.ceil(scale * this.dimensions.y / this.tileSize);
|
||||
|
||||
return new $.Point(x, y);
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getPixelRatio: function (level) {
|
||||
var imageSizeScaled = this.dimensions.times(this.getLevelScale(level)),
|
||||
rx = 1.0 / imageSizeScaled.x,
|
||||
ry = 1.0 / imageSizeScaled.y;
|
||||
|
||||
return new $.Point(rx, ry);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getClosestLevel: function (rect) {
|
||||
var i,
|
||||
tilesPerSide = Math.floor(Math.max(rect.x, rect.y) / this.tileSize),
|
||||
tiles;
|
||||
for (i = this.minLevel; i < this.maxLevel; i++) {
|
||||
tiles = this.getNumTiles(i);
|
||||
if (Math.max(tiles.x, tiles.y) + 1 >= tilesPerSide) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Math.max(0, i - 1);
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {OpenSeadragon.Point} point
|
||||
*/
|
||||
getTileAtPoint: function (level, point) {
|
||||
var pixel = point.times(this.dimensions.x).times(this.getLevelScale(level)),
|
||||
tx = Math.floor(pixel.x / this.tileSize),
|
||||
ty = Math.floor(pixel.y / this.tileSize);
|
||||
|
||||
return new $.Point(tx, ty);
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
getTileBounds: function (level, x, y) {
|
||||
var dimensionsScaled = this.dimensions.times(this.getLevelScale(level)),
|
||||
px = (x === 0) ? 0 : this.tileSize * x - this.tileOverlap,
|
||||
py = (y === 0) ? 0 : this.tileSize * y - this.tileOverlap,
|
||||
sx = this.tileSize + (x === 0 ? 1 : 2) * this.tileOverlap,
|
||||
sy = this.tileSize + (y === 0 ? 1 : 2) * this.tileOverlap,
|
||||
scale = 1.0 / dimensionsScaled.x;
|
||||
|
||||
sx = Math.min( sx, dimensionsScaled.x - px );
|
||||
sy = Math.min( sy, dimensionsScaled.y - py );
|
||||
sx = Math.min(sx, dimensionsScaled.x - px);
|
||||
sy = Math.min(sy, dimensionsScaled.y - py);
|
||||
|
||||
return new $.Rect( px * scale, py * scale, sx * scale, sy * scale );
|
||||
},
|
||||
return new $.Rect(px * scale, py * scale, sx * scale, sy * scale);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for retrieving, and caching the
|
||||
* image metadata pertinent to this TileSources implementation.
|
||||
* @function
|
||||
* @param {String} url
|
||||
* @throws {Error}
|
||||
*/
|
||||
getImageInfo: function( url ) {
|
||||
var _this = this,
|
||||
/**
|
||||
* Responsible for retrieving, and caching the
|
||||
* image metadata pertinent to this TileSources implementation.
|
||||
* @function
|
||||
* @param {String} url
|
||||
* @throws {Error}
|
||||
*/
|
||||
getImageInfo: function (url) {
|
||||
var _this = this,
|
||||
callbackName,
|
||||
callback,
|
||||
readySource,
|
||||
@ -282,195 +282,195 @@ $.TileSource.prototype = {
|
||||
lastDot;
|
||||
|
||||
|
||||
if( url ) {
|
||||
urlParts = url.split( '/' );
|
||||
filename = urlParts[ urlParts.length - 1 ];
|
||||
lastDot = filename.lastIndexOf( '.' );
|
||||
if ( lastDot > -1 ) {
|
||||
urlParts[ urlParts.length - 1 ] = filename.slice( 0, lastDot );
|
||||
}
|
||||
}
|
||||
|
||||
callback = function( data ){
|
||||
var $TileSource = $.TileSource.determineType( _this, data, url );
|
||||
if ( !$TileSource ) {
|
||||
_this.raiseEvent( 'open-failed', { message: "Unable to load TileSource", source: url } );
|
||||
return;
|
||||
if (url) {
|
||||
urlParts = url.split('/');
|
||||
filename = urlParts[urlParts.length - 1];
|
||||
lastDot = filename.lastIndexOf('.');
|
||||
if (lastDot > -1) {
|
||||
urlParts[urlParts.length - 1] = filename.slice(0, lastDot);
|
||||
}
|
||||
}
|
||||
|
||||
options = $TileSource.prototype.configure.apply( _this, [ data, url ]);
|
||||
readySource = new $TileSource( options );
|
||||
_this.ready = true;
|
||||
_this.raiseEvent( 'ready', readySource );
|
||||
};
|
||||
callback = function (data) {
|
||||
var $TileSource = $.TileSource.determineType(_this, data, url);
|
||||
if (!$TileSource) {
|
||||
_this.raiseEvent('open-failed', { message: "Unable to load TileSource", source: url });
|
||||
return;
|
||||
}
|
||||
|
||||
if( url.match(/\.js$/) ){
|
||||
//TODO: Its not very flexible to require tile sources to end jsonp
|
||||
// request for info with a url that ends with '.js' but for
|
||||
// now it's the only way I see to distinguish uniformly.
|
||||
callbackName = url.split( '/' ).pop().replace('.js','');
|
||||
$.jsonp({
|
||||
url: url,
|
||||
async: false,
|
||||
callbackName: callbackName,
|
||||
callback: callback
|
||||
});
|
||||
} else {
|
||||
// request info via xhr asyncronously.
|
||||
$.makeAjaxRequest( url, function( xhr ) {
|
||||
var data = processResponse( xhr );
|
||||
callback( data );
|
||||
}, function ( xhr ) {
|
||||
_this.raiseEvent( 'open-failed', {
|
||||
message: "HTTP " + xhr.status + " attempting to load TileSource",
|
||||
source: url
|
||||
options = $TileSource.prototype.configure.apply(_this, [data, url]);
|
||||
readySource = new $TileSource(options);
|
||||
_this.ready = true;
|
||||
_this.raiseEvent('ready', { tileSource: readySource });
|
||||
};
|
||||
|
||||
if (url.match(/\.js$/)) {
|
||||
//TODO: Its not very flexible to require tile sources to end jsonp
|
||||
// request for info with a url that ends with '.js' but for
|
||||
// now it's the only way I see to distinguish uniformly.
|
||||
callbackName = url.split('/').pop().replace('.js', '');
|
||||
$.jsonp({
|
||||
url: url,
|
||||
async: false,
|
||||
callbackName: callbackName,
|
||||
callback: callback
|
||||
});
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// request info via xhr asyncronously.
|
||||
$.makeAjaxRequest(url, function (xhr) {
|
||||
var data = processResponse(xhr);
|
||||
callback(data);
|
||||
}, function (xhr) {
|
||||
_this.raiseEvent('open-failed', {
|
||||
message: "HTTP " + xhr.status + " attempting to load TileSource",
|
||||
source: url
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Responsible determining if a the particular TileSource supports the
|
||||
* data format ( and allowed to apply logic against the url the data was
|
||||
* loaded from, if any ). Overriding implementations are expected to do
|
||||
* something smart with data and / or url to determine support. Also
|
||||
* understand that iteration order of TileSources is not guarunteed so
|
||||
* please make sure your data or url is expressive enough to ensure a simple
|
||||
* and sufficient mechanisim for clear determination.
|
||||
* @function
|
||||
* @param {String|Object|Array|Document} data
|
||||
* @param {String} url - the url the data was loaded
|
||||
* from if any.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
supports: function( data, url ) {
|
||||
return false;
|
||||
},
|
||||
/**
|
||||
* Responsible determining if a the particular TileSource supports the
|
||||
* data format ( and allowed to apply logic against the url the data was
|
||||
* loaded from, if any ). Overriding implementations are expected to do
|
||||
* something smart with data and / or url to determine support. Also
|
||||
* understand that iteration order of TileSources is not guarunteed so
|
||||
* please make sure your data or url is expressive enough to ensure a simple
|
||||
* and sufficient mechanisim for clear determination.
|
||||
* @function
|
||||
* @param {String|Object|Array|Document} data
|
||||
* @param {String} url - the url the data was loaded
|
||||
* from if any.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
supports: function (data, url) {
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Responsible for parsing and configuring the
|
||||
* image metadata pertinent to this TileSources implementation.
|
||||
* This method is not implemented by this class other than to throw an Error
|
||||
* announcing you have to implement it. Because of the variety of tile
|
||||
* server technologies, and various specifications for building image
|
||||
* pyramids, this method is here to allow easy integration.
|
||||
* @function
|
||||
* @param {String|Object|Array|Document} data
|
||||
* @param {String} url - the url the data was loaded
|
||||
* from if any.
|
||||
* @return {Object} options - A dictionary of keyword arguments sufficient
|
||||
* to configure this tile sources constructor.
|
||||
* @throws {Error}
|
||||
*/
|
||||
configure: function( data, url ) {
|
||||
throw new Error( "Method not implemented." );
|
||||
},
|
||||
/**
|
||||
* Responsible for parsing and configuring the
|
||||
* image metadata pertinent to this TileSources implementation.
|
||||
* This method is not implemented by this class other than to throw an Error
|
||||
* announcing you have to implement it. Because of the variety of tile
|
||||
* server technologies, and various specifications for building image
|
||||
* pyramids, this method is here to allow easy integration.
|
||||
* @function
|
||||
* @param {String|Object|Array|Document} data
|
||||
* @param {String} url - the url the data was loaded
|
||||
* from if any.
|
||||
* @return {Object} options - A dictionary of keyword arguments sufficient
|
||||
* to configure this tile sources constructor.
|
||||
* @throws {Error}
|
||||
*/
|
||||
configure: function (data, url) {
|
||||
throw new Error("Method not implemented.");
|
||||
},
|
||||
|
||||
/**
|
||||
* Responsible for retriving the url which will return an image for the
|
||||
* region speified by the given x, y, and level components.
|
||||
* This method is not implemented by this class other than to throw an Error
|
||||
* announcing you have to implement it. Because of the variety of tile
|
||||
* server technologies, and various specifications for building image
|
||||
* pyramids, this method is here to allow easy integration.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @throws {Error}
|
||||
*/
|
||||
getTileUrl: function( level, x, y ) {
|
||||
throw new Error( "Method not implemented." );
|
||||
},
|
||||
/**
|
||||
* Responsible for retriving the url which will return an image for the
|
||||
* region speified by the given x, y, and level components.
|
||||
* This method is not implemented by this class other than to throw an Error
|
||||
* announcing you have to implement it. Because of the variety of tile
|
||||
* server technologies, and various specifications for building image
|
||||
* pyramids, this method is here to allow easy integration.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @throws {Error}
|
||||
*/
|
||||
getTileUrl: function (level, x, y) {
|
||||
throw new Error("Method not implemented.");
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
tileExists: function( level, x, y ) {
|
||||
var numTiles = this.getNumTiles( level );
|
||||
return level >= this.minLevel &&
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
*/
|
||||
tileExists: function (level, x, y) {
|
||||
var numTiles = this.getNumTiles(level);
|
||||
return level >= this.minLevel &&
|
||||
level <= this.maxLevel &&
|
||||
x >= 0 &&
|
||||
y >= 0 &&
|
||||
x < numTiles.x &&
|
||||
y < numTiles.y;
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$.extend( true, $.TileSource.prototype, $.EventHandler.prototype );
|
||||
$.extend(true, $.TileSource.prototype, $.EventHandler.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* Decides whether to try to process the response as xml, json, or hand back
|
||||
* the text
|
||||
* @eprivate
|
||||
* @inner
|
||||
* @function
|
||||
* @param {XMLHttpRequest} xhr - the completed network request
|
||||
*/
|
||||
function processResponse( xhr ){
|
||||
var responseText = xhr.responseText,
|
||||
status = xhr.status,
|
||||
/**
|
||||
* Decides whether to try to process the response as xml, json, or hand back
|
||||
* the text
|
||||
* @eprivate
|
||||
* @inner
|
||||
* @function
|
||||
* @param {XMLHttpRequest} xhr - the completed network request
|
||||
*/
|
||||
function processResponse(xhr) {
|
||||
var responseText = xhr.responseText,
|
||||
status = xhr.status,
|
||||
statusText,
|
||||
data;
|
||||
|
||||
if ( !xhr ) {
|
||||
throw new Error( $.getString( "Errors.Security" ) );
|
||||
} else if ( xhr.status !== 200 && xhr.status !== 0 ) {
|
||||
status = xhr.status;
|
||||
statusText = ( status == 404 ) ?
|
||||
if (!xhr) {
|
||||
throw new Error($.getString("Errors.Security"));
|
||||
} else if (xhr.status !== 200 && xhr.status !== 0) {
|
||||
status = xhr.status;
|
||||
statusText = (status == 404) ?
|
||||
"Not Found" :
|
||||
xhr.statusText;
|
||||
throw new Error( $.getString( "Errors.Status", status, statusText ) );
|
||||
}
|
||||
throw new Error($.getString("Errors.Status", status, statusText));
|
||||
}
|
||||
|
||||
if( responseText.match(/\s*<.*/) ){
|
||||
try{
|
||||
data = ( xhr.responseXML && xhr.responseXML.documentElement ) ?
|
||||
if (responseText.match(/\s*<.*/)) {
|
||||
try {
|
||||
data = (xhr.responseXML && xhr.responseXML.documentElement) ?
|
||||
xhr.responseXML :
|
||||
$.parseXml( responseText );
|
||||
} catch (e){
|
||||
data = xhr.responseText;
|
||||
}
|
||||
}else if( responseText.match(/\s*[\{\[].*/) ){
|
||||
/*jshint evil:true*/
|
||||
data = eval( '('+responseText+')' );
|
||||
}else{
|
||||
data = responseText;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines the TileSource Implementation by introspection of OpenSeadragon
|
||||
* namespace, calling each TileSource implementation of 'isType'
|
||||
* @eprivate
|
||||
* @inner
|
||||
* @function
|
||||
* @param {Object|Array|Document} data - the tile source configuration object
|
||||
* @param {String} url - the url where the tile source configuration object was
|
||||
* loaded from, if any.
|
||||
*/
|
||||
$.TileSource.determineType = function( tileSource, data, url ){
|
||||
var property;
|
||||
for( property in OpenSeadragon ){
|
||||
if( property.match(/.+TileSource$/) &&
|
||||
$.isFunction( OpenSeadragon[ property ] ) &&
|
||||
$.isFunction( OpenSeadragon[ property ].prototype.supports ) &&
|
||||
OpenSeadragon[ property ].prototype.supports.call( tileSource, data, url )
|
||||
){
|
||||
return OpenSeadragon[ property ];
|
||||
$.parseXml(responseText);
|
||||
} catch (e) {
|
||||
data = xhr.responseText;
|
||||
}
|
||||
} else if (responseText.match(/\s*[\{\[].*/)) {
|
||||
/*jshint evil:true*/
|
||||
data = eval('(' + responseText + ')');
|
||||
} else {
|
||||
data = responseText;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
$.console.error( "No TileSource was able to open %s %s", url, data );
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines the TileSource Implementation by introspection of OpenSeadragon
|
||||
* namespace, calling each TileSource implementation of 'isType'
|
||||
* @eprivate
|
||||
* @inner
|
||||
* @function
|
||||
* @param {Object|Array|Document} data - the tile source configuration object
|
||||
* @param {String} url - the url where the tile source configuration object was
|
||||
* loaded from, if any.
|
||||
*/
|
||||
$.TileSource.determineType = function (tileSource, data, url) {
|
||||
var property;
|
||||
for (property in OpenSeadragon) {
|
||||
if (property.match(/.+TileSource$/) &&
|
||||
$.isFunction(OpenSeadragon[property]) &&
|
||||
$.isFunction(OpenSeadragon[property].prototype.supports) &&
|
||||
OpenSeadragon[property].prototype.supports.call(tileSource, data, url)
|
||||
) {
|
||||
return OpenSeadragon[property];
|
||||
}
|
||||
}
|
||||
|
||||
$.console.error("No TileSource was able to open %s %s", url, data);
|
||||
};
|
||||
|
||||
|
||||
}( OpenSeadragon ));
|
||||
} (OpenSeadragon));
|
||||
|
@ -1463,7 +1463,7 @@ function onCanvasDrag( tracker, position, delta, shift ) {
|
||||
this.viewport.applyConstraints();
|
||||
}
|
||||
}
|
||||
this.raiseEvent( 'canvas-click', {
|
||||
this.raiseEvent( 'canvas-drag', {
|
||||
tracker: tracker,
|
||||
position: position,
|
||||
delta: delta,
|
||||
|
Loading…
Reference in New Issue
Block a user