mirror of
https://github.com/openseadragon/openseadragon.git
synced 2025-01-19 17:21:50 +03:00
commit
3842779746
2
.gitignore
vendored
2
.gitignore
vendored
@ -2,3 +2,5 @@
|
|||||||
node_modules
|
node_modules
|
||||||
build/
|
build/
|
||||||
sftp-config.json
|
sftp-config.json
|
||||||
|
coverage/
|
||||||
|
temp/
|
||||||
|
62
Gruntfile.js
62
Gruntfile.js
@ -1,3 +1,5 @@
|
|||||||
|
/* global module */
|
||||||
|
|
||||||
module.exports = function(grunt) {
|
module.exports = function(grunt) {
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
@ -5,7 +7,7 @@ module.exports = function(grunt) {
|
|||||||
grunt.loadNpmTasks("grunt-contrib-concat");
|
grunt.loadNpmTasks("grunt-contrib-concat");
|
||||||
grunt.loadNpmTasks("grunt-contrib-jshint");
|
grunt.loadNpmTasks("grunt-contrib-jshint");
|
||||||
grunt.loadNpmTasks("grunt-contrib-uglify");
|
grunt.loadNpmTasks("grunt-contrib-uglify");
|
||||||
grunt.loadNpmTasks("grunt-contrib-qunit");
|
grunt.loadNpmTasks("grunt-qunit-istanbul");
|
||||||
grunt.loadNpmTasks("grunt-contrib-connect");
|
grunt.loadNpmTasks("grunt-contrib-connect");
|
||||||
grunt.loadNpmTasks("grunt-contrib-watch");
|
grunt.loadNpmTasks("grunt-contrib-watch");
|
||||||
grunt.loadNpmTasks("grunt-contrib-clean");
|
grunt.loadNpmTasks("grunt-contrib-clean");
|
||||||
@ -44,11 +46,14 @@ module.exports = function(grunt) {
|
|||||||
"src/referencestrip.js",
|
"src/referencestrip.js",
|
||||||
"src/displayrectangle.js",
|
"src/displayrectangle.js",
|
||||||
"src/spring.js",
|
"src/spring.js",
|
||||||
"src/imageLoader.js",
|
"src/imageloader.js",
|
||||||
"src/tile.js",
|
"src/tile.js",
|
||||||
"src/overlay.js",
|
"src/overlay.js",
|
||||||
"src/drawer.js",
|
"src/drawer.js",
|
||||||
"src/viewport.js"
|
"src/viewport.js",
|
||||||
|
"src/tiledimage.js",
|
||||||
|
"src/tilecache.js",
|
||||||
|
"src/world.js"
|
||||||
];
|
];
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
@ -69,6 +74,7 @@ module.exports = function(grunt) {
|
|||||||
clean: {
|
clean: {
|
||||||
build: ["build"],
|
build: ["build"],
|
||||||
package: [packageDir],
|
package: [packageDir],
|
||||||
|
coverage: ["coverage"],
|
||||||
release: {
|
release: {
|
||||||
src: [releaseRoot],
|
src: [releaseRoot],
|
||||||
options: {
|
options: {
|
||||||
@ -134,10 +140,26 @@ module.exports = function(grunt) {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
qunit: {
|
qunit: {
|
||||||
|
normal: {
|
||||||
|
options: {
|
||||||
|
urls: [ "http://localhost:8000/test/test.html" ]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
coverage: {
|
||||||
|
options: {
|
||||||
|
urls: [ "http://localhost:8000/test/coverage.html" ],
|
||||||
|
coverage: {
|
||||||
|
src: ['src/*.js'],
|
||||||
|
htmlReport: 'coverage/html/',
|
||||||
|
instrumentedFiles: 'temp/',
|
||||||
|
baseUrl: '.',
|
||||||
|
disposeCollector: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
all: {
|
all: {
|
||||||
options: {
|
options: {
|
||||||
timeout: 10000,
|
timeout: 10000
|
||||||
urls: [ "http://localhost:8000/test/test.html" ]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -151,7 +173,7 @@ module.exports = function(grunt) {
|
|||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
files: [ "Gruntfile.js", "src/*.js", "images/*" ],
|
files: [ "Gruntfile.js", "src/*.js", "images/*" ],
|
||||||
tasks: "build"
|
tasks: "watchTask"
|
||||||
},
|
},
|
||||||
jshint: {
|
jshint: {
|
||||||
options: {
|
options: {
|
||||||
@ -206,6 +228,8 @@ module.exports = function(grunt) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
// Bower task.
|
||||||
|
// Generates the Bower file for site-build.
|
||||||
grunt.registerTask("bower", function() {
|
grunt.registerTask("bower", function() {
|
||||||
var path = "../site-build/bower.json";
|
var path = "../site-build/bower.json";
|
||||||
var data = grunt.file.readJSON(path);
|
var data = grunt.file.readJSON(path);
|
||||||
@ -213,6 +237,18 @@ module.exports = function(grunt) {
|
|||||||
grunt.file.write(path, JSON.stringify(data, null, 2) + "\n");
|
grunt.file.write(path, JSON.stringify(data, null, 2) + "\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
// Watch task.
|
||||||
|
// Called from the watch feature; does a full build or a minbuild, depending on
|
||||||
|
// whether you used --min on the command line.
|
||||||
|
grunt.registerTask("watchTask", function() {
|
||||||
|
if (grunt.option('min')) {
|
||||||
|
grunt.task.run("minbuild");
|
||||||
|
} else {
|
||||||
|
grunt.task.run("build");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Build task.
|
// Build task.
|
||||||
// Cleans out the build folder and builds the code and images into it, checking lint.
|
// Cleans out the build folder and builds the code and images into it, checking lint.
|
||||||
@ -221,10 +257,22 @@ module.exports = function(grunt) {
|
|||||||
"uglify", "replace:cleanPaths", "copy:build"
|
"uglify", "replace:cleanPaths", "copy:build"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
// Minimal build task.
|
||||||
|
// For use during development as desired. Creates only the unminified version.
|
||||||
|
grunt.registerTask("minbuild", [
|
||||||
|
"git-describe", "concat", "copy:build"
|
||||||
|
]);
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Test task.
|
// Test task.
|
||||||
// Builds and runs unit tests.
|
// Builds and runs unit tests.
|
||||||
grunt.registerTask("test", ["build", "connect", "qunit"]);
|
grunt.registerTask("test", ["build", "connect", "qunit:normal"]);
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
// Coverage task.
|
||||||
|
// Outputs unit test code coverage report.
|
||||||
|
grunt.registerTask("coverage", ["clean:coverage", "connect", "qunit:coverage"]);
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Package task.
|
// Package task.
|
||||||
|
@ -63,6 +63,12 @@ and open `http://localhost:8000/test/test.html` in your browser.
|
|||||||
|
|
||||||
Another good page, if you want to interactively test out your changes, is `http://localhost:8000/test/demo/basic.html`.
|
Another good page, if you want to interactively test out your changes, is `http://localhost:8000/test/demo/basic.html`.
|
||||||
|
|
||||||
|
You can also get a report of the tests' code coverage:
|
||||||
|
|
||||||
|
grunt coverage
|
||||||
|
|
||||||
|
The report shows up at `coverage/html/index.html` viewable in a browser.
|
||||||
|
|
||||||
### Contributing
|
### Contributing
|
||||||
|
|
||||||
OpenSeadragon is truly a community project; we welcome your involvement!
|
OpenSeadragon is truly a community project; we welcome your involvement!
|
||||||
|
@ -1,6 +1,54 @@
|
|||||||
OPENSEADRAGON CHANGELOG
|
OPENSEADRAGON CHANGELOG
|
||||||
=======================
|
=======================
|
||||||
|
|
||||||
|
1.3.0: (in progress)
|
||||||
|
|
||||||
|
* True multi-image mode (#450)
|
||||||
|
* BREAKING CHANGE: Passing an array for the tileSources option is no longer enough to trigger sequence mode; you have to set the sequenceMode option to true as well
|
||||||
|
* BREAKING CHANGE: Navigator no longer sends an open event when its viewer opens
|
||||||
|
* BREAKING CHANGE: Viewer.drawers and Viewer.drawersContainer no longer exist
|
||||||
|
* BREAKING CHANGE: A Viewer's Drawer and Viewport are now made once per Viewer and reused for every image that Viewer opens (rather than being recreated for every open); this means if you change Viewer options between opens, the behavior is different now.
|
||||||
|
* DEPRECATION: use Viewer.addTiledImage instead of Viewer.addLayer
|
||||||
|
* addTiledImage supports positioning config properties
|
||||||
|
* DEPRECATION: use World.getItemAt instead of Viewer.getLayerAtLevel
|
||||||
|
* DEPRECATION: use World.getIndexOfItem instead of Viewer.getLevelOfLayer
|
||||||
|
* DEPRECATION: use World.getItemCount instead of Viewer.getLayersCount
|
||||||
|
* DEPRECATION: use World.setItemIndex instead of Viewer.setLayerLevel
|
||||||
|
* DEPRECATION: use World.removeItem instead of Viewer.removeLayer
|
||||||
|
* DEPRECATION: use World.needsDraw instead of Drawer.needsUpdate
|
||||||
|
* DEPRECATION: use TileCache.numTilesLoaded instead of Drawer.numTilesLoaded
|
||||||
|
* DEPRECATION: use World.resetItems instead of Drawer.reset
|
||||||
|
* DEPRECATION: use Drawer.clear and World.draw instead of Drawer.update
|
||||||
|
* DEPRECATION: the layersAspectRatioEpsilon option is no longer necessary
|
||||||
|
* DEPRECATION: Viewer's add-layer event is now World's add-item event
|
||||||
|
* DEPRECATION: Viewer's layer-level-changed event is now World's item-index-change event
|
||||||
|
* DEPRECATION: Viewer's remove-layer event is now World's remove-item event
|
||||||
|
* DEPRECATION: Viewer's add-layer-failed event is now add-item-failed
|
||||||
|
* DEPRECATION: TileSourceCollection has been retired in favor of World
|
||||||
|
* DEPRECATION: collectionMode no longer draws outlines or reflections for items
|
||||||
|
* Drawer has been split into three classes:
|
||||||
|
* TiledImage, tile management and positioning for a single tiled image
|
||||||
|
* TileCache, tile caching for all images
|
||||||
|
* Drawer, tile drawing for all images
|
||||||
|
* New class: World, keeps track of multiple images in the scene
|
||||||
|
* Viewer now has world and tileCache properties
|
||||||
|
* Rect and Point now have clone functions
|
||||||
|
* New Viewport method for managing homeBounds as well as constraints: setHomeBounds
|
||||||
|
* Viewport.open supports positioning config properties
|
||||||
|
* Margins option to push the home region in from the edges of the Viewer (#505)
|
||||||
|
* Rect and Point toString() functions are now consistent: rounding values to nearest hundredth
|
||||||
|
* Overlays appear in the DOM immediately on open or addOverlay (#507)
|
||||||
|
* imageLoaderLimit now works (#544)
|
||||||
|
* Turning off scrollToZoom in gestureSettings now allows scroll events to propagate
|
||||||
|
* You can now set a minZoomLevel that's greater than the home zoom level
|
||||||
|
* Added union() to OpenSeadragon.Rect
|
||||||
|
* Fixed an error in fitBounds if the new and old bounds were extremely close in size
|
||||||
|
* Added ajaxWithCredentials option (#543)
|
||||||
|
* Added viewport-change event for after the viewport changes but before it's drawn
|
||||||
|
* A spring's current value is now updated immediately on reset (#524)
|
||||||
|
* Fixed an error in fitBounds that occurred sometimes with immediately = true
|
||||||
|
* Added support for HDPI (retina) displays (#583)
|
||||||
|
|
||||||
1.2.2: (in progress)
|
1.2.2: (in progress)
|
||||||
|
|
||||||
* Corrected IIIF tile source to use canonical syntax (#586)
|
* Corrected IIIF tile source to use canonical syntax (#586)
|
||||||
|
@ -8,7 +8,8 @@
|
|||||||
"*.sublime-workspace"
|
"*.sublime-workspace"
|
||||||
],
|
],
|
||||||
"folder_exclude_patterns": [
|
"folder_exclude_patterns": [
|
||||||
"node_modules"
|
"node_modules",
|
||||||
|
"coverage"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
"grunt-git-describe": "^2.3.2",
|
"grunt-git-describe": "^2.3.2",
|
||||||
"grunt-contrib-uglify": "^0.4.0",
|
"grunt-contrib-uglify": "^0.4.0",
|
||||||
"grunt-contrib-watch": "^0.6.1",
|
"grunt-contrib-watch": "^0.6.1",
|
||||||
"grunt-contrib-qunit": "^0.5.1",
|
|
||||||
"grunt-contrib-jshint": "^0.10.0",
|
"grunt-contrib-jshint": "^0.10.0",
|
||||||
"grunt-contrib-compress": "^0.9.1",
|
"grunt-contrib-compress": "^0.9.1",
|
||||||
"grunt-contrib-connect": "^0.7.1",
|
"grunt-contrib-connect": "^0.7.1",
|
||||||
"qunitjs": "^1.14.0"
|
"qunitjs": "^1.14.0",
|
||||||
|
"grunt-qunit-istanbul": "^0.4.5"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "grunt test"
|
"test": "grunt test"
|
||||||
|
1273
src/drawer.js
1273
src/drawer.js
File diff suppressed because it is too large
Load Diff
@ -34,16 +34,7 @@
|
|||||||
|
|
||||||
(function( $ ){
|
(function( $ ){
|
||||||
|
|
||||||
/**
|
// private class
|
||||||
* @private
|
|
||||||
* @class ImageJob
|
|
||||||
* @classdesc Handles loading a single image for use in a single {@link OpenSeadragon.Tile}.
|
|
||||||
*
|
|
||||||
* @memberof OpenSeadragon
|
|
||||||
* @param {String} source - URL of image to download.
|
|
||||||
* @param {String} crossOriginPolicy - CORS policy to use for downloads
|
|
||||||
* @param {Function} callback - Called once image has finished downloading.
|
|
||||||
*/
|
|
||||||
function ImageJob ( options ) {
|
function ImageJob ( options ) {
|
||||||
|
|
||||||
$.extend( true, this, {
|
$.extend( true, this, {
|
||||||
@ -60,11 +51,6 @@ function ImageJob ( options ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImageJob.prototype = {
|
ImageJob.prototype = {
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates downloading of associated image.
|
|
||||||
* @method
|
|
||||||
*/
|
|
||||||
start: function(){
|
start: function(){
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
@ -104,20 +90,24 @@ ImageJob.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class
|
* @class ImageLoader
|
||||||
|
* @memberof OpenSeadragon
|
||||||
* @classdesc Handles downloading of a set of images using asynchronous queue pattern.
|
* @classdesc Handles downloading of a set of images using asynchronous queue pattern.
|
||||||
|
* You generally won't have to interact with the ImageLoader directly.
|
||||||
|
* @param {Object} options - Options for this ImageLoader.
|
||||||
|
* @param {Number} [options.jobLimit] - The number of concurrent image requests. See imageLoaderLimit in {@link OpenSeadragon.Options} for details.
|
||||||
*/
|
*/
|
||||||
$.ImageLoader = function() {
|
$.ImageLoader = function( options ) {
|
||||||
|
|
||||||
$.extend( true, this, {
|
$.extend( true, this, {
|
||||||
jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,
|
jobLimit: $.DEFAULT_SETTINGS.imageLoaderLimit,
|
||||||
jobQueue: [],
|
jobQueue: [],
|
||||||
jobsInProgress: 0
|
jobsInProgress: 0
|
||||||
});
|
}, options );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$.ImageLoader.prototype = {
|
$.ImageLoader.prototype = /** @lends OpenSeadragon.ImageLoader.prototype */{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an unloaded image to the loader queue.
|
* Add an unloaded image to the loader queue.
|
||||||
@ -143,7 +133,7 @@ $.ImageLoader.prototype = {
|
|||||||
this.jobsInProgress++;
|
this.jobsInProgress++;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.jobQueue.push( newJob );
|
this.jobQueue.push( newJob );
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -172,10 +162,10 @@ function completeJob( loader, job, callback ) {
|
|||||||
if ( (!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {
|
if ( (!loader.jobLimit || loader.jobsInProgress < loader.jobLimit) && loader.jobQueue.length > 0) {
|
||||||
nextJob = loader.jobQueue.shift();
|
nextJob = loader.jobQueue.shift();
|
||||||
nextJob.start();
|
nextJob.start();
|
||||||
|
loader.jobsInProgress++;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback( job.image );
|
callback( job.image );
|
||||||
}
|
}
|
||||||
|
|
||||||
}( OpenSeadragon ));
|
}( OpenSeadragon ));
|
||||||
|
|
140
src/navigator.js
140
src/navigator.js
@ -173,7 +173,10 @@ $.Navigator = function( options ){
|
|||||||
options.controlOptions
|
options.controlOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE && options.controlOptions.anchor != $.ControlAnchor.NONE ) {
|
this._resizeWithViewer = options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE &&
|
||||||
|
options.controlOptions.anchor != $.ControlAnchor.NONE;
|
||||||
|
|
||||||
|
if ( this._resizeWithViewer ) {
|
||||||
if ( options.width && options.height ) {
|
if ( options.width && options.height ) {
|
||||||
this.element.style.height = typeof ( options.height ) == "number" ? ( options.height + 'px' ) : options.height;
|
this.element.style.height = typeof ( options.height ) == "number" ? ( options.height + 'px' ) : options.height;
|
||||||
this.element.style.width = typeof ( options.width ) == "number" ? ( options.width + 'px' ) : options.width;
|
this.element.style.width = typeof ( options.width ) == "number" ? ( options.width + 'px' ) : options.width;
|
||||||
@ -194,8 +197,7 @@ $.Navigator = function( options ){
|
|||||||
this.displayRegionContainer.appendChild(this.displayRegion);
|
this.displayRegionContainer.appendChild(this.displayRegion);
|
||||||
this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer);
|
this.element.getElementsByTagName('div')[0].appendChild(this.displayRegionContainer);
|
||||||
|
|
||||||
if (options.navigatorRotate)
|
if (options.navigatorRotate) {
|
||||||
{
|
|
||||||
options.viewer.addHandler("rotate", function (args) {
|
options.viewer.addHandler("rotate", function (args) {
|
||||||
_setTransformRotate(_this.displayRegionContainer, args.degrees);
|
_setTransformRotate(_this.displayRegionContainer, args.degrees);
|
||||||
_setTransformRotate(_this.displayRegion, -args.degrees);
|
_setTransformRotate(_this.displayRegion, -args.degrees);
|
||||||
@ -213,6 +215,32 @@ $.Navigator = function( options ){
|
|||||||
scrollHandler: $.delegate( this, onCanvasScroll )
|
scrollHandler: $.delegate( this, onCanvasScroll )
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.addHandler("reset-size", function() {
|
||||||
|
if (_this.viewport) {
|
||||||
|
_this.viewport.goHome(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addHandler("reset-size", function() {
|
||||||
|
if (_this.viewport) {
|
||||||
|
_this.viewport.goHome(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.addHandler("item-index-change", function(event) {
|
||||||
|
var item = _this.world.getItemAt(event.previousIndex);
|
||||||
|
_this.world.setItemIndex(item, event.newIndex);
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.addHandler("remove-item", function(event) {
|
||||||
|
var theirItem = event.item;
|
||||||
|
var myItem = _this._getMatchingItem(theirItem);
|
||||||
|
if (myItem) {
|
||||||
|
_this.world.removeItem(myItem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.update(viewer.viewport);
|
||||||
};
|
};
|
||||||
|
|
||||||
$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{
|
$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{
|
||||||
@ -228,23 +256,13 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
|||||||
(this.container.clientWidth === 0 ? 1 : this.container.clientWidth),
|
(this.container.clientWidth === 0 ? 1 : this.container.clientWidth),
|
||||||
(this.container.clientHeight === 0 ? 1 : this.container.clientHeight)
|
(this.container.clientHeight === 0 ? 1 : this.container.clientHeight)
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( !containerSize.equals( this.oldContainerSize ) ) {
|
if ( !containerSize.equals( this.oldContainerSize ) ) {
|
||||||
var oldBounds = this.viewport.getBounds();
|
|
||||||
var oldCenter = this.viewport.getCenter();
|
|
||||||
this.viewport.resize( containerSize, true );
|
this.viewport.resize( containerSize, true );
|
||||||
var imageHeight = 1 / this.source.aspectRatio;
|
this.viewport.goHome(true);
|
||||||
var newWidth = oldBounds.width <= 1 ? oldBounds.width : 1;
|
|
||||||
var newHeight = oldBounds.height <= imageHeight ?
|
|
||||||
oldBounds.height : imageHeight;
|
|
||||||
var newBounds = new $.Rect(
|
|
||||||
oldCenter.x - ( newWidth / 2.0 ),
|
|
||||||
oldCenter.y - ( newHeight / 2.0 ),
|
|
||||||
newWidth,
|
|
||||||
newHeight
|
|
||||||
);
|
|
||||||
this.viewport.fitBounds( newBounds, true );
|
|
||||||
this.oldContainerSize = containerSize;
|
this.oldContainerSize = containerSize;
|
||||||
this.drawer.update();
|
this.drawer.clear();
|
||||||
|
this.world.draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -264,55 +282,91 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
|||||||
bottomright;
|
bottomright;
|
||||||
|
|
||||||
viewerSize = $.getElementSize( this.viewer.element );
|
viewerSize = $.getElementSize( this.viewer.element );
|
||||||
if ( !viewerSize.equals( this.oldViewerSize ) ) {
|
if ( this._resizeWithViewer && !viewerSize.equals( this.oldViewerSize ) ) {
|
||||||
this.oldViewerSize = viewerSize;
|
this.oldViewerSize = viewerSize;
|
||||||
if ( this.maintainSizeRatio ) {
|
|
||||||
|
if ( this.maintainSizeRatio || !this.elementArea) {
|
||||||
newWidth = viewerSize.x * this.sizeRatio;
|
newWidth = viewerSize.x * this.sizeRatio;
|
||||||
newHeight = viewerSize.y * this.sizeRatio;
|
newHeight = viewerSize.y * this.sizeRatio;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y));
|
newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y));
|
||||||
newHeight = this.elementArea / newWidth;
|
newHeight = this.elementArea / newWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.element.style.width = Math.round( newWidth ) + 'px';
|
this.element.style.width = Math.round( newWidth ) + 'px';
|
||||||
this.element.style.height = Math.round( newHeight ) + 'px';
|
this.element.style.height = Math.round( newHeight ) + 'px';
|
||||||
|
|
||||||
|
if (!this.elementArea) {
|
||||||
|
this.elementArea = newWidth * newHeight;
|
||||||
|
}
|
||||||
|
|
||||||
this.updateSize();
|
this.updateSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if( viewport && this.viewport ) {
|
if( viewport && this.viewport ) {
|
||||||
bounds = viewport.getBounds( true );
|
bounds = viewport.getBounds( true );
|
||||||
topleft = this.viewport.pixelFromPoint( bounds.getTopLeft(), false );
|
topleft = this.viewport.pixelFromPoint( bounds.getTopLeft(), false );
|
||||||
bottomright = this.viewport.pixelFromPoint( bounds.getBottomRight(), false ).minus( this.totalBorderWidths );
|
bottomright = this.viewport.pixelFromPoint( bounds.getBottomRight(), false )
|
||||||
|
.minus( this.totalBorderWidths );
|
||||||
|
|
||||||
//update style for navigator-box
|
//update style for navigator-box
|
||||||
(function(style) {
|
var style = this.displayRegion.style;
|
||||||
|
style.display = this.world.getItemCount() ? 'block' : 'none';
|
||||||
|
|
||||||
style.top = Math.round( topleft.y ) + 'px';
|
style.top = Math.round( topleft.y ) + 'px';
|
||||||
style.left = Math.round( topleft.x ) + 'px';
|
style.left = Math.round( topleft.x ) + 'px';
|
||||||
|
|
||||||
var width = Math.abs( topleft.x - bottomright.x );
|
var width = Math.abs( topleft.x - bottomright.x );
|
||||||
var height = Math.abs( topleft.y - bottomright.y );
|
var height = Math.abs( topleft.y - bottomright.y );
|
||||||
// make sure width and height are non-negative so IE doesn't throw
|
// make sure width and height are non-negative so IE doesn't throw
|
||||||
style.width = Math.round( Math.max( width, 0 ) ) + 'px';
|
style.width = Math.round( Math.max( width, 0 ) ) + 'px';
|
||||||
style.height = Math.round( Math.max( height, 0 ) ) + 'px';
|
style.height = Math.round( Math.max( height, 0 ) ) + 'px';
|
||||||
|
|
||||||
}( this.displayRegion.style ));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function( source ) {
|
// overrides Viewer.addTiledImage
|
||||||
this.updateSize();
|
addTiledImage: function(options) {
|
||||||
var containerSize = this.viewer.viewport.containerSize.times( this.sizeRatio );
|
var _this = this;
|
||||||
var ts = source.getTileSize(source.maxLevel);
|
|
||||||
if ( ts > containerSize.x || ts > containerSize.y ) {
|
|
||||||
this.minPixelRatio = Math.min( containerSize.x, containerSize.y ) / ts;
|
|
||||||
} else {
|
|
||||||
this.minPixelRatio = this.viewer.minPixelRatio;
|
|
||||||
}
|
|
||||||
return $.Viewer.prototype.open.apply( this, [ source ] );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var original = options.originalTiledImage;
|
||||||
|
delete options.original;
|
||||||
|
|
||||||
|
var optionsClone = $.extend({}, options, {
|
||||||
|
success: function(event) {
|
||||||
|
var myItem = event.item;
|
||||||
|
myItem._originalForNavigator = original;
|
||||||
|
_this._matchBounds(myItem, original, true);
|
||||||
|
|
||||||
|
original.addHandler('bounds-change', function() {
|
||||||
|
_this._matchBounds(myItem, original);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return $.Viewer.prototype.addTiledImage.apply(this, [optionsClone]);
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_getMatchingItem: function(theirItem) {
|
||||||
|
var count = this.world.getItemCount();
|
||||||
|
var item;
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
item = this.world.getItemAt(i);
|
||||||
|
if (item._originalForNavigator === theirItem) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_matchBounds: function(myItem, theirItem, immediately) {
|
||||||
|
var bounds = theirItem.getBounds();
|
||||||
|
myItem.setPosition(bounds.getTopLeft(), immediately);
|
||||||
|
myItem.setWidth(bounds.width, immediately);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,20 +126,14 @@
|
|||||||
* The element to append the viewer's container element to. If not provided, the 'id' property must be provided.
|
* The element to append the viewer's container element to. If not provided, the 'id' property must be provided.
|
||||||
* If both the element and id properties are specified, the viewer is appended to the element provided in the element property.
|
* If both the element and id properties are specified, the viewer is appended to the element provided in the element property.
|
||||||
*
|
*
|
||||||
|
* @property {Array|String|Function|Object} [tileSources=null]
|
||||||
|
* Tile source(s) to open initially. This is a complex parameter; see
|
||||||
|
* {@link OpenSeadragon.Viewer#open} for details.
|
||||||
|
*
|
||||||
* @property {Number} [tabIndex=0]
|
* @property {Number} [tabIndex=0]
|
||||||
* Tabbing order index to assign to the viewer element. Positive values are selected in increasing order. When tabIndex is 0
|
* Tabbing order index to assign to the viewer element. Positive values are selected in increasing order. When tabIndex is 0
|
||||||
* source order is used. A negative value omits the viewer from the tabbing order.
|
* source order is used. A negative value omits the viewer from the tabbing order.
|
||||||
*
|
*
|
||||||
* @property {Array|String|Function|Object[]|Array[]|String[]|Function[]} [tileSources=null]
|
|
||||||
* As an Array, the tileSource can hold either Objects or mixed
|
|
||||||
* types of Arrays of Objects, Strings, or Functions. 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}.
|
|
||||||
*
|
|
||||||
* @property {Array} overlays Array of objects defining permanent overlays of
|
* @property {Array} overlays Array of objects defining permanent overlays of
|
||||||
* the viewer. The overlays added via this option and later removed with
|
* the viewer. The overlays added via this option and later removed with
|
||||||
* {@link OpenSeadragon.Viewer#removeOverlay} will be added back when a new
|
* {@link OpenSeadragon.Viewer#removeOverlay} will be added back when a new
|
||||||
@ -215,9 +209,6 @@
|
|||||||
* @property {Number} [opacity=1]
|
* @property {Number} [opacity=1]
|
||||||
* Opacity of the drawer (1=opaque, 0=transparent)
|
* Opacity of the drawer (1=opaque, 0=transparent)
|
||||||
*
|
*
|
||||||
* @property {Number} [layersAspectRatioEpsilon=0.0001]
|
|
||||||
* Maximum aspectRatio mismatch between 2 layers.
|
|
||||||
*
|
|
||||||
* @property {Number} [degrees=0]
|
* @property {Number} [degrees=0]
|
||||||
* Initial rotation.
|
* Initial rotation.
|
||||||
*
|
*
|
||||||
@ -265,10 +256,14 @@
|
|||||||
* @property {Number} [visibilityRatio=0.5]
|
* @property {Number} [visibilityRatio=0.5]
|
||||||
* The percentage ( as a number from 0 to 1 ) of the source image which
|
* 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
|
* must be kept within the viewport. If the image is dragged beyond that
|
||||||
* limit, it will 'bounce' back until the minimum visibility ration is
|
* limit, it will 'bounce' back until the minimum visibility ratio is
|
||||||
* achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to
|
* achieved. Setting this to 0 and wrapHorizontal ( or wrapVertical ) to
|
||||||
* true will provide the effect of an infinitely scrolling viewport.
|
* true will provide the effect of an infinitely scrolling viewport.
|
||||||
*
|
*
|
||||||
|
* @property {Object} [viewportMargins={}]
|
||||||
|
* Pushes the "home" region in from the sides by the specified amounts.
|
||||||
|
* Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom.
|
||||||
|
*
|
||||||
* @property {Number} [imageLoaderLimit=0]
|
* @property {Number} [imageLoaderLimit=0]
|
||||||
* The maximum number of image requests to make concurrently. By default
|
* The maximum number of image requests to make concurrently. By default
|
||||||
* it is set to 0 allowing the browser to make the maximum number of
|
* it is set to 0 allowing the browser to make the maximum number of
|
||||||
@ -455,8 +450,8 @@
|
|||||||
* this setting when set to false.
|
* this setting when set to false.
|
||||||
*
|
*
|
||||||
* @property {Boolean} [showSequenceControl=true]
|
* @property {Boolean} [showSequenceControl=true]
|
||||||
* If the viewer has been configured with a sequence of tile sources, then
|
* If sequenceMode is true, then provide buttons for navigating forward and
|
||||||
* provide buttons for navigating forward and backward through the images.
|
* backward through the images.
|
||||||
*
|
*
|
||||||
* @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT]
|
* @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT]
|
||||||
* Placement of the default sequence controls.
|
* Placement of the default sequence controls.
|
||||||
@ -514,26 +509,29 @@
|
|||||||
* To only change the button images, consider using
|
* To only change the button images, consider using
|
||||||
* {@link OpenSeadragon.Options.navImages}
|
* {@link OpenSeadragon.Options.navImages}
|
||||||
*
|
*
|
||||||
|
* @property {Boolean} [sequenceMode=false]
|
||||||
|
* Set to true to have the viewer treat your tilesources as a sequence of images to
|
||||||
|
* be opened one at a time rather than all at once.
|
||||||
|
*
|
||||||
* @property {Number} [initialPage=0]
|
* @property {Number} [initialPage=0]
|
||||||
* If the viewer has been configured with a sequence of tile sources, display this page initially.
|
* If sequenceMode is true, display this page initially.
|
||||||
*
|
*
|
||||||
* @property {Boolean} [preserveViewport=false]
|
* @property {Boolean} [preserveViewport=false]
|
||||||
* If the viewer has been configured with a sequence of tile sources, then
|
* If sequenceMode is true, then normally navigating to through each image resets the
|
||||||
* normally navigating through each image resets the viewport to 'home'
|
* viewport to 'home' position. If preserveViewport is set to true, then the viewport
|
||||||
* position. If preserveViewport is set to true, then the viewport position
|
* position is preserved when navigating between images in the sequence.
|
||||||
* is preserved when navigating between images in the sequence.
|
|
||||||
*
|
*
|
||||||
* @property {Boolean} [preserveOverlays=false]
|
* @property {Boolean} [preserveOverlays=false]
|
||||||
* If the viewer has been configured with a sequence of tile sources, then
|
* If sequenceMode is true, then normally navigating to through each image
|
||||||
* normally navigating through each image resets the overlays.
|
* resets the overlays.
|
||||||
* If preserveOverlays is set to true, then the overlays
|
* If preserveOverlays is set to true, then the overlays
|
||||||
* are preserved when navigating between images in the sequence.
|
* are preserved when navigating between images in the sequence.
|
||||||
* Note: setting preserveOverlays overrides any overlays specified in the
|
* Note: setting preserveOverlays overrides any overlays specified in the
|
||||||
* "overlays" property.
|
* "overlays" property.
|
||||||
*
|
*
|
||||||
* @property {Boolean} [showReferenceStrip=false]
|
* @property {Boolean} [showReferenceStrip=false]
|
||||||
* If the viewer has been configured with a sequence of tile sources, then
|
* If sequenceMode is true, then display a scrolling strip of image thumbnails for
|
||||||
* display a scrolling strip of image thumbnails for navigating through the images.
|
* navigating through the images.
|
||||||
*
|
*
|
||||||
* @property {String} [referenceStripScroll='horizontal']
|
* @property {String} [referenceStripScroll='horizontal']
|
||||||
*
|
*
|
||||||
@ -548,16 +546,29 @@
|
|||||||
* @property {Number} [referenceStripSizeRatio=0.2]
|
* @property {Number} [referenceStripSizeRatio=0.2]
|
||||||
*
|
*
|
||||||
* @property {Boolean} [collectionMode=false]
|
* @property {Boolean} [collectionMode=false]
|
||||||
|
* Set to true to have the viewer arrange your TiledImages in a grid or line.
|
||||||
*
|
*
|
||||||
* @property {Number} [collectionRows=3]
|
* @property {Number} [collectionRows=3]
|
||||||
|
* If collectionMode is true, specifies how many rows the grid should have. Use 1 to make a line.
|
||||||
|
* If collectionLayout is 'vertical', specifies how many columns instead.
|
||||||
*
|
*
|
||||||
* @property {String} [collectionLayout='horizontal']
|
* @property {String} [collectionLayout='horizontal']
|
||||||
|
* If collectionMode is true, specifies whether to arrange vertically or horizontally.
|
||||||
*
|
*
|
||||||
* @property {Number} [collectionTileSize=800]
|
* @property {Number} [collectionTileSize=800]
|
||||||
|
* If collectionMode is true, specifies the size, in viewport coordinates, for each TiledImage to fit into.
|
||||||
|
* The TiledImage will be centered within a square of the specified size.
|
||||||
|
*
|
||||||
|
* @property {Number} [collectionTileMargin=80]
|
||||||
|
* If collectionMode is true, specifies the margin, in viewport coordinates, between each TiledImage.
|
||||||
*
|
*
|
||||||
* @property {String|Boolean} [crossOriginPolicy=false]
|
* @property {String|Boolean} [crossOriginPolicy=false]
|
||||||
* Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will
|
* Valid values are 'Anonymous', 'use-credentials', and false. If false, canvas requests will
|
||||||
* not use CORS, and the canvas will be tainted.
|
* not use CORS, and the canvas will be tainted.
|
||||||
|
*
|
||||||
|
* @property {Boolean} [ajaxWithCredentials=false]
|
||||||
|
* Whether to set the withCredentials XHR flag for AJAX requests (when loading tile sources).
|
||||||
|
* Note that this can be overridden at the {@link OpenSeadragon.TileSource} level.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -809,6 +820,25 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
canvasElement.getContext( '2d' ) );
|
canvasElement.getContext( '2d' ) );
|
||||||
}());
|
}());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ratio comparing the device screen's pixel density to the canvas's backing store pixel density. Defaults to 1 if canvas isn't supported by the browser.
|
||||||
|
* @member {Number} pixelDensityRatio
|
||||||
|
* @memberof OpenSeadragon
|
||||||
|
*/
|
||||||
|
$.pixelDensityRatio = (function () {
|
||||||
|
if ( $.supportsCanvas ) {
|
||||||
|
var context = document.createElement('canvas').getContext('2d');
|
||||||
|
var devicePixelRatio = window.devicePixelRatio || 1;
|
||||||
|
var backingStoreRatio = context.webkitBackingStorePixelRatio ||
|
||||||
|
context.mozBackingStorePixelRatio ||
|
||||||
|
context.msBackingStorePixelRatio ||
|
||||||
|
context.oBackingStorePixelRatio ||
|
||||||
|
context.backingStorePixelRatio || 1;
|
||||||
|
return devicePixelRatio / backingStoreRatio;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
}( OpenSeadragon ));
|
}( OpenSeadragon ));
|
||||||
|
|
||||||
@ -916,6 +946,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
tileHost: null,
|
tileHost: null,
|
||||||
initialPage: 0,
|
initialPage: 0,
|
||||||
crossOriginPolicy: false,
|
crossOriginPolicy: false,
|
||||||
|
ajaxWithCredentials: false,
|
||||||
|
|
||||||
//PAN AND ZOOM SETTINGS AND CONSTRAINTS
|
//PAN AND ZOOM SETTINGS AND CONSTRAINTS
|
||||||
panHorizontal: true,
|
panHorizontal: true,
|
||||||
@ -988,9 +1019,6 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
// APPEARANCE
|
// APPEARANCE
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
|
|
||||||
// LAYERS SETTINGS
|
|
||||||
layersAspectRatioEpsilon: 0.0001,
|
|
||||||
|
|
||||||
//REFERENCE STRIP SETTINGS
|
//REFERENCE STRIP SETTINGS
|
||||||
showReferenceStrip: false,
|
showReferenceStrip: false,
|
||||||
referenceStripScroll: 'horizontal',
|
referenceStripScroll: 'horizontal',
|
||||||
@ -1005,6 +1033,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
collectionLayout: 'horizontal', //vertical
|
collectionLayout: 'horizontal', //vertical
|
||||||
collectionMode: false,
|
collectionMode: false,
|
||||||
collectionTileSize: 800,
|
collectionTileSize: 800,
|
||||||
|
collectionTileMargin: 80,
|
||||||
|
|
||||||
//PERFORMANCE SETTINGS
|
//PERFORMANCE SETTINGS
|
||||||
imageLoaderLimit: 0,
|
imageLoaderLimit: 0,
|
||||||
@ -1924,13 +1953,25 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes an AJAX request.
|
* Makes an AJAX request.
|
||||||
* @function
|
* @param {Object} options
|
||||||
* @param {String} url - the url to request
|
* @param {String} options.url - the url to request
|
||||||
* @param {Function} onSuccess - a function to call on a successful response
|
* @param {Function} options.success - a function to call on a successful response
|
||||||
* @param {Function} onError - a function to call on when an error occurs
|
* @param {Function} options.error - a function to call on when an error occurs
|
||||||
|
* @param {Boolean} [options.withCredentials=false] - whether to set the XHR's withCredentials
|
||||||
* @throws {Error}
|
* @throws {Error}
|
||||||
*/
|
*/
|
||||||
makeAjaxRequest: function( url, onSuccess, onError ) {
|
makeAjaxRequest: function( url, onSuccess, onError ) {
|
||||||
|
var withCredentials;
|
||||||
|
|
||||||
|
// Note that our preferred API is that you pass in a single object; the named
|
||||||
|
// arguments are for legacy support.
|
||||||
|
if( $.isPlainObject( url ) ){
|
||||||
|
onSuccess = url.success;
|
||||||
|
onError = url.error;
|
||||||
|
withCredentials = url.withCredentials;
|
||||||
|
url = url.url;
|
||||||
|
}
|
||||||
|
|
||||||
var protocol = $.getUrlProtocol( url );
|
var protocol = $.getUrlProtocol( url );
|
||||||
var request = $.createAjaxRequest( protocol === "file:" );
|
var request = $.createAjaxRequest( protocol === "file:" );
|
||||||
|
|
||||||
@ -1957,6 +1998,10 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (withCredentials) {
|
||||||
|
request.withCredentials = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
request.open( "GET", url, true );
|
request.open( "GET", url, true );
|
||||||
request.send( null );
|
request.send( null );
|
||||||
@ -2271,7 +2316,8 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
|||||||
debug: nullfunction,
|
debug: nullfunction,
|
||||||
info: nullfunction,
|
info: nullfunction,
|
||||||
warn: nullfunction,
|
warn: nullfunction,
|
||||||
error: nullfunction
|
error: nullfunction,
|
||||||
|
assert: nullfunction
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +60,13 @@ $.Point = function( x, y ) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
|
$.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
* @returns {OpenSeadragon.Point} a duplicate of this Point
|
||||||
|
*/
|
||||||
|
clone: function() {
|
||||||
|
return new $.Point(this.x, this.y);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add another Point to this point and return a new Point.
|
* Add another Point to this point and return a new Point.
|
||||||
@ -189,7 +196,7 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
|
|||||||
* @returns {String} A string representation of this point.
|
* @returns {String} A string representation of this point.
|
||||||
*/
|
*/
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return "(" + Math.round(this.x) + "," + Math.round(this.y) + ")";
|
return "(" + (Math.round(this.x * 100) / 100) + "," + (Math.round(this.y * 100) / 100) + ")";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,6 +75,13 @@ $.Rect = function( x, y, width, height ) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
|
$.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
* @returns {OpenSeadragon.Rect} a duplicate of this Rect
|
||||||
|
*/
|
||||||
|
clone: function() {
|
||||||
|
return new $.Rect(this.x, this.y, this.width, this.height);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The aspect ratio is simply the ratio of width to height.
|
* The aspect ratio is simply the ratio of width to height.
|
||||||
@ -194,6 +201,21 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the smallest rectangle that will contain this and the given rectangle.
|
||||||
|
* @param {OpenSeadragon.Rect} rect
|
||||||
|
* @return {OpenSeadragon.Rect} The new rectangle.
|
||||||
|
*/
|
||||||
|
// ----------
|
||||||
|
union: function(rect) {
|
||||||
|
var left = Math.min(this.x, rect.x);
|
||||||
|
var top = Math.min(this.y, rect.y);
|
||||||
|
var right = Math.max(this.x + this.width, rect.x + rect.width);
|
||||||
|
var bottom = Math.max(this.y + this.height, rect.y + rect.height);
|
||||||
|
|
||||||
|
return new OpenSeadragon.Rect(left, top, right - left, bottom - top);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates a rectangle around a point. Currently only 90, 180, and 270
|
* Rotates a rectangle around a point. Currently only 90, 180, and 270
|
||||||
* degrees are supported.
|
* degrees are supported.
|
||||||
@ -257,10 +279,10 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{
|
|||||||
*/
|
*/
|
||||||
toString: function() {
|
toString: function() {
|
||||||
return "[" +
|
return "[" +
|
||||||
Math.round(this.x*100) + "," +
|
(Math.round(this.x*100) / 100) + "," +
|
||||||
Math.round(this.y*100) + "," +
|
(Math.round(this.y*100) / 100) + "," +
|
||||||
Math.round(this.width*100) + "x" +
|
(Math.round(this.width*100) / 100) + "x" +
|
||||||
Math.round(this.height*100) +
|
(Math.round(this.height*100) / 100) +
|
||||||
"]";
|
"]";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -290,6 +290,13 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Overrides Viewer.destroy
|
||||||
|
destroy: function() {
|
||||||
|
if (this.element) {
|
||||||
|
this.element.parentNode.removeChild(this.element);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} );
|
} );
|
||||||
|
@ -117,10 +117,8 @@ $.Spring.prototype = /** @lends OpenSeadragon.Spring.prototype */{
|
|||||||
* @param {Number} target
|
* @param {Number} target
|
||||||
*/
|
*/
|
||||||
resetTo: function( target ) {
|
resetTo: function( target ) {
|
||||||
this.target.value = target;
|
this.start.value = this.target.value = this.current.value = target;
|
||||||
this.target.time = this.current.time;
|
this.start.time = this.target.time = this.current.time = $.now();
|
||||||
this.start.value = this.target.value;
|
|
||||||
this.start.time = this.target.time;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
47
src/tile.js
47
src/tile.js
@ -33,7 +33,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
(function( $ ){
|
(function( $ ){
|
||||||
var TILE_CACHE = {};
|
|
||||||
/**
|
/**
|
||||||
* @class Tile
|
* @class Tile
|
||||||
* @memberof OpenSeadragon
|
* @memberof OpenSeadragon
|
||||||
@ -231,7 +231,8 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
* Renders the tile in a canvas-based context.
|
* Renders the tile in a canvas-based context.
|
||||||
* @function
|
* @function
|
||||||
* @param {Canvas} context
|
* @param {Canvas} context
|
||||||
* @param {Function} method for firing the drawing event. drawingHandler({context, tile, rendered})
|
* @param {Function} drawingHandler - Method for firing the drawing event.
|
||||||
|
* drawingHandler({context, tile, rendered})
|
||||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||||
*/
|
*/
|
||||||
drawCanvas: function( context, drawingHandler ) {
|
drawCanvas: function( context, drawingHandler ) {
|
||||||
@ -241,16 +242,23 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
rendered,
|
rendered,
|
||||||
canvas;
|
canvas;
|
||||||
|
|
||||||
if ( !this.loaded || !( this.image || TILE_CACHE[ this.url ] ) ){
|
if (!this.cacheImageRecord) {
|
||||||
|
$.console.warn('[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', this.toString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rendered = this.cacheImageRecord.getRenderedContext();
|
||||||
|
|
||||||
|
if ( !this.loaded || !( this.image || rendered) ){
|
||||||
$.console.warn(
|
$.console.warn(
|
||||||
"Attempting to draw tile %s when it's not yet loaded.",
|
"Attempting to draw tile %s when it's not yet loaded.",
|
||||||
this.toString()
|
this.toString()
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
context.globalAlpha = this.opacity;
|
|
||||||
|
|
||||||
//context.save();
|
context.globalAlpha = this.opacity;
|
||||||
|
|
||||||
//if we are supposed to be rendering fully opaque rectangle,
|
//if we are supposed to be rendering fully opaque rectangle,
|
||||||
//ie its done fading or fading is turned off, and if we are drawing
|
//ie its done fading or fading is turned off, and if we are drawing
|
||||||
@ -260,46 +268,40 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
//clearing only the inside of the rectangle occupied
|
//clearing only the inside of the rectangle occupied
|
||||||
//by the png prevents edge flikering
|
//by the png prevents edge flikering
|
||||||
context.clearRect(
|
context.clearRect(
|
||||||
position.x+1,
|
(position.x * $.pixelDensityRatio)+1,
|
||||||
position.y+1,
|
(position.y * $.pixelDensityRatio)+1,
|
||||||
size.x-2,
|
(size.x * $.pixelDensityRatio)-2,
|
||||||
size.y-2
|
(size.y * $.pixelDensityRatio)-2
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( !TILE_CACHE[ this.url ] ){
|
if(!rendered){
|
||||||
canvas = document.createElement( 'canvas' );
|
canvas = document.createElement( 'canvas' );
|
||||||
canvas.width = this.image.width;
|
canvas.width = this.image.width;
|
||||||
canvas.height = this.image.height;
|
canvas.height = this.image.height;
|
||||||
rendered = canvas.getContext('2d');
|
rendered = canvas.getContext('2d');
|
||||||
rendered.drawImage( this.image, 0, 0 );
|
rendered.drawImage( this.image, 0, 0 );
|
||||||
TILE_CACHE[ this.url ] = rendered;
|
this.cacheImageRecord.setRenderedContext(rendered);
|
||||||
//since we are caching the prerendered image on a canvas
|
//since we are caching the prerendered image on a canvas
|
||||||
//allow the image to not be held in memory
|
//allow the image to not be held in memory
|
||||||
this.image = null;
|
this.image = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
rendered = TILE_CACHE[ this.url ];
|
|
||||||
|
|
||||||
// This gives the application a chance to make image manipulation changes as we are rendering the image
|
// This gives the application a chance to make image manipulation changes as we are rendering the image
|
||||||
drawingHandler({context: context, tile: this, rendered: rendered});
|
drawingHandler({context: context, tile: this, rendered: rendered});
|
||||||
|
|
||||||
//rendered.save();
|
|
||||||
context.drawImage(
|
context.drawImage(
|
||||||
rendered.canvas,
|
rendered.canvas,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
rendered.canvas.width,
|
rendered.canvas.width,
|
||||||
rendered.canvas.height,
|
rendered.canvas.height,
|
||||||
position.x,
|
position.x * $.pixelDensityRatio,
|
||||||
position.y,
|
position.y * $.pixelDensityRatio,
|
||||||
size.x,
|
size.x * $.pixelDensityRatio,
|
||||||
size.y
|
size.y * $.pixelDensityRatio
|
||||||
);
|
);
|
||||||
//rendered.restore();
|
|
||||||
|
|
||||||
//context.restore();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,9 +315,6 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
|||||||
if ( this.element && this.element.parentNode ) {
|
if ( this.element && this.element.parentNode ) {
|
||||||
this.element.parentNode.removeChild( this.element );
|
this.element.parentNode.removeChild( this.element );
|
||||||
}
|
}
|
||||||
if ( TILE_CACHE[ this.url ]){
|
|
||||||
delete TILE_CACHE[ this.url ];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element = null;
|
this.element = null;
|
||||||
this.imgElement = null;
|
this.imgElement = null;
|
||||||
|
238
src/tilecache.js
Normal file
238
src/tilecache.js
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
/*
|
||||||
|
* OpenSeadragon - TileCache
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 CodePlex Foundation
|
||||||
|
* Copyright (C) 2010-2013 OpenSeadragon contributors
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of CodePlex Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function( $ ){
|
||||||
|
|
||||||
|
// private class
|
||||||
|
var TileRecord = function( options ) {
|
||||||
|
$.console.assert( options, "[TileCache.cacheTile] options is required" );
|
||||||
|
$.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" );
|
||||||
|
$.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" );
|
||||||
|
this.tile = options.tile;
|
||||||
|
this.tiledImage = options.tiledImage;
|
||||||
|
};
|
||||||
|
|
||||||
|
// private class
|
||||||
|
var ImageRecord = function(options) {
|
||||||
|
$.console.assert( options, "[ImageRecord] options is required" );
|
||||||
|
$.console.assert( options.image, "[ImageRecord] options.image is required" );
|
||||||
|
this._image = options.image;
|
||||||
|
this._tiles = [];
|
||||||
|
};
|
||||||
|
|
||||||
|
ImageRecord.prototype = {
|
||||||
|
destroy: function() {
|
||||||
|
this._image = null;
|
||||||
|
this._renderedContext = null;
|
||||||
|
this._tiles = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getImage: function() {
|
||||||
|
return this._image;
|
||||||
|
},
|
||||||
|
|
||||||
|
getRenderedContext: function() {
|
||||||
|
return this._renderedContext;
|
||||||
|
},
|
||||||
|
|
||||||
|
setRenderedContext: function(renderedContext) {
|
||||||
|
this._renderedContext = renderedContext;
|
||||||
|
},
|
||||||
|
|
||||||
|
addTile: function(tile) {
|
||||||
|
$.console.assert(tile, '[ImageRecord.addTile] tile is required');
|
||||||
|
this._tiles.push(tile);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeTile: function(tile) {
|
||||||
|
for (var i = 0; i < this._tiles.length; i++) {
|
||||||
|
if (this._tiles[i] === tile) {
|
||||||
|
this._tiles.splice(i, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$.console.warn('[ImageRecord.removeTile] trying to remove unknown tile', tile);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTileCount: function() {
|
||||||
|
return this._tiles.length;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class TileCache
|
||||||
|
* @memberof OpenSeadragon
|
||||||
|
* @classdesc Stores all the tiles displayed in a {@link OpenSeadragon.Viewer}.
|
||||||
|
* You generally won't have to interact with the TileCache directly.
|
||||||
|
* @param {Object} options - Configuration for this TileCache.
|
||||||
|
* @param {Number} [options.maxImageCacheCount] - See maxImageCacheCount in
|
||||||
|
* {@link OpenSeadragon.Options} for details.
|
||||||
|
*/
|
||||||
|
$.TileCache = function( options ) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
this._maxImageCacheCount = options.maxImageCacheCount || $.DEFAULT_SETTINGS.maxImageCacheCount;
|
||||||
|
this._tilesLoaded = [];
|
||||||
|
this._imagesLoaded = [];
|
||||||
|
this._imagesLoadedCount = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
$.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||||
|
/**
|
||||||
|
* @returns {Number} The total number of tiles that have been loaded by
|
||||||
|
* this TileCache.
|
||||||
|
*/
|
||||||
|
numTilesLoaded: function() {
|
||||||
|
return this._tilesLoaded.length;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Caches the specified tile, removing an old tile if necessary to stay under the
|
||||||
|
* maxImageCacheCount specified on construction. Note that if multiple tiles reference
|
||||||
|
* the same image, there may be more tiles than maxImageCacheCount; the goal is to keep
|
||||||
|
* the number of images below that number. Note, as well, that even the number of images
|
||||||
|
* may temporarily surpass that number, but should eventually come back down to the max specified.
|
||||||
|
* @param {Object} options - Tile info.
|
||||||
|
* @param {OpenSeadragon.Tile} options.tile - The tile to cache.
|
||||||
|
* @param {OpenSeadragon.TiledImage} options.tiledImage - The TiledImage that owns that tile.
|
||||||
|
* @param {Number} [options.cutoff=0] - If adding this tile goes over the cache max count, this
|
||||||
|
* function will release an old tile. The cutoff option specifies a tile level at or below which
|
||||||
|
* tiles will not be released.
|
||||||
|
*/
|
||||||
|
cacheTile: function( options ) {
|
||||||
|
$.console.assert( options, "[TileCache.cacheTile] options is required" );
|
||||||
|
$.console.assert( options.tile, "[TileCache.cacheTile] options.tile is required" );
|
||||||
|
$.console.assert( options.tile.url, "[TileCache.cacheTile] options.tile.url is required" );
|
||||||
|
$.console.assert( options.tile.image, "[TileCache.cacheTile] options.tile.image is required" );
|
||||||
|
$.console.assert( options.tiledImage, "[TileCache.cacheTile] options.tiledImage is required" );
|
||||||
|
|
||||||
|
var cutoff = options.cutoff || 0;
|
||||||
|
var insertionIndex = this._tilesLoaded.length;
|
||||||
|
|
||||||
|
var imageRecord = this._imagesLoaded[options.tile.url];
|
||||||
|
if (!imageRecord) {
|
||||||
|
imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({
|
||||||
|
image: options.tile.image
|
||||||
|
});
|
||||||
|
|
||||||
|
this._imagesLoadedCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
imageRecord.addTile(options.tile);
|
||||||
|
options.tile.cacheImageRecord = imageRecord;
|
||||||
|
|
||||||
|
// Note that just because we're unloading a tile doesn't necessarily mean
|
||||||
|
// we're unloading an image. With repeated calls it should sort itself out, though.
|
||||||
|
if ( this._imagesLoadedCount > this._maxImageCacheCount ) {
|
||||||
|
var worstTile = null;
|
||||||
|
var worstTileIndex = -1;
|
||||||
|
var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;
|
||||||
|
|
||||||
|
for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) {
|
||||||
|
prevTileRecord = this._tilesLoaded[ i ];
|
||||||
|
prevTile = prevTileRecord.tile;
|
||||||
|
|
||||||
|
if ( prevTile.level <= cutoff || prevTile.beingDrawn ) {
|
||||||
|
continue;
|
||||||
|
} else if ( !worstTile ) {
|
||||||
|
worstTile = prevTile;
|
||||||
|
worstTileIndex = i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevTime = prevTile.lastTouchTime;
|
||||||
|
worstTime = worstTile.lastTouchTime;
|
||||||
|
prevLevel = prevTile.level;
|
||||||
|
worstLevel = worstTile.level;
|
||||||
|
|
||||||
|
if ( prevTime < worstTime ||
|
||||||
|
( prevTime == worstTime && prevLevel > worstLevel ) ) {
|
||||||
|
worstTile = prevTile;
|
||||||
|
worstTileIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( worstTile && worstTileIndex >= 0 ) {
|
||||||
|
this._unloadTile(worstTile);
|
||||||
|
insertionIndex = worstTileIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._tilesLoaded[ insertionIndex ] = new TileRecord({
|
||||||
|
tile: options.tile,
|
||||||
|
tiledImage: options.tiledImage
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all tiles associated with the specified tiledImage.
|
||||||
|
* @param {OpenSeadragon.TiledImage} tiledImage
|
||||||
|
*/
|
||||||
|
clearTilesFor: function( tiledImage ) {
|
||||||
|
$.console.assert(tiledImage, '[TileCache.clearTilesFor] tiledImage is required');
|
||||||
|
var tileRecord;
|
||||||
|
for ( var i = 0; i < this._tilesLoaded.length; ++i ) {
|
||||||
|
tileRecord = this._tilesLoaded[ i ];
|
||||||
|
if ( tileRecord.tiledImage === tiledImage ) {
|
||||||
|
this._unloadTile(tileRecord.tile);
|
||||||
|
this._tilesLoaded.splice( i, 1 );
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
getImageRecord: function(url) {
|
||||||
|
$.console.assert(url, '[TileCache.getImageRecord] url is required');
|
||||||
|
return this._imagesLoaded[url];
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_unloadTile: function(tile) {
|
||||||
|
$.console.assert(tile, '[TileCache._unloadTile] tile is required');
|
||||||
|
tile.unload();
|
||||||
|
tile.cacheImageRecord = null;
|
||||||
|
|
||||||
|
var imageRecord = this._imagesLoaded[tile.url];
|
||||||
|
imageRecord.removeTile(tile);
|
||||||
|
if (!imageRecord.getTileCount()) {
|
||||||
|
imageRecord.destroy();
|
||||||
|
delete this._imagesLoaded[tile.url];
|
||||||
|
this._imagesLoadedCount--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}( OpenSeadragon ));
|
1149
src/tiledimage.js
Normal file
1149
src/tiledimage.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -38,44 +38,52 @@
|
|||||||
/**
|
/**
|
||||||
* @class TileSource
|
* @class TileSource
|
||||||
* @classdesc The TileSource contains the most basic implementation required to create a
|
* @classdesc 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
|
* smooth transition between layers in an image pyramid. It has only a single key
|
||||||
* interface that must be implemented to complete it key functionality:
|
* interface that must be implemented to complete its key functionality:
|
||||||
* 'getTileUrl'. It also has several optional interfaces that can be
|
* 'getTileUrl'. It also has several optional interfaces that can be
|
||||||
* implemented if a new TileSource wishes to support configuration via a simple
|
* implemented if a new TileSource wishes to support configuration via a simple
|
||||||
* object or array ('configure') and if the tile source supports or requires
|
* 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,
|
* configuration via retrieval of a document on the network ala AJAX or JSONP,
|
||||||
* ('getImageInfo').
|
* ('getImageInfo').
|
||||||
* <br/>
|
* <br/>
|
||||||
* By default the image pyramid is split into N layers where the images longest
|
* By default the image pyramid is split into N layers where the image's longest
|
||||||
* side in M (in pixels), where N is the smallest integer which satisfies
|
* side in M (in pixels), where N is the smallest integer which satisfies
|
||||||
* <strong>2^(N+1) >= M</strong>.
|
* <strong>2^(N+1) >= M</strong>.
|
||||||
*
|
*
|
||||||
* @memberof OpenSeadragon
|
* @memberof OpenSeadragon
|
||||||
* @extends OpenSeadragon.EventSource
|
* @extends OpenSeadragon.EventSource
|
||||||
* @param {Number|Object|Array|String} width
|
* @param {Object} options
|
||||||
* If more than a single argument is supplied, the traditional use of
|
* You can either specify a URL, or literally define the TileSource (by specifying
|
||||||
* positional parameters is supplied and width is expected to be the width
|
* width, height, tileSize, tileOverlap, minLevel, and maxLevel). For the former,
|
||||||
* source image at its max resolution in pixels. If a single argument is supplied and
|
* the extending class is expected to implement 'getImageInfo' and 'configure'.
|
||||||
* it is an Object or Array, the construction is assumed to occur through
|
* For the latter, the construction is assumed to occur through
|
||||||
* the extending classes implementation of 'configure'. Finally if only a
|
* the extending classes implementation of 'configure'.
|
||||||
* single argument is supplied and it is a String, the extending class is
|
* @param {String} [options.url]
|
||||||
* expected to implement 'getImageInfo' and 'configure'.
|
* The URL for the data necessary for this TileSource.
|
||||||
* @param {Number} height
|
* @param {Function} [options.success]
|
||||||
|
* A function to be called upon successful creation.
|
||||||
|
* @param {Boolean} [options.ajaxWithCredentials]
|
||||||
|
* If this TileSource needs to make an AJAX call, this specifies whether to set
|
||||||
|
* the XHR's withCredentials (for accessing secure data).
|
||||||
|
* @param {Number} [options.width]
|
||||||
* Width of the source image at max resolution in pixels.
|
* Width of the source image at max resolution in pixels.
|
||||||
* @param {Number} tileSize
|
* @param {Number} [options.height]
|
||||||
|
* Height of the source image at max resolution in pixels.
|
||||||
|
* @param {Number} [options.tileSize]
|
||||||
* The size of the tiles to assumed to make up each pyramid layer in pixels.
|
* 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
|
* Tile size determines the point at which the image pyramid must be
|
||||||
* divided into a matrix of smaller images.
|
* divided into a matrix of smaller images.
|
||||||
* @param {Number} tileOverlap
|
* @param {Number} [options.tileOverlap]
|
||||||
* The number of pixels each tile is expected to overlap touching tiles.
|
* The number of pixels each tile is expected to overlap touching tiles.
|
||||||
* @param {Number} minLevel
|
* @param {Number} [options.minLevel]
|
||||||
* The minimum level to attempt to load.
|
* The minimum level to attempt to load.
|
||||||
* @param {Number} maxLevel
|
* @param {Number} [options.maxLevel]
|
||||||
* The maximum level to attempt to load.
|
* The maximum level to attempt to load.
|
||||||
*/
|
*/
|
||||||
$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {
|
$.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLevel ) {
|
||||||
var callback = null,
|
var _this = this;
|
||||||
args = arguments,
|
|
||||||
|
var args = arguments,
|
||||||
options,
|
options,
|
||||||
i;
|
i;
|
||||||
|
|
||||||
@ -102,19 +110,23 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
|||||||
//source
|
//source
|
||||||
$.extend( true, this, options );
|
$.extend( true, this, options );
|
||||||
|
|
||||||
//Any functions that are passed as arguments are bound to the ready callback
|
if (!this.success) {
|
||||||
/*jshint loopfunc:true*/
|
//Any functions that are passed as arguments are bound to the ready callback
|
||||||
for ( i = 0; i < arguments.length; i++ ) {
|
for ( i = 0; i < arguments.length; i++ ) {
|
||||||
if ( $.isFunction( arguments[ i ] ) ) {
|
if ( $.isFunction( arguments[ i ] ) ) {
|
||||||
callback = arguments[ i ];
|
this.success = arguments[ i ];
|
||||||
this.addHandler( 'ready', function ( event ) {
|
//only one callback per constructor
|
||||||
callback( event );
|
break;
|
||||||
} );
|
}
|
||||||
//only one callback per constructor
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.success) {
|
||||||
|
this.addHandler( 'ready', function ( event ) {
|
||||||
|
_this.success( event );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ratio of width to height
|
* Ratio of width to height
|
||||||
* @member {Number} aspectRatio
|
* @member {Number} aspectRatio
|
||||||
@ -154,6 +166,10 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if( 'string' == $.type( arguments[ 0 ] ) ){
|
if( 'string' == $.type( arguments[ 0 ] ) ){
|
||||||
|
this.url = arguments[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.url) {
|
||||||
//in case the getImageInfo method is overriden and/or implies an
|
//in case the getImageInfo method is overriden and/or implies an
|
||||||
//async mechanism set some safe defaults first
|
//async mechanism set some safe defaults first
|
||||||
this.aspectRatio = 1;
|
this.aspectRatio = 1;
|
||||||
@ -165,7 +181,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
|||||||
this.ready = false;
|
this.ready = false;
|
||||||
//configuration via url implies the extending class
|
//configuration via url implies the extending class
|
||||||
//implements and 'configure'
|
//implements and 'configure'
|
||||||
this.getImageInfo( arguments[ 0 ] );
|
this.getImageInfo( this.url );
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -185,8 +201,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
|||||||
Math.log( 2 )
|
Math.log( 2 )
|
||||||
) : 0
|
) : 0
|
||||||
);
|
);
|
||||||
if( callback && $.isFunction( callback ) ){
|
if( this.success && $.isFunction( this.success ) ){
|
||||||
callback( this );
|
this.success( this );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,6 +371,10 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
|||||||
}
|
}
|
||||||
|
|
||||||
options = $TileSource.prototype.configure.apply( _this, [ data, url ]);
|
options = $TileSource.prototype.configure.apply( _this, [ data, url ]);
|
||||||
|
if (options.ajaxWithCredentials === undefined) {
|
||||||
|
options.ajaxWithCredentials = _this.ajaxWithCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
readySource = new $TileSource( options );
|
readySource = new $TileSource( options );
|
||||||
_this.ready = true;
|
_this.ready = true;
|
||||||
/**
|
/**
|
||||||
@ -383,45 +403,50 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// request info via xhr asynchronously.
|
// request info via xhr asynchronously.
|
||||||
$.makeAjaxRequest( url, function( xhr ) {
|
$.makeAjaxRequest( {
|
||||||
var data = processResponse( xhr );
|
url: url,
|
||||||
callback( data );
|
withCredentials: this.ajaxWithCredentials,
|
||||||
}, function ( xhr, exc ) {
|
success: function( xhr ) {
|
||||||
var msg;
|
var data = processResponse( xhr );
|
||||||
|
callback( data );
|
||||||
|
},
|
||||||
|
error: function ( xhr, exc ) {
|
||||||
|
var msg;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
IE < 10 will block XHR requests to different origins. Any property access on the request
|
IE < 10 will block XHR requests to different origins. Any property access on the request
|
||||||
object will raise an exception which we'll attempt to handle by formatting the original
|
object will raise an exception which we'll attempt to handle by formatting the original
|
||||||
exception rather than the second one raised when we try to access xhr.status
|
exception rather than the second one raised when we try to access xhr.status
|
||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
msg = "HTTP " + xhr.status + " attempting to load TileSource";
|
msg = "HTTP " + xhr.status + " attempting to load TileSource";
|
||||||
} catch ( e ) {
|
} catch ( e ) {
|
||||||
var formattedExc;
|
var formattedExc;
|
||||||
if ( typeof( exc ) == "undefined" || !exc.toString ) {
|
if ( typeof( exc ) == "undefined" || !exc.toString ) {
|
||||||
formattedExc = "Unknown error";
|
formattedExc = "Unknown error";
|
||||||
} else {
|
} else {
|
||||||
formattedExc = exc.toString();
|
formattedExc = exc.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = formattedExc + " attempting to load TileSource";
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = formattedExc + " attempting to load TileSource";
|
/***
|
||||||
|
* Raised when an error occurs loading a TileSource.
|
||||||
|
*
|
||||||
|
* @event open-failed
|
||||||
|
* @memberof OpenSeadragon.TileSource
|
||||||
|
* @type {object}
|
||||||
|
* @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.
|
||||||
|
* @property {String} message
|
||||||
|
* @property {String} source
|
||||||
|
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||||
|
*/
|
||||||
|
_this.raiseEvent( 'open-failed', {
|
||||||
|
message: msg,
|
||||||
|
source: url
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/***
|
|
||||||
* Raised when an error occurs loading a TileSource.
|
|
||||||
*
|
|
||||||
* @event open-failed
|
|
||||||
* @memberof OpenSeadragon.TileSource
|
|
||||||
* @type {object}
|
|
||||||
* @property {OpenSeadragon.TileSource} eventSource - A reference to the TileSource which raised the event.
|
|
||||||
* @property {String} message
|
|
||||||
* @property {String} source
|
|
||||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
|
||||||
*/
|
|
||||||
_this.raiseEvent( 'open-failed', {
|
|
||||||
message: msg,
|
|
||||||
source: url
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,110 +34,9 @@
|
|||||||
|
|
||||||
(function( $ ){
|
(function( $ ){
|
||||||
|
|
||||||
/**
|
// deprecated
|
||||||
* @class TileSourceCollection
|
|
||||||
* @memberof OpenSeadragon
|
|
||||||
* @extends OpenSeadragon.TileSource
|
|
||||||
*/
|
|
||||||
$.TileSourceCollection = function( tileSize, tileSources, rows, layout ) {
|
$.TileSourceCollection = function( tileSize, tileSources, rows, layout ) {
|
||||||
var options;
|
$.console.error('TileSourceCollection is deprecated; use World instead');
|
||||||
|
|
||||||
if( $.isPlainObject( tileSize ) ){
|
|
||||||
options = tileSize;
|
|
||||||
}else{
|
|
||||||
options = {
|
|
||||||
tileSize: arguments[ 0 ],
|
|
||||||
tileSources: arguments[ 1 ],
|
|
||||||
rows: arguments[ 2 ],
|
|
||||||
layout: arguments[ 3 ]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !options.layout ){
|
|
||||||
options.layout = 'horizontal';
|
|
||||||
}
|
|
||||||
|
|
||||||
var minLevel = 0,
|
|
||||||
levelSize = 1.0,
|
|
||||||
tilesPerRow = Math.ceil( options.tileSources.length / options.rows ),
|
|
||||||
longSide = tilesPerRow >= options.rows ?
|
|
||||||
tilesPerRow :
|
|
||||||
options.rows;
|
|
||||||
|
|
||||||
if( 'horizontal' == options.layout ){
|
|
||||||
options.width = ( options.tileSize ) * tilesPerRow;
|
|
||||||
options.height = ( options.tileSize ) * options.rows;
|
|
||||||
} else {
|
|
||||||
options.height = ( options.tileSize ) * tilesPerRow;
|
|
||||||
options.width = ( options.tileSize ) * options.rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
options.tileOverlap = -options.tileMargin;
|
|
||||||
options.tilesPerRow = tilesPerRow;
|
|
||||||
|
|
||||||
//Set min level to avoid loading sublevels since collection is a
|
|
||||||
//different kind of abstraction
|
|
||||||
|
|
||||||
while( levelSize < ( options.tileSize ) * longSide ){
|
|
||||||
//$.console.log( '%s levelSize %s minLevel %s', options.tileSize * longSide, levelSize, minLevel );
|
|
||||||
levelSize = levelSize * 2.0;
|
|
||||||
minLevel++;
|
|
||||||
}
|
|
||||||
options.minLevel = minLevel;
|
|
||||||
|
|
||||||
//for( var name in options ){
|
|
||||||
// $.console.log( 'Collection %s %s', name, options[ name ] );
|
|
||||||
//}
|
|
||||||
|
|
||||||
$.TileSource.apply( this, [ options ] );
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$.extend( $.TileSourceCollection.prototype, $.TileSource.prototype, /** @lends OpenSeadragon.TileSourceCollection.prototype */{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @function
|
|
||||||
* @param {Number} level
|
|
||||||
* @param {Number} x
|
|
||||||
* @param {Number} y
|
|
||||||
*/
|
|
||||||
getTileBounds: function( level, x, y ) {
|
|
||||||
var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
|
||||||
px = this.tileSize * x - this.tileOverlap,
|
|
||||||
py = this.tileSize * y - this.tileOverlap,
|
|
||||||
sx = this.tileSize + 1 * this.tileOverlap,
|
|
||||||
sy = this.tileSize + 1 * this.tileOverlap,
|
|
||||||
scale = 1.0 / dimensionsScaled.x;
|
|
||||||
|
|
||||||
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 );
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @function
|
|
||||||
*/
|
|
||||||
configure: function( data, url ){
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @function
|
|
||||||
* @param {Number} level
|
|
||||||
* @param {Number} x
|
|
||||||
* @param {Number} y
|
|
||||||
*/
|
|
||||||
getTileUrl: function( level, x, y ) {
|
|
||||||
//$.console.log([ level, '/', x, '_', y ].join( '' ));
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
}( OpenSeadragon ));
|
}( OpenSeadragon ));
|
||||||
|
1173
src/viewer.js
1173
src/viewer.js
File diff suppressed because it is too large
Load Diff
377
src/viewport.js
377
src/viewport.js
@ -37,10 +37,23 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @class Viewport
|
* @class Viewport
|
||||||
* @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.) for an {@link OpenSeadragon.Viewer}.
|
|
||||||
* A new instance is created for each TileSource opened (see {@link OpenSeadragon.Viewer#viewport}).
|
|
||||||
*
|
|
||||||
* @memberof OpenSeadragon
|
* @memberof OpenSeadragon
|
||||||
|
* @classdesc Handles coordinate-related functionality (zoom, pan, rotation, etc.)
|
||||||
|
* for an {@link OpenSeadragon.Viewer}.
|
||||||
|
* @param {Object} options - Options for this Viewport.
|
||||||
|
* @param {Object} [options.margins] - See viewportMargins in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.springStiffness] - See springStiffness in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.animationTime] - See animationTime in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.minZoomImageRatio] - See minZoomImageRatio in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.maxZoomPixelRatio] - See maxZoomPixelRatio in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.visibilityRatio] - See visibilityRatio in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Boolean} [options.wrapHorizontal] - See wrapHorizontal in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Boolean} [options.wrapVertical] - See wrapVertical in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.defaultZoomLevel] - See defaultZoomLevel in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.minZoomLevel] - See minZoomLevel in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.maxZoomLevel] - See maxZoomLevel in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.degrees] - See degrees in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Boolean} [options.homeFillsViewer] - See homeFillsViewer in {@link OpenSeadragon.Options}.
|
||||||
*/
|
*/
|
||||||
$.Viewport = function( options ) {
|
$.Viewport = function( options ) {
|
||||||
|
|
||||||
@ -63,6 +76,15 @@ $.Viewport = function( options ) {
|
|||||||
delete options.config;
|
delete options.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._margins = $.extend({
|
||||||
|
left: 0,
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0
|
||||||
|
}, options.margins || {});
|
||||||
|
|
||||||
|
delete options.margins;
|
||||||
|
|
||||||
$.extend( true, this, {
|
$.extend( true, this, {
|
||||||
|
|
||||||
//required settings
|
//required settings
|
||||||
@ -89,6 +111,11 @@ $.Viewport = function( options ) {
|
|||||||
|
|
||||||
}, options );
|
}, options );
|
||||||
|
|
||||||
|
this._containerInnerSize = new $.Point(
|
||||||
|
Math.max(1, this.containerSize.x - (this._margins.left + this._margins.right)),
|
||||||
|
Math.max(1, this.containerSize.y - (this._margins.top + this._margins.bottom))
|
||||||
|
);
|
||||||
|
|
||||||
this.centerSpringX = new $.Spring({
|
this.centerSpringX = new $.Spring({
|
||||||
initial: 0,
|
initial: 0,
|
||||||
springStiffness: this.springStiffness,
|
springStiffness: this.springStiffness,
|
||||||
@ -105,44 +132,77 @@ $.Viewport = function( options ) {
|
|||||||
animationTime: this.animationTime
|
animationTime: this.animationTime
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resetContentSize( this.contentSize );
|
this._oldCenterX = this.centerSpringX.current.value;
|
||||||
|
this._oldCenterY = this.centerSpringY.current.value;
|
||||||
|
this._oldZoom = this.zoomSpring.current.value;
|
||||||
|
|
||||||
|
if (this.contentSize) {
|
||||||
|
this.resetContentSize( this.contentSize );
|
||||||
|
} else {
|
||||||
|
this.setHomeBounds(new $.Rect(0, 0, 1, 1), 1);
|
||||||
|
}
|
||||||
|
|
||||||
this.goHome( true );
|
this.goHome( true );
|
||||||
this.update();
|
this.update();
|
||||||
};
|
};
|
||||||
|
|
||||||
$.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
$.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Updates the viewport's home bounds and constraints for the given content size.
|
||||||
* @function
|
* @function
|
||||||
|
* @param {OpenSeadragon.Point} contentSize - size of the content in content units
|
||||||
* @return {OpenSeadragon.Viewport} Chainable.
|
* @return {OpenSeadragon.Viewport} Chainable.
|
||||||
* @fires OpenSeadragon.Viewer.event:reset-size
|
* @fires OpenSeadragon.Viewer.event:reset-size
|
||||||
*/
|
*/
|
||||||
resetContentSize: function( contentSize ){
|
resetContentSize: function( contentSize ){
|
||||||
this.contentSize = contentSize;
|
$.console.assert(contentSize, "[Viewport.resetContentSize] contentSize is required");
|
||||||
|
$.console.assert(contentSize instanceof $.Point, "[Viewport.resetContentSize] contentSize must be an OpenSeadragon.Point");
|
||||||
|
$.console.assert(contentSize.x > 0, "[Viewport.resetContentSize] contentSize.x must be greater than 0");
|
||||||
|
$.console.assert(contentSize.y > 0, "[Viewport.resetContentSize] contentSize.y must be greater than 0");
|
||||||
|
|
||||||
|
this.setHomeBounds(new $.Rect(0, 0, 1, contentSize.y / contentSize.x), contentSize.x);
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the viewport's home bounds and constraints.
|
||||||
|
* @function
|
||||||
|
* @param {OpenSeadragon.Rect} bounds - the new bounds in viewport coordinates
|
||||||
|
* @param {Number} contentFactor - how many content units per viewport unit
|
||||||
|
* @fires OpenSeadragon.Viewer.event:reset-size
|
||||||
|
*/
|
||||||
|
setHomeBounds: function(bounds, contentFactor) {
|
||||||
|
$.console.assert(bounds, "[Viewport.setHomeBounds] bounds is required");
|
||||||
|
$.console.assert(bounds instanceof $.Rect, "[Viewport.setHomeBounds] bounds must be an OpenSeadragon.Rect");
|
||||||
|
$.console.assert(bounds.width > 0, "[Viewport.setHomeBounds] bounds.width must be greater than 0");
|
||||||
|
$.console.assert(bounds.height > 0, "[Viewport.setHomeBounds] bounds.height must be greater than 0");
|
||||||
|
|
||||||
|
this.homeBounds = bounds.clone();
|
||||||
|
this.contentSize = this.homeBounds.getSize().times(contentFactor);
|
||||||
this.contentAspectX = this.contentSize.x / this.contentSize.y;
|
this.contentAspectX = this.contentSize.x / this.contentSize.y;
|
||||||
this.contentAspectY = this.contentSize.y / this.contentSize.x;
|
this.contentAspectY = this.contentSize.y / this.contentSize.x;
|
||||||
this.fitWidthBounds = new $.Rect( 0, 0, 1, this.contentAspectY );
|
|
||||||
this.fitHeightBounds = new $.Rect( 0, 0, this.contentAspectY, this.contentAspectY);
|
|
||||||
|
|
||||||
this.homeBounds = new $.Rect( 0, 0, 1, this.contentAspectY );
|
|
||||||
|
|
||||||
if( this.viewer ){
|
if( this.viewer ){
|
||||||
/**
|
/**
|
||||||
* Raised when the viewer's content size is reset (see {@link OpenSeadragon.Viewport#resetContentSize}).
|
* Raised when the viewer's content size or home bounds are reset
|
||||||
|
* (see {@link OpenSeadragon.Viewport#resetContentSize},
|
||||||
|
* {@link OpenSeadragon.Viewport#setHomeBounds}).
|
||||||
*
|
*
|
||||||
* @event reset-size
|
* @event reset-size
|
||||||
* @memberof OpenSeadragon.Viewer
|
* @memberof OpenSeadragon.Viewer
|
||||||
* @type {object}
|
* @type {object}
|
||||||
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
|
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
|
||||||
* @property {OpenSeadragon.Point} contentSize
|
* @property {OpenSeadragon.Point} contentSize
|
||||||
|
* @property {OpenSeadragon.Rect} homeBounds
|
||||||
|
* @property {Number} contentFactor
|
||||||
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||||
*/
|
*/
|
||||||
this.viewer.raiseEvent( 'reset-size', {
|
this.viewer.raiseEvent( 'reset-size', {
|
||||||
contentSize: contentSize
|
contentSize: this.contentSize.clone(),
|
||||||
|
contentFactor: contentFactor,
|
||||||
|
homeBounds: this.homeBounds.clone()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -155,15 +215,18 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
var aspectFactor =
|
var aspectFactor =
|
||||||
this.contentAspectX / this.getAspectRatio();
|
this.contentAspectX / this.getAspectRatio();
|
||||||
|
|
||||||
|
var output;
|
||||||
if( this.homeFillsViewer ){ // fill the viewer and clip the image
|
if( this.homeFillsViewer ){ // fill the viewer and clip the image
|
||||||
return ( aspectFactor >= 1) ?
|
output = ( aspectFactor >= 1) ?
|
||||||
aspectFactor :
|
aspectFactor :
|
||||||
1;
|
1;
|
||||||
} else {
|
} else {
|
||||||
return ( aspectFactor >= 1 ) ?
|
output = ( aspectFactor >= 1 ) ?
|
||||||
1 :
|
1 :
|
||||||
aspectFactor;
|
aspectFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return output / this.homeBounds.width;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -216,16 +279,18 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
this.minZoomLevel :
|
this.minZoomLevel :
|
||||||
this.minZoomImageRatio * homeZoom;
|
this.minZoomImageRatio * homeZoom;
|
||||||
|
|
||||||
return Math.min( zoom, homeZoom );
|
return zoom;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
getMaxZoom: function() {
|
getMaxZoom: function() {
|
||||||
var zoom = this.maxZoomLevel ?
|
var zoom = this.maxZoomLevel;
|
||||||
this.maxZoomLevel :
|
if (!zoom) {
|
||||||
( this.contentSize.x * this.maxZoomPixelRatio / this.containerSize.x );
|
zoom = this.contentSize.x * this.maxZoomPixelRatio / this._containerInnerSize.x;
|
||||||
|
zoom /= this.homeBounds.width;
|
||||||
|
}
|
||||||
|
|
||||||
return Math.max( zoom, this.getHomeZoom() );
|
return Math.max( zoom, this.getHomeZoom() );
|
||||||
},
|
},
|
||||||
@ -234,11 +299,12 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
getAspectRatio: function() {
|
getAspectRatio: function() {
|
||||||
return this.containerSize.x / this.containerSize.y;
|
return this._containerInnerSize.x / this._containerInnerSize.y;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
|
* @returns {OpenSeadragon.Point} The size of the container, in screen coordinates.
|
||||||
*/
|
*/
|
||||||
getContainerSize: function() {
|
getContainerSize: function() {
|
||||||
return new $.Point(
|
return new $.Point(
|
||||||
@ -250,6 +316,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
||||||
|
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to, in viewport coordinates.
|
||||||
*/
|
*/
|
||||||
getBounds: function( current ) {
|
getBounds: function( current ) {
|
||||||
var center = this.getCenter( current ),
|
var center = this.getCenter( current ),
|
||||||
@ -264,6 +331,22 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function
|
||||||
|
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
||||||
|
* @returns {OpenSeadragon.Rect} The location you are zoomed/panned to,
|
||||||
|
* including the space taken by margins, in viewport coordinates.
|
||||||
|
*/
|
||||||
|
getBoundsWithMargins: function( current ) {
|
||||||
|
var bounds = this.getBounds(current);
|
||||||
|
var factor = this._containerInnerSize.x * this.getZoom(current);
|
||||||
|
bounds.x -= this._margins.left / factor;
|
||||||
|
bounds.y -= this._margins.top / factor;
|
||||||
|
bounds.width += (this._margins.left + this._margins.right) / factor;
|
||||||
|
bounds.height += (this._margins.top + this._margins.bottom) / factor;
|
||||||
|
return bounds;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* @function
|
||||||
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
||||||
@ -304,13 +387,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
height
|
height
|
||||||
);
|
);
|
||||||
|
|
||||||
newZoomPixel = this.zoomPoint.minus(
|
newZoomPixel = this._pixelFromPoint(this.zoomPoint, bounds);
|
||||||
bounds.getTopLeft()
|
|
||||||
).times(
|
|
||||||
this.containerSize.x / bounds.width
|
|
||||||
);
|
|
||||||
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );
|
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );
|
||||||
deltaZoomPoints = deltaZoomPixels.divide( this.containerSize.x * zoom );
|
deltaZoomPoints = deltaZoomPixels.divide( this._containerInnerSize.x * zoom );
|
||||||
|
|
||||||
return centerTarget.plus( deltaZoomPoints );
|
return centerTarget.plus( deltaZoomPoints );
|
||||||
},
|
},
|
||||||
@ -335,13 +414,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* @return {OpenSeadragon.Rect} constrained bounds.
|
* @return {OpenSeadragon.Rect} constrained bounds.
|
||||||
*/
|
*/
|
||||||
_applyBoundaryConstraints: function( bounds, immediately ) {
|
_applyBoundaryConstraints: function( bounds, immediately ) {
|
||||||
var horizontalThreshold,
|
var dx = 0,
|
||||||
verticalThreshold,
|
|
||||||
left,
|
|
||||||
right,
|
|
||||||
top,
|
|
||||||
bottom,
|
|
||||||
dx = 0,
|
|
||||||
dy = 0,
|
dy = 0,
|
||||||
newBounds = new $.Rect(
|
newBounds = new $.Rect(
|
||||||
bounds.x,
|
bounds.x,
|
||||||
@ -350,49 +423,52 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
bounds.height
|
bounds.height
|
||||||
);
|
);
|
||||||
|
|
||||||
horizontalThreshold = this.visibilityRatio * newBounds.width;
|
var horizontalThreshold = this.visibilityRatio * newBounds.width;
|
||||||
verticalThreshold = this.visibilityRatio * newBounds.height;
|
var verticalThreshold = this.visibilityRatio * newBounds.height;
|
||||||
|
|
||||||
left = newBounds.x + newBounds.width;
|
|
||||||
right = 1 - newBounds.x;
|
|
||||||
top = newBounds.y + newBounds.height;
|
|
||||||
bottom = this.contentAspectY - newBounds.y;
|
|
||||||
|
|
||||||
if ( this.wrapHorizontal ) {
|
if ( this.wrapHorizontal ) {
|
||||||
//do nothing
|
//do nothing
|
||||||
} else {
|
} else {
|
||||||
if ( left < horizontalThreshold ) {
|
var thresholdLeft = newBounds.x + (newBounds.width - horizontalThreshold);
|
||||||
dx = horizontalThreshold - left;
|
if (this.homeBounds.x > thresholdLeft) {
|
||||||
|
dx = this.homeBounds.x - thresholdLeft;
|
||||||
}
|
}
|
||||||
if ( right < horizontalThreshold ) {
|
|
||||||
dx = dx ?
|
var homeRight = this.homeBounds.x + this.homeBounds.width;
|
||||||
( dx + right - horizontalThreshold ) / 2 :
|
var thresholdRight = newBounds.x + horizontalThreshold;
|
||||||
( right - horizontalThreshold );
|
if (homeRight < thresholdRight) {
|
||||||
|
var newDx = homeRight - thresholdRight;
|
||||||
|
if (dx) {
|
||||||
|
dx = (dx + newDx) / 2;
|
||||||
|
} else {
|
||||||
|
dx = newDx;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( this.wrapVertical ) {
|
if ( this.wrapVertical ) {
|
||||||
//do nothing
|
//do nothing
|
||||||
} else {
|
} else {
|
||||||
if ( top < verticalThreshold ) {
|
var thresholdTop = newBounds.y + (newBounds.height - verticalThreshold);
|
||||||
dy = ( verticalThreshold - top );
|
if (this.homeBounds.y > thresholdTop) {
|
||||||
|
dy = this.homeBounds.y - thresholdTop;
|
||||||
}
|
}
|
||||||
if ( bottom < verticalThreshold ) {
|
|
||||||
dy = dy ?
|
var homeBottom = this.homeBounds.y + this.homeBounds.height;
|
||||||
( dy + bottom - verticalThreshold ) / 2 :
|
var thresholdBottom = newBounds.y + verticalThreshold;
|
||||||
( bottom - verticalThreshold );
|
if (homeBottom < thresholdBottom) {
|
||||||
|
var newDy = homeBottom - thresholdBottom;
|
||||||
|
if (dy) {
|
||||||
|
dy = (dy + newDy) / 2;
|
||||||
|
} else {
|
||||||
|
dy = newDy;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( dx || dy || immediately ) {
|
if ( dx || dy ) {
|
||||||
newBounds.x += dx;
|
newBounds.x += dx;
|
||||||
newBounds.y += dy;
|
newBounds.y += dy;
|
||||||
if( newBounds.width > 1 ){
|
|
||||||
newBounds.x = 0.5 - newBounds.width/2;
|
|
||||||
}
|
|
||||||
if( newBounds.height > this.contentAspectY ){
|
|
||||||
newBounds.y = this.contentAspectY/2 - newBounds.height/2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( this.viewer ){
|
if( this.viewer ){
|
||||||
@ -512,21 +588,28 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
}
|
}
|
||||||
|
|
||||||
newBounds = this._applyBoundaryConstraints( newBounds, immediately );
|
newBounds = this._applyBoundaryConstraints( newBounds, immediately );
|
||||||
|
center = newBounds.getCenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( newZoom == oldZoom || newBounds.width == oldBounds.width ) {
|
if (immediately) {
|
||||||
return this.panTo( constraints ? newBounds.getCenter() : center, immediately );
|
this.panTo( center, true );
|
||||||
|
return this.zoomTo(newZoom, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(newZoom - oldZoom) < 0.00000000001 ||
|
||||||
|
Math.abs(newBounds.width - oldBounds.width) < 0.00000000001) {
|
||||||
|
return this.panTo( center, immediately );
|
||||||
}
|
}
|
||||||
|
|
||||||
referencePoint = oldBounds.getTopLeft().times(
|
referencePoint = oldBounds.getTopLeft().times(
|
||||||
this.containerSize.x / oldBounds.width
|
this._containerInnerSize.x / oldBounds.width
|
||||||
).minus(
|
).minus(
|
||||||
newBounds.getTopLeft().times(
|
newBounds.getTopLeft().times(
|
||||||
this.containerSize.x / newBounds.width
|
this._containerInnerSize.x / newBounds.width
|
||||||
)
|
)
|
||||||
).divide(
|
).divide(
|
||||||
this.containerSize.x / oldBounds.width -
|
this._containerInnerSize.x / oldBounds.width -
|
||||||
this.containerSize.x / newBounds.width
|
this._containerInnerSize.x / newBounds.width
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.zoomTo( newZoom, referencePoint, immediately );
|
return this.zoomTo( newZoom, referencePoint, immediately );
|
||||||
@ -559,53 +642,27 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* Zooms so the image just fills the viewer vertically.
|
||||||
* @param {Boolean} immediately
|
* @param {Boolean} immediately
|
||||||
* @return {OpenSeadragon.Viewport} Chainable.
|
* @return {OpenSeadragon.Viewport} Chainable.
|
||||||
*/
|
*/
|
||||||
fitVertically: function( immediately ) {
|
fitVertically: function( immediately ) {
|
||||||
var center = this.getCenter();
|
var box = new $.Rect(this.homeBounds.x + (this.homeBounds.width / 2), this.homeBounds.y,
|
||||||
|
0, this.homeBounds.height);
|
||||||
|
|
||||||
if ( this.wrapHorizontal ) {
|
return this.fitBounds( box, immediately );
|
||||||
center.x = ( 1 + ( center.x % 1 ) ) % 1;
|
|
||||||
this.centerSpringX.resetTo( center.x );
|
|
||||||
this.centerSpringX.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.wrapVertical ) {
|
|
||||||
center.y = (
|
|
||||||
this.contentAspectY + ( center.y % this.contentAspectY )
|
|
||||||
) % this.contentAspectY;
|
|
||||||
this.centerSpringY.resetTo( center.y );
|
|
||||||
this.centerSpringY.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.fitBounds( this.fitHeightBounds, immediately );
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function
|
* Zooms so the image just fills the viewer horizontally.
|
||||||
* @param {Boolean} immediately
|
* @param {Boolean} immediately
|
||||||
* @return {OpenSeadragon.Viewport} Chainable.
|
* @return {OpenSeadragon.Viewport} Chainable.
|
||||||
*/
|
*/
|
||||||
fitHorizontally: function( immediately ) {
|
fitHorizontally: function( immediately ) {
|
||||||
var center = this.getCenter();
|
var box = new $.Rect(this.homeBounds.x, this.homeBounds.y + (this.homeBounds.height / 2),
|
||||||
|
this.homeBounds.width, 0);
|
||||||
|
|
||||||
if ( this.wrapHorizontal ) {
|
return this.fitBounds( box, immediately );
|
||||||
center.x = (
|
|
||||||
this.contentAspectX + ( center.x % this.contentAspectX )
|
|
||||||
) % this.contentAspectX;
|
|
||||||
this.centerSpringX.resetTo( center.x );
|
|
||||||
this.centerSpringX.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( this.wrapVertical ) {
|
|
||||||
center.y = ( 1 + ( center.y % 1 ) ) % 1;
|
|
||||||
this.centerSpringY.resetTo( center.y );
|
|
||||||
this.centerSpringY.update();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.fitBounds( this.fitWidthBounds, immediately );
|
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -736,7 +793,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
/**
|
/**
|
||||||
* Raised when rotation has been changed.
|
* Raised when rotation has been changed.
|
||||||
*
|
*
|
||||||
* @event update-viewport
|
* @event rotate
|
||||||
* @memberof OpenSeadragon.Viewer
|
* @memberof OpenSeadragon.Viewer
|
||||||
* @type {object}
|
* @type {object}
|
||||||
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
|
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
|
||||||
@ -769,12 +826,16 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
newBounds = oldBounds,
|
newBounds = oldBounds,
|
||||||
widthDeltaFactor;
|
widthDeltaFactor;
|
||||||
|
|
||||||
this.containerSize = new $.Point(
|
this.containerSize.x = newContainerSize.x;
|
||||||
newContainerSize.x,
|
this.containerSize.y = newContainerSize.y;
|
||||||
newContainerSize.y
|
|
||||||
|
this._containerInnerSize = new $.Point(
|
||||||
|
Math.max(1, newContainerSize.x - (this._margins.left + this._margins.right)),
|
||||||
|
Math.max(1, newContainerSize.y - (this._margins.top + this._margins.bottom))
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( maintain ) {
|
if ( maintain ) {
|
||||||
|
// TODO: widthDeltaFactor will always be 1; probably not what's intended
|
||||||
widthDeltaFactor = newContainerSize.x / this.containerSize.x;
|
widthDeltaFactor = newContainerSize.x / this.containerSize.x;
|
||||||
newBounds.width = oldBounds.width * widthDeltaFactor;
|
newBounds.width = oldBounds.width * widthDeltaFactor;
|
||||||
newBounds.height = newBounds.width / this.getAspectRatio();
|
newBounds.height = newBounds.width / this.getAspectRatio();
|
||||||
@ -805,10 +866,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
update: function() {
|
update: function() {
|
||||||
var oldCenterX = this.centerSpringX.current.value,
|
var oldZoomPixel,
|
||||||
oldCenterY = this.centerSpringY.current.value,
|
|
||||||
oldZoom = this.zoomSpring.current.value,
|
|
||||||
oldZoomPixel,
|
|
||||||
newZoomPixel,
|
newZoomPixel,
|
||||||
deltaZoomPixels,
|
deltaZoomPixels,
|
||||||
deltaZoomPoints;
|
deltaZoomPoints;
|
||||||
@ -819,7 +877,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
|
|
||||||
this.zoomSpring.update();
|
this.zoomSpring.update();
|
||||||
|
|
||||||
if (this.zoomPoint && this.zoomSpring.current.value != oldZoom) {
|
if (this.zoomPoint && this.zoomSpring.current.value != this._oldZoom) {
|
||||||
newZoomPixel = this.pixelFromPoint( this.zoomPoint, true );
|
newZoomPixel = this.pixelFromPoint( this.zoomPoint, true );
|
||||||
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );
|
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );
|
||||||
deltaZoomPoints = this.deltaPointsFromPixels( deltaZoomPixels, true );
|
deltaZoomPoints = this.deltaPointsFromPixels( deltaZoomPixels, true );
|
||||||
@ -833,9 +891,15 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
this.centerSpringX.update();
|
this.centerSpringX.update();
|
||||||
this.centerSpringY.update();
|
this.centerSpringY.update();
|
||||||
|
|
||||||
return this.centerSpringX.current.value != oldCenterX ||
|
var changed = this.centerSpringX.current.value != this._oldCenterX ||
|
||||||
this.centerSpringY.current.value != oldCenterY ||
|
this.centerSpringY.current.value != this._oldCenterY ||
|
||||||
this.zoomSpring.current.value != oldZoom;
|
this.zoomSpring.current.value != this._oldZoom;
|
||||||
|
|
||||||
|
this._oldCenterX = this.centerSpringX.current.value;
|
||||||
|
this._oldCenterY = this.centerSpringY.current.value;
|
||||||
|
this._oldZoom = this.zoomSpring.current.value;
|
||||||
|
|
||||||
|
return changed;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
@ -846,7 +910,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
*/
|
*/
|
||||||
deltaPixelsFromPoints: function( deltaPoints, current ) {
|
deltaPixelsFromPoints: function( deltaPoints, current ) {
|
||||||
return deltaPoints.times(
|
return deltaPoints.times(
|
||||||
this.containerSize.x * this.getZoom( current )
|
this._containerInnerSize.x * this.getZoom( current )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -857,7 +921,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
*/
|
*/
|
||||||
deltaPointsFromPixels: function( deltaPixels, current ) {
|
deltaPointsFromPixels: function( deltaPixels, current ) {
|
||||||
return deltaPixels.divide(
|
return deltaPixels.divide(
|
||||||
this.containerSize.x * this.getZoom( current )
|
this._containerInnerSize.x * this.getZoom( current )
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -867,11 +931,17 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
* @param {Boolean} current - Pass true for the current location; defaults to false (target location).
|
||||||
*/
|
*/
|
||||||
pixelFromPoint: function( point, current ) {
|
pixelFromPoint: function( point, current ) {
|
||||||
var bounds = this.getBounds( current );
|
return this._pixelFromPoint(point, this.getBounds( current ));
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_pixelFromPoint: function( point, bounds ) {
|
||||||
return point.minus(
|
return point.minus(
|
||||||
bounds.getTopLeft()
|
bounds.getTopLeft()
|
||||||
).times(
|
).times(
|
||||||
this.containerSize.x / bounds.width
|
this._containerInnerSize.x / bounds.width
|
||||||
|
).plus(
|
||||||
|
new $.Point(this._margins.left, this._margins.top)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -882,17 +952,27 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
*/
|
*/
|
||||||
pointFromPixel: function( pixel, current ) {
|
pointFromPixel: function( pixel, current ) {
|
||||||
var bounds = this.getBounds( current );
|
var bounds = this.getBounds( current );
|
||||||
return pixel.divide(
|
return pixel.minus(
|
||||||
this.containerSize.x / bounds.width
|
new $.Point(this._margins.left, this._margins.top)
|
||||||
|
).divide(
|
||||||
|
this._containerInnerSize.x / bounds.width
|
||||||
).plus(
|
).plus(
|
||||||
bounds.getTopLeft()
|
bounds.getTopLeft()
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_viewportToImageDelta: function( viewerX, viewerY ) {
|
||||||
|
var scale = this.homeBounds.width;
|
||||||
|
return new $.Point(viewerX * (this.contentSize.x / scale),
|
||||||
|
viewerY * ((this.contentSize.y * this.contentAspectX) / scale));
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates from OpenSeadragon viewer coordinate system to image coordinate system.
|
* Translates from OpenSeadragon viewer coordinate system to image coordinate system.
|
||||||
* This method can be called either by passing X,Y coordinates or an
|
* This method can be called either by passing X,Y coordinates or an
|
||||||
* OpenSeadragon.Point
|
* OpenSeadragon.Point
|
||||||
|
* Note: not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.
|
||||||
* @function
|
* @function
|
||||||
* @param {OpenSeadragon.Point} viewerX the point in viewport coordinate system.
|
* @param {OpenSeadragon.Point} viewerX the point in viewport coordinate system.
|
||||||
* @param {Number} viewerX X coordinate in viewport coordinate system.
|
* @param {Number} viewerX X coordinate in viewport coordinate system.
|
||||||
@ -904,13 +984,26 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
//they passed a point instead of individual components
|
//they passed a point instead of individual components
|
||||||
return this.viewportToImageCoordinates( viewerX.x, viewerX.y );
|
return this.viewportToImageCoordinates( viewerX.x, viewerX.y );
|
||||||
}
|
}
|
||||||
return new $.Point( viewerX * this.contentSize.x, viewerY * this.contentSize.y * this.contentAspectX );
|
|
||||||
|
if (this.viewer && this.viewer.world.getItemCount() > 1) {
|
||||||
|
$.console.error('[Viewport.viewportToImageCoordinates] is not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._viewportToImageDelta(viewerX - this.homeBounds.x, viewerY - this.homeBounds.y);
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_imageToViewportDelta: function( imageX, imageY ) {
|
||||||
|
var scale = this.homeBounds.width;
|
||||||
|
return new $.Point((imageX / this.contentSize.x) * scale,
|
||||||
|
(imageY / this.contentSize.y / this.contentAspectX) * scale);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Translates from image coordinate system to OpenSeadragon viewer coordinate system
|
* Translates from image coordinate system to OpenSeadragon viewer coordinate system
|
||||||
* This method can be called either by passing X,Y coordinates or an
|
* This method can be called either by passing X,Y coordinates or an
|
||||||
* OpenSeadragon.Point
|
* OpenSeadragon.Point
|
||||||
|
* Note: not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.
|
||||||
* @function
|
* @function
|
||||||
* @param {OpenSeadragon.Point} imageX the point in image coordinate system.
|
* @param {OpenSeadragon.Point} imageX the point in image coordinate system.
|
||||||
* @param {Number} imageX X coordinate in image coordinate system.
|
* @param {Number} imageX X coordinate in image coordinate system.
|
||||||
@ -922,7 +1015,15 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
//they passed a point instead of individual components
|
//they passed a point instead of individual components
|
||||||
return this.imageToViewportCoordinates( imageX.x, imageX.y );
|
return this.imageToViewportCoordinates( imageX.x, imageX.y );
|
||||||
}
|
}
|
||||||
return new $.Point( imageX / this.contentSize.x, imageY / this.contentSize.y / this.contentAspectX );
|
|
||||||
|
if (this.viewer && this.viewer.world.getItemCount() > 1) {
|
||||||
|
$.console.error('[Viewport.imageToViewportCoordinates] is not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var point = this._imageToViewportDelta(imageX, imageY);
|
||||||
|
point.x += this.homeBounds.x;
|
||||||
|
point.y += this.homeBounds.y;
|
||||||
|
return point;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -930,6 +1031,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* pixel coordinates to OpenSeadragon viewport rectangle coordinates.
|
* pixel coordinates to OpenSeadragon viewport rectangle coordinates.
|
||||||
* This method can be called either by passing X,Y,width,height or an
|
* This method can be called either by passing X,Y,width,height or an
|
||||||
* OpenSeadragon.Rect
|
* OpenSeadragon.Rect
|
||||||
|
* Note: not accurate with multi-image; use TiledImage.imageToViewportRectangle instead.
|
||||||
* @function
|
* @function
|
||||||
* @param {OpenSeadragon.Rect} imageX the rectangle in image coordinate system.
|
* @param {OpenSeadragon.Rect} imageX the rectangle in image coordinate system.
|
||||||
* @param {Number} imageX the X coordinate of the top left corner of the rectangle
|
* @param {Number} imageX the X coordinate of the top left corner of the rectangle
|
||||||
@ -950,10 +1052,11 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
rect.x, rect.y, rect.width, rect.height
|
rect.x, rect.y, rect.width, rect.height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
coordA = this.imageToViewportCoordinates(
|
coordA = this.imageToViewportCoordinates(
|
||||||
imageX, imageY
|
imageX, imageY
|
||||||
);
|
);
|
||||||
coordB = this.imageToViewportCoordinates(
|
coordB = this._imageToViewportDelta(
|
||||||
pixelWidth, pixelHeight
|
pixelWidth, pixelHeight
|
||||||
);
|
);
|
||||||
return new $.Rect(
|
return new $.Rect(
|
||||||
@ -969,6 +1072,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* the viewport in point coordinates to image rectangle coordinates.
|
* the viewport in point coordinates to image rectangle coordinates.
|
||||||
* This method can be called either by passing X,Y,width,height or an
|
* This method can be called either by passing X,Y,width,height or an
|
||||||
* OpenSeadragon.Rect
|
* OpenSeadragon.Rect
|
||||||
|
* Note: not accurate with multi-image; use TiledImage.viewportToImageRectangle instead.
|
||||||
* @function
|
* @function
|
||||||
* @param {OpenSeadragon.Rect} viewerX the rectangle in viewport coordinate system.
|
* @param {OpenSeadragon.Rect} viewerX the rectangle in viewport coordinate system.
|
||||||
* @param {Number} viewerX the X coordinate of the top left corner of the rectangle
|
* @param {Number} viewerX the X coordinate of the top left corner of the rectangle
|
||||||
@ -989,8 +1093,9 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
rect.x, rect.y, rect.width, rect.height
|
rect.x, rect.y, rect.width, rect.height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
coordA = this.viewportToImageCoordinates( viewerX, viewerY );
|
coordA = this.viewportToImageCoordinates( viewerX, viewerY );
|
||||||
coordB = this.viewportToImageCoordinates( pointWidth, pointHeight );
|
coordB = this._viewportToImageDelta(pointWidth, pointHeight);
|
||||||
return new $.Rect(
|
return new $.Rect(
|
||||||
coordA.x,
|
coordA.x,
|
||||||
coordA.y,
|
coordA.y,
|
||||||
@ -1002,6 +1107,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
/**
|
/**
|
||||||
* Convert pixel coordinates relative to the viewer element to image
|
* Convert pixel coordinates relative to the viewer element to image
|
||||||
* coordinates.
|
* coordinates.
|
||||||
|
* Note: not accurate with multi-image.
|
||||||
* @param {OpenSeadragon.Point} pixel
|
* @param {OpenSeadragon.Point} pixel
|
||||||
* @returns {OpenSeadragon.Point}
|
* @returns {OpenSeadragon.Point}
|
||||||
*/
|
*/
|
||||||
@ -1013,6 +1119,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
/**
|
/**
|
||||||
* Convert pixel coordinates relative to the image to
|
* Convert pixel coordinates relative to the image to
|
||||||
* viewer element coordinates.
|
* viewer element coordinates.
|
||||||
|
* Note: not accurate with multi-image.
|
||||||
* @param {OpenSeadragon.Point} pixel
|
* @param {OpenSeadragon.Point} pixel
|
||||||
* @returns {OpenSeadragon.Point}
|
* @returns {OpenSeadragon.Point}
|
||||||
*/
|
*/
|
||||||
@ -1023,6 +1130,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert pixel coordinates relative to the window to image coordinates.
|
* Convert pixel coordinates relative to the window to image coordinates.
|
||||||
|
* Note: not accurate with multi-image.
|
||||||
* @param {OpenSeadragon.Point} pixel
|
* @param {OpenSeadragon.Point} pixel
|
||||||
* @returns {OpenSeadragon.Point}
|
* @returns {OpenSeadragon.Point}
|
||||||
*/
|
*/
|
||||||
@ -1034,6 +1142,7 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert image coordinates to pixel coordinates relative to the window.
|
* Convert image coordinates to pixel coordinates relative to the window.
|
||||||
|
* Note: not accurate with multi-image.
|
||||||
* @param {OpenSeadragon.Point} pixel
|
* @param {OpenSeadragon.Point} pixel
|
||||||
* @returns {OpenSeadragon.Point}
|
* @returns {OpenSeadragon.Point}
|
||||||
*/
|
*/
|
||||||
@ -1091,15 +1200,21 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* 1 means original image size, 0.5 half size...
|
* 1 means original image size, 0.5 half size...
|
||||||
* Viewport zoom: ratio of the displayed image's width to viewport's width.
|
* Viewport zoom: ratio of the displayed image's width to viewport's width.
|
||||||
* 1 means identical width, 2 means image's width is twice the viewport's width...
|
* 1 means identical width, 2 means image's width is twice the viewport's width...
|
||||||
|
* Note: not accurate with multi-image.
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} viewportZoom The viewport zoom
|
* @param {Number} viewportZoom The viewport zoom
|
||||||
* target zoom.
|
* target zoom.
|
||||||
* @returns {Number} imageZoom The image zoom
|
* @returns {Number} imageZoom The image zoom
|
||||||
*/
|
*/
|
||||||
viewportToImageZoom: function( viewportZoom ) {
|
viewportToImageZoom: function( viewportZoom ) {
|
||||||
var imageWidth = this.viewer.source.dimensions.x;
|
if (this.viewer && this.viewer.world.getItemCount() > 1) {
|
||||||
var containerWidth = this.getContainerSize().x;
|
$.console.error('[Viewport.viewportToImageZoom] is not accurate with multi-image.');
|
||||||
var viewportToImageZoomRatio = containerWidth / imageWidth;
|
}
|
||||||
|
|
||||||
|
var imageWidth = this.contentSize.x;
|
||||||
|
var containerWidth = this._containerInnerSize.x;
|
||||||
|
var scale = this.homeBounds.width;
|
||||||
|
var viewportToImageZoomRatio = (containerWidth / imageWidth) * scale;
|
||||||
return viewportZoom * viewportToImageZoomRatio;
|
return viewportZoom * viewportToImageZoomRatio;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1109,15 +1224,21 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
|
|||||||
* 1 means original image size, 0.5 half size...
|
* 1 means original image size, 0.5 half size...
|
||||||
* Viewport zoom: ratio of the displayed image's width to viewport's width.
|
* Viewport zoom: ratio of the displayed image's width to viewport's width.
|
||||||
* 1 means identical width, 2 means image's width is twice the viewport's width...
|
* 1 means identical width, 2 means image's width is twice the viewport's width...
|
||||||
|
* Note: not accurate with multi-image.
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} imageZoom The image zoom
|
* @param {Number} imageZoom The image zoom
|
||||||
* target zoom.
|
* target zoom.
|
||||||
* @returns {Number} viewportZoom The viewport zoom
|
* @returns {Number} viewportZoom The viewport zoom
|
||||||
*/
|
*/
|
||||||
imageToViewportZoom: function( imageZoom ) {
|
imageToViewportZoom: function( imageZoom ) {
|
||||||
var imageWidth = this.viewer.source.dimensions.x;
|
if (this.viewer && this.viewer.world.getItemCount() > 1) {
|
||||||
var containerWidth = this.getContainerSize().x;
|
$.console.error('[Viewport.imageToViewportZoom] is not accurate with multi-image.');
|
||||||
var viewportToImageZoomRatio = imageWidth / containerWidth;
|
}
|
||||||
|
|
||||||
|
var imageWidth = this.contentSize.x;
|
||||||
|
var containerWidth = this._containerInnerSize.x;
|
||||||
|
var scale = this.homeBounds.width;
|
||||||
|
var viewportToImageZoomRatio = (imageWidth / containerWidth) / scale;
|
||||||
return imageZoom * viewportToImageZoomRatio;
|
return imageZoom * viewportToImageZoomRatio;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
393
src/world.js
Normal file
393
src/world.js
Normal file
@ -0,0 +1,393 @@
|
|||||||
|
/*
|
||||||
|
* OpenSeadragon - World
|
||||||
|
*
|
||||||
|
* Copyright (C) 2009 CodePlex Foundation
|
||||||
|
* Copyright (C) 2010-2013 OpenSeadragon contributors
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are
|
||||||
|
* met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of CodePlex Foundation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from
|
||||||
|
* this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||||
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function( $ ){
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class World
|
||||||
|
* @memberof OpenSeadragon
|
||||||
|
* @extends OpenSeadragon.EventSource
|
||||||
|
* @classdesc Keeps track of all of the tiled images in the scene.
|
||||||
|
* @param {Object} options - World options.
|
||||||
|
* @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this World.
|
||||||
|
**/
|
||||||
|
$.World = function( options ) {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
$.console.assert( options.viewer, "[World] options.viewer is required" );
|
||||||
|
|
||||||
|
$.EventSource.call( this );
|
||||||
|
|
||||||
|
this.viewer = options.viewer;
|
||||||
|
this._items = [];
|
||||||
|
this._needsDraw = false;
|
||||||
|
this._delegatedFigureSizes = function(event) {
|
||||||
|
_this._figureSizes();
|
||||||
|
};
|
||||||
|
|
||||||
|
this._figureSizes();
|
||||||
|
};
|
||||||
|
|
||||||
|
$.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.World.prototype */{
|
||||||
|
/**
|
||||||
|
* Add the specified item.
|
||||||
|
* @param {OpenSeadragon.TiledImage} item - The item to add.
|
||||||
|
* @param {Number} [options.index] - Index for the item. If not specified, goes at the top.
|
||||||
|
* @fires OpenSeadragon.World.event:add-item
|
||||||
|
* @fires OpenSeadragon.World.event:metrics-change
|
||||||
|
*/
|
||||||
|
addItem: function( item, options ) {
|
||||||
|
$.console.assert(item, "[World.addItem] item is required");
|
||||||
|
$.console.assert(item instanceof $.TiledImage, "[World.addItem] only TiledImages supported at this time");
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
if (options.index !== undefined) {
|
||||||
|
var index = Math.max(0, Math.min(this._items.length, options.index));
|
||||||
|
this._items.splice(index, 0, item);
|
||||||
|
} else {
|
||||||
|
this._items.push( item );
|
||||||
|
}
|
||||||
|
|
||||||
|
this._figureSizes();
|
||||||
|
this._needsDraw = true;
|
||||||
|
|
||||||
|
item.addHandler('bounds-change', this._delegatedFigureSizes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when an item is added to the World.
|
||||||
|
* @event add-item
|
||||||
|
* @memberOf OpenSeadragon.World
|
||||||
|
* @type {object}
|
||||||
|
* @property {OpenSeadragon.Viewer} eventSource - A reference to the World which raised the event.
|
||||||
|
* @property {OpenSeadragon.TiledImage} item - The item that has been added.
|
||||||
|
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||||
|
*/
|
||||||
|
this.raiseEvent( 'add-item', {
|
||||||
|
item: item
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the item at the specified index.
|
||||||
|
* @param {Number} index - The item's index.
|
||||||
|
* @returns {OpenSeadragon.TiledImage} The item at the specified index.
|
||||||
|
*/
|
||||||
|
getItemAt: function( index ) {
|
||||||
|
$.console.assert(index !== undefined, "[World.getItemAt] index is required");
|
||||||
|
return this._items[ index ];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the index of the given item or -1 if not present.
|
||||||
|
* @param {OpenSeadragon.TiledImage} item - The item.
|
||||||
|
* @returns {Number} The index of the item or -1 if not present.
|
||||||
|
*/
|
||||||
|
getIndexOfItem: function( item ) {
|
||||||
|
$.console.assert(item, "[World.getIndexOfItem] item is required");
|
||||||
|
return $.indexOf( this._items, item );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Number} The number of items used.
|
||||||
|
*/
|
||||||
|
getItemCount: function() {
|
||||||
|
return this._items.length;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the index of a item so that it appears over or under others.
|
||||||
|
* @param {OpenSeadragon.TiledImage} item - The item to move.
|
||||||
|
* @param {Number} index - The new index.
|
||||||
|
* @fires OpenSeadragon.World.event:item-index-change
|
||||||
|
*/
|
||||||
|
setItemIndex: function( item, index ) {
|
||||||
|
$.console.assert(item, "[World.setItemIndex] item is required");
|
||||||
|
$.console.assert(index !== undefined, "[World.setItemIndex] index is required");
|
||||||
|
|
||||||
|
var oldIndex = this.getIndexOfItem( item );
|
||||||
|
|
||||||
|
if ( index >= this._items.length ) {
|
||||||
|
throw new Error( "Index bigger than number of layers." );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( index === oldIndex || oldIndex === -1 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._items.splice( oldIndex, 1 );
|
||||||
|
this._items.splice( index, 0, item );
|
||||||
|
this._needsDraw = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when the order of the indexes has been changed.
|
||||||
|
* @event item-index-change
|
||||||
|
* @memberOf OpenSeadragon.World
|
||||||
|
* @type {object}
|
||||||
|
* @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.
|
||||||
|
* @property {OpenSeadragon.TiledImage} item - The item whose index has
|
||||||
|
* been changed
|
||||||
|
* @property {Number} previousIndex - The previous index of the item
|
||||||
|
* @property {Number} newIndex - The new index of the item
|
||||||
|
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||||
|
*/
|
||||||
|
this.raiseEvent( 'item-index-change', {
|
||||||
|
item: item,
|
||||||
|
previousIndex: oldIndex,
|
||||||
|
newIndex: index
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove an item.
|
||||||
|
* @param {OpenSeadragon.TiledImage} item - The item to remove.
|
||||||
|
* @fires OpenSeadragon.World.event:remove-item
|
||||||
|
* @fires OpenSeadragon.World.event:metrics-change
|
||||||
|
*/
|
||||||
|
removeItem: function( item ) {
|
||||||
|
$.console.assert(item, "[World.removeItem] item is required");
|
||||||
|
|
||||||
|
var index = $.indexOf(this._items, item );
|
||||||
|
if ( index === -1 ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.removeHandler('bounds-change', this._delegatedFigureSizes);
|
||||||
|
this._items.splice( index, 1 );
|
||||||
|
this._figureSizes();
|
||||||
|
this._needsDraw = true;
|
||||||
|
this._raiseRemoveItem(item);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove all items.
|
||||||
|
* @fires OpenSeadragon.World.event:remove-item
|
||||||
|
* @fires OpenSeadragon.World.event:metrics-change
|
||||||
|
*/
|
||||||
|
removeAll: function() {
|
||||||
|
var item;
|
||||||
|
for (var i = 0; i < this._items.length; i++) {
|
||||||
|
item = this._items[i];
|
||||||
|
item.removeHandler('bounds-change', this._delegatedFigureSizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
var removedItems = this._items;
|
||||||
|
this._items = [];
|
||||||
|
this._figureSizes();
|
||||||
|
this._needsDraw = true;
|
||||||
|
|
||||||
|
for (i = 0; i < removedItems.length; i++) {
|
||||||
|
item = removedItems[i];
|
||||||
|
this._raiseRemoveItem(item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all tiles and triggers updates for all items.
|
||||||
|
*/
|
||||||
|
resetItems: function() {
|
||||||
|
for ( var i = 0; i < this._items.length; i++ ) {
|
||||||
|
this._items[i].reset();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates (i.e. animates bounds of) all items.
|
||||||
|
*/
|
||||||
|
update: function() {
|
||||||
|
var animated = false;
|
||||||
|
for ( var i = 0; i < this._items.length; i++ ) {
|
||||||
|
animated = this._items[i].update() || animated;
|
||||||
|
}
|
||||||
|
|
||||||
|
return animated;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draws all items.
|
||||||
|
*/
|
||||||
|
draw: function() {
|
||||||
|
for ( var i = 0; i < this._items.length; i++ ) {
|
||||||
|
this._items[i].draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._needsDraw = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Boolean} true if any items need updating.
|
||||||
|
*/
|
||||||
|
needsDraw: function() {
|
||||||
|
for ( var i = 0; i < this._items.length; i++ ) {
|
||||||
|
if ( this._items[i].needsDraw() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this._needsDraw;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {OpenSeadragon.Rect} The smallest rectangle that encloses all items, in viewport coordinates.
|
||||||
|
*/
|
||||||
|
getHomeBounds: function() {
|
||||||
|
return this._homeBounds.clone();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To facilitate zoom constraints, we keep track of the pixel density of the
|
||||||
|
* densest item in the World (i.e. the item whose content size to viewport size
|
||||||
|
* ratio is the highest) and save it as this "content factor".
|
||||||
|
* @returns {Number} the number of content units per viewport unit.
|
||||||
|
*/
|
||||||
|
getContentFactor: function() {
|
||||||
|
return this._contentFactor;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arranges all of the TiledImages with the specified settings.
|
||||||
|
* @param {Object} options - Specifies how to arrange.
|
||||||
|
* @param {Boolean} [options.immediately=false] - Whether to animate to the new arrangement.
|
||||||
|
* @param {String} [options.layout] - See collectionLayout in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.rows] - See collectionRows in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.tileSize] - See collectionTileSize in {@link OpenSeadragon.Options}.
|
||||||
|
* @param {Number} [options.tileMargin] - See collectionTileMargin in {@link OpenSeadragon.Options}.
|
||||||
|
* @fires OpenSeadragon.World.event:metrics-change
|
||||||
|
*/
|
||||||
|
arrange: function(options) {
|
||||||
|
options = options || {};
|
||||||
|
var immediately = options.immediately || false;
|
||||||
|
var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout;
|
||||||
|
var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows;
|
||||||
|
var tileSize = options.tileSize || $.DEFAULT_SETTINGS.collectionTileSize;
|
||||||
|
var tileMargin = options.tileMargin || $.DEFAULT_SETTINGS.collectionTileMargin;
|
||||||
|
var increment = tileSize + tileMargin;
|
||||||
|
var wrap = Math.ceil(this._items.length / rows);
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
var item, box, width, height, position;
|
||||||
|
for (var i = 0; i < this._items.length; i++) {
|
||||||
|
if (i && (i % wrap) === 0) {
|
||||||
|
if (layout === 'horizontal') {
|
||||||
|
y += increment;
|
||||||
|
x = 0;
|
||||||
|
} else {
|
||||||
|
x += increment;
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item = this._items[i];
|
||||||
|
box = item.getBounds();
|
||||||
|
if (box.width > box.height) {
|
||||||
|
width = tileSize;
|
||||||
|
} else {
|
||||||
|
width = tileSize * (box.width / box.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
height = width * (box.height / box.width);
|
||||||
|
position = new $.Point(x + ((tileSize - width) / 2),
|
||||||
|
y + ((tileSize - height) / 2));
|
||||||
|
|
||||||
|
item.setPosition(position, immediately);
|
||||||
|
item.setWidth(width, immediately);
|
||||||
|
|
||||||
|
if (layout === 'horizontal') {
|
||||||
|
x += increment;
|
||||||
|
} else {
|
||||||
|
y += increment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_figureSizes: function() {
|
||||||
|
var oldHomeBounds = this._homeBounds ? this._homeBounds.clone() : null;
|
||||||
|
var oldContentSize = this._contentSize ? this._contentSize.clone() : null;
|
||||||
|
var oldContentFactor = this._contentFactor || 0;
|
||||||
|
|
||||||
|
if ( !this._items.length ) {
|
||||||
|
this._homeBounds = new $.Rect(0, 0, 1, 1);
|
||||||
|
this._contentSize = new $.Point(1, 1);
|
||||||
|
this._contentFactor = 1;
|
||||||
|
} else {
|
||||||
|
var bounds = this._items[0].getBounds();
|
||||||
|
this._contentFactor = this._items[0].getContentSize().x / bounds.width;
|
||||||
|
var left = bounds.x;
|
||||||
|
var top = bounds.y;
|
||||||
|
var right = bounds.x + bounds.width;
|
||||||
|
var bottom = bounds.y + bounds.height;
|
||||||
|
var box;
|
||||||
|
for ( var i = 1; i < this._items.length; i++ ) {
|
||||||
|
box = this._items[i].getBounds();
|
||||||
|
this._contentFactor = Math.max(this._contentFactor, this._items[i].getContentSize().x / box.width);
|
||||||
|
left = Math.min( left, box.x );
|
||||||
|
top = Math.min( top, box.y );
|
||||||
|
right = Math.max( right, box.x + box.width );
|
||||||
|
bottom = Math.max( bottom, box.y + box.height );
|
||||||
|
}
|
||||||
|
|
||||||
|
this._homeBounds = new $.Rect( left, top, right - left, bottom - top );
|
||||||
|
this._contentSize = new $.Point(this._homeBounds.width * this._contentFactor,
|
||||||
|
this._homeBounds.height * this._contentFactor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._contentFactor !== oldContentFactor || !this._homeBounds.equals(oldHomeBounds) ||
|
||||||
|
!this._contentSize.equals(oldContentSize)) {
|
||||||
|
/**
|
||||||
|
* Raised when the home bounds or content factor change.
|
||||||
|
* @event metrics-change
|
||||||
|
* @memberOf OpenSeadragon.World
|
||||||
|
* @type {object}
|
||||||
|
* @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.
|
||||||
|
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||||
|
*/
|
||||||
|
this.raiseEvent('metrics-change', {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// private
|
||||||
|
_raiseRemoveItem: function(item) {
|
||||||
|
/**
|
||||||
|
* Raised when an item is removed.
|
||||||
|
* @event remove-item
|
||||||
|
* @memberOf OpenSeadragon.World
|
||||||
|
* @type {object}
|
||||||
|
* @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event.
|
||||||
|
* @property {OpenSeadragon.TiledImage} item - The item's underlying item.
|
||||||
|
* @property {?Object} userData - Arbitrary subscriber-defined object.
|
||||||
|
*/
|
||||||
|
this.raiseEvent( 'remove-item', { item: item } );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}( OpenSeadragon ));
|
79
test/coverage.html
Normal file
79
test/coverage.html
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>OpenSeadragon QUnit</title>
|
||||||
|
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css">
|
||||||
|
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
|
||||||
|
<link rel="stylesheet" href="/test/helpers/test.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="qunit"></div>
|
||||||
|
<div id="qunit-fixture"></div>
|
||||||
|
<script src="/node_modules/qunitjs/qunit/qunit.js"></script>
|
||||||
|
<script src="/test/lib/jquery-1.9.1.min.js"></script>
|
||||||
|
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
|
||||||
|
<script src="/test/lib/jquery.simulate.js"></script>
|
||||||
|
|
||||||
|
<!-- OpenSeadragon sources -->
|
||||||
|
<script src="/src/openseadragon.js"></script>
|
||||||
|
<script src="/src/fullscreen.js"></script>
|
||||||
|
<script src="/src/eventsource.js"></script>
|
||||||
|
<script src="/src/mousetracker.js"></script>
|
||||||
|
<script src="/src/control.js"></script>
|
||||||
|
<script src="/src/controldock.js"></script>
|
||||||
|
<script src="/src/viewer.js"></script>
|
||||||
|
<script src="/src/navigator.js"></script>
|
||||||
|
<script src="/src/strings.js"></script>
|
||||||
|
<script src="/src/point.js"></script>
|
||||||
|
<script src="/src/tilesource.js"></script>
|
||||||
|
<script src="/src/dzitilesource.js"></script>
|
||||||
|
<script src="/src/iiiftilesource.js"></script>
|
||||||
|
<script src="/src/osmtilesource.js"></script>
|
||||||
|
<script src="/src/tmstilesource.js"></script>
|
||||||
|
<script src="/src/legacytilesource.js"></script>
|
||||||
|
<script src="/src/tilesourcecollection.js"></script>
|
||||||
|
<script src="/src/button.js"></script>
|
||||||
|
<script src="/src/buttongroup.js"></script>
|
||||||
|
<script src="/src/rectangle.js"></script>
|
||||||
|
<script src="/src/referencestrip.js"></script>
|
||||||
|
<script src="/src/displayrectangle.js"></script>
|
||||||
|
<script src="/src/spring.js"></script>
|
||||||
|
<script src="/src/imageLoader.js"></script>
|
||||||
|
<script src="/src/tile.js"></script>
|
||||||
|
<script src="/src/overlay.js"></script>
|
||||||
|
<script src="/src/drawer.js"></script>
|
||||||
|
<script src="/src/viewport.js"></script>
|
||||||
|
<script src="/src/tiledimage.js"></script>
|
||||||
|
<script src="/src/tilecache.js"></script>
|
||||||
|
<script src="/src/world.js"></script>
|
||||||
|
|
||||||
|
<!-- Helpers -->
|
||||||
|
<script src="/test/helpers/legacy.mouse.shim.js"></script>
|
||||||
|
<script src="/test/helpers/test.js"></script>
|
||||||
|
|
||||||
|
<!-- Modules -->
|
||||||
|
<!-- Polyfill must be inserted first because it is testing functions
|
||||||
|
reassignments which could be done by other test. -->
|
||||||
|
<script src="/test/modules/polyfills.js"></script>
|
||||||
|
<script src="/test/modules/basic.js"></script>
|
||||||
|
<script src="/test/modules/strings.js"></script>
|
||||||
|
<script src="/test/modules/formats.js"></script>
|
||||||
|
<script src="/test/modules/utils.js"></script>
|
||||||
|
<script src="/test/modules/events.js"></script>
|
||||||
|
<script src="/test/modules/units.js"></script>
|
||||||
|
<script src="/test/modules/multi-image.js"></script>
|
||||||
|
<script src="/test/modules/overlays.js"></script>
|
||||||
|
<script src="/test/modules/controls.js"></script>
|
||||||
|
<script src="/test/modules/viewport.js"></script>
|
||||||
|
<script src="/test/modules/world.js"></script>
|
||||||
|
<script src="/test/modules/drawer.js"></script>
|
||||||
|
<script src="/test/modules/tiledimage.js"></script>
|
||||||
|
<script src="/test/modules/tilecache.js"></script>
|
||||||
|
<script src="/test/modules/referencestrip.js"></script>
|
||||||
|
<script src="/test/modules/tilesourcecollection.js"></script>
|
||||||
|
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||||
|
so we put them last. -->
|
||||||
|
<script src="/test/modules/navigator.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
31
test/demo/collections/index.html
Normal file
31
test/demo/collections/index.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OpenSeadragon Collections Demo</title>
|
||||||
|
<script type="text/javascript" src='../../../build/openseadragon/openseadragon.js'></script>
|
||||||
|
<script type="text/javascript" src='../../lib/jquery-1.9.1.min.js'></script>
|
||||||
|
<script type="text/javascript" src='main.js'></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
.openseadragon1 {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openseadragon1.small {
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openseadragon-overlay {
|
||||||
|
background-color: rgba(255, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="contentDiv" class="openseadragon1"></div>
|
||||||
|
</body>
|
||||||
|
</html>
|
381
test/demo/collections/main.js
Normal file
381
test/demo/collections/main.js
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
/* globals $, App */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
window.App = {
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var testInitialOpen = true;
|
||||||
|
var testOverlays = false;
|
||||||
|
var testMargins = false;
|
||||||
|
var testNavigator = false;
|
||||||
|
var margins;
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
// debugMode: true,
|
||||||
|
zoomPerScroll: 1.02,
|
||||||
|
showNavigator: testNavigator,
|
||||||
|
useCanvas: true,
|
||||||
|
// defaultZoomLevel: 2,
|
||||||
|
// homeFillsViewer: true,
|
||||||
|
// sequenceMode: true,
|
||||||
|
// showReferenceStrip: true,
|
||||||
|
// referenceStripScroll: 'vertical',
|
||||||
|
navPrevNextWrap: false,
|
||||||
|
preserveViewport: false,
|
||||||
|
// collectionMode: true,
|
||||||
|
// collectionRows: 1,
|
||||||
|
// collectionLayout: 'vertical',
|
||||||
|
// collectionTileSize: 10,
|
||||||
|
// collectionTileMargin: 10,
|
||||||
|
// wrapHorizontal: true,
|
||||||
|
// wrapVertical: true,
|
||||||
|
id: "contentDiv",
|
||||||
|
prefixUrl: "../../../build/openseadragon/images/"
|
||||||
|
};
|
||||||
|
|
||||||
|
var highsmith = {
|
||||||
|
Image: {
|
||||||
|
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
Url: "http://openseadragon.github.io/example-images/highsmith/highsmith_files/",
|
||||||
|
Format: "jpg",
|
||||||
|
Overlap: "2",
|
||||||
|
TileSize: "256",
|
||||||
|
Size: {
|
||||||
|
Height: "9221",
|
||||||
|
Width: "7026"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (testInitialOpen) {
|
||||||
|
config.tileSources = [
|
||||||
|
{
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
|
x: 4,
|
||||||
|
y: 2,
|
||||||
|
width: 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tileSource: "../../data/tall.dzi",
|
||||||
|
x: 1.5,
|
||||||
|
y: 0,
|
||||||
|
width: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tileSource: '../../data/wide.dzi',
|
||||||
|
opacity: 1,
|
||||||
|
x: 0,
|
||||||
|
y: 1.5,
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// config.tileSources = {
|
||||||
|
// tileSource: highsmith,
|
||||||
|
// width: 1
|
||||||
|
// };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testOverlays) {
|
||||||
|
config.overlays = [
|
||||||
|
{
|
||||||
|
id: "overlay1",
|
||||||
|
x: 2,
|
||||||
|
y: 0,
|
||||||
|
width: 0.25,
|
||||||
|
height: 0.25
|
||||||
|
},
|
||||||
|
{
|
||||||
|
px: 13,
|
||||||
|
py: 120,
|
||||||
|
width: 124,
|
||||||
|
height: 132,
|
||||||
|
id: "overlay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
px: 400,
|
||||||
|
py: 500,
|
||||||
|
width: 400,
|
||||||
|
height: 400,
|
||||||
|
id: "fixed-overlay",
|
||||||
|
placement: "TOP_LEFT"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testMargins) {
|
||||||
|
margins = {
|
||||||
|
top: 250,
|
||||||
|
left: 250,
|
||||||
|
right: 250,
|
||||||
|
bottom: 250
|
||||||
|
};
|
||||||
|
|
||||||
|
config.viewportMargins = margins;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.viewer = OpenSeadragon(config);
|
||||||
|
|
||||||
|
if (testInitialOpen) {
|
||||||
|
function openHandler() {
|
||||||
|
self.viewer.removeHandler('open', openHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.viewer.addHandler( "open", openHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testMargins) {
|
||||||
|
this.viewer.addHandler('animation', function() {
|
||||||
|
var box = new OpenSeadragon.Rect(margins.left, margins.top,
|
||||||
|
$('#contentDiv').width() - (margins.left + margins.right),
|
||||||
|
$('#contentDiv').height() - (margins.top + margins.bottom));
|
||||||
|
|
||||||
|
self.viewer.drawer.debugRect(box);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!testInitialOpen) {
|
||||||
|
this.basicTest();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
shrink: function(index) {
|
||||||
|
index = index || 0;
|
||||||
|
var image = this.viewer.world.getItemAt(index);
|
||||||
|
image.setWidth(image.getBounds().width * 0.3);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
move: function(index) {
|
||||||
|
index = index || 0;
|
||||||
|
var image = this.viewer.world.getItemAt(index);
|
||||||
|
var point = image.getBounds().getTopLeft();
|
||||||
|
point.x += image.getBounds().width * 0.3;
|
||||||
|
image.setPosition(point);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
add: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.viewer.addTiledImage({
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
|
width: 1,
|
||||||
|
success: function() {
|
||||||
|
self.viewer.viewport.goHome();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
toggle: function() {
|
||||||
|
var $el = $(this.viewer.element);
|
||||||
|
$el.toggleClass('small');
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
basicTest: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.viewer.addHandler('open', function() {
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
|
width: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
crossTest: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.viewer.addHandler( "open", function() {
|
||||||
|
var options = {
|
||||||
|
tileSource: '../../data/wide.dzi',
|
||||||
|
opacity: 1,
|
||||||
|
x: 0,
|
||||||
|
y: 1.5,
|
||||||
|
height: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
var addItemHandler = function( event ) {
|
||||||
|
if ( event.options === options ) {
|
||||||
|
self.viewer.world.removeHandler( "add-item", addItemHandler );
|
||||||
|
self.viewer.viewport.goHome();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.viewer.world.addHandler( "add-item", addItemHandler );
|
||||||
|
self.viewer.addTiledImage( options );
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/tall.dzi",
|
||||||
|
x: 1.5,
|
||||||
|
y: 0,
|
||||||
|
width: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
crossTest2: function() {
|
||||||
|
this.viewer.open([
|
||||||
|
{
|
||||||
|
tileSource: "../../data/tall.dzi",
|
||||||
|
x: 1.5,
|
||||||
|
y: 0,
|
||||||
|
width: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tileSource: '../../data/wide.dzi',
|
||||||
|
x: 0,
|
||||||
|
y: 1.5,
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
crossTest3: function() {
|
||||||
|
var self = this;
|
||||||
|
var expected = 2;
|
||||||
|
var loaded = 0;
|
||||||
|
|
||||||
|
this.viewer.world.addHandler('add-item', function() {
|
||||||
|
loaded++;
|
||||||
|
if (loaded === expected) {
|
||||||
|
// self.viewer.viewport.goHome();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.addTiledImage({
|
||||||
|
tileSource: "../../data/tall.dzi",
|
||||||
|
x: 1.5,
|
||||||
|
y: 0,
|
||||||
|
width: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.addTiledImage({
|
||||||
|
tileSource: '../../data/wide.dzi',
|
||||||
|
opacity: 1,
|
||||||
|
x: 0,
|
||||||
|
y: 1.5,
|
||||||
|
height: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
collectionTest: function() {
|
||||||
|
var tileSources = [];
|
||||||
|
var random;
|
||||||
|
for (var i = 0; i < 10; i++) {
|
||||||
|
random = Math.random();
|
||||||
|
if (random < 0.33) {
|
||||||
|
tileSources.push('../../data/testpattern.dzi');
|
||||||
|
} else if (random < 0.66) {
|
||||||
|
tileSources.push('../../data/tall.dzi');
|
||||||
|
} else {
|
||||||
|
tileSources.push('../../data/wide.dzi');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.viewer.open(tileSources);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
gridTest: function() {
|
||||||
|
var self = this;
|
||||||
|
var startX = -3;
|
||||||
|
var expected = 0;
|
||||||
|
var loaded = 0;
|
||||||
|
|
||||||
|
this.viewer.addHandler( "open", function() {
|
||||||
|
self.viewer.world.addHandler('add-item', function() {
|
||||||
|
loaded++;
|
||||||
|
if (loaded === expected) {
|
||||||
|
self.viewer.viewport.goHome(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var x, y;
|
||||||
|
for (y = 0; y < 6; y++) {
|
||||||
|
for (x = 0; x < 6; x++) {
|
||||||
|
if (!x && !y) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var options = {
|
||||||
|
tileSource: '../../data/testpattern.dzi',
|
||||||
|
x: startX + x,
|
||||||
|
y: y,
|
||||||
|
width: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
expected++;
|
||||||
|
self.viewer.addTiledImage( options );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
|
x: startX,
|
||||||
|
y: 0,
|
||||||
|
width: 1
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
bigTest: function() {
|
||||||
|
this.viewer.open({
|
||||||
|
tileSource: "../../data/testpattern.dzi",
|
||||||
|
x: -2,
|
||||||
|
y: -2,
|
||||||
|
width: 6
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
cjTest: function() {
|
||||||
|
var imageKey = "e-pluribus-unum";
|
||||||
|
var imageXML = '<?xml version="1.0" encoding="UTF-8"?><Image TileSize="254" Overlap="1" Format="png" xmlns="http://schemas.microsoft.com/deepzoom/2008"><Size Width="88560" Height="88560"/></Image>';
|
||||||
|
var $xml = $($.parseXML(imageXML));
|
||||||
|
var $image = $xml.find('Image');
|
||||||
|
var $size = $xml.find('Size');
|
||||||
|
|
||||||
|
var dzi = {
|
||||||
|
Image: {
|
||||||
|
xmlns: $image.attr('xmlns'),
|
||||||
|
Url: "http://chrisjordan.com/dzi/" + imageKey + '_files/',
|
||||||
|
Format: $image.attr('Format'),
|
||||||
|
Overlap: $image.attr('Overlap'),
|
||||||
|
TileSize: $image.attr('TileSize'),
|
||||||
|
Size: {
|
||||||
|
Height: $size.attr('Height'),
|
||||||
|
Width: $size.attr('Width')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.viewer.open({
|
||||||
|
tileSource: dzi,
|
||||||
|
width: 100
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
stanfordTest: function() {
|
||||||
|
var info = {"@context":"http://library.stanford.edu/iiif/image-api/1.1/context.json","@id":"http://ids.lib.harvard.edu/ids/iiif/48530377","width":6251,"height":109517,"scale_factors":[1,2,4,8,16,32],"tile_width":256,"tile_height":256,"formats":["jpg"],"qualities":["native"],"profile":"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1"};
|
||||||
|
|
||||||
|
this.viewer.open(info);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
App.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
135
test/demo/item-animation.html
Normal file
135
test/demo/item-animation.html
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OpenSeadragon Collections Demo</title>
|
||||||
|
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
|
||||||
|
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
.openseadragon1 {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
App = {
|
||||||
|
itemCount: 5,
|
||||||
|
positionRange: 100,
|
||||||
|
sizeRange: 30,
|
||||||
|
delay: 100,
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.index = 0;
|
||||||
|
this.paused = false;
|
||||||
|
|
||||||
|
var tileSource = {
|
||||||
|
Image: {
|
||||||
|
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
Url: "http://openseadragon.github.io/example-images/highsmith/highsmith_files/",
|
||||||
|
Format: "jpg",
|
||||||
|
Overlap: "2",
|
||||||
|
TileSize: "256",
|
||||||
|
Size: {
|
||||||
|
Height: "9221",
|
||||||
|
Width: "7026"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var tileSources = [];
|
||||||
|
for (var i = 0; i < this.itemCount; i++) {
|
||||||
|
tileSources.push(tileSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.viewer = OpenSeadragon({
|
||||||
|
id: "contentDiv",
|
||||||
|
prefixUrl: "../../build/openseadragon/images/",
|
||||||
|
tileSources: tileSources
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.addHandler('open', function() {
|
||||||
|
self.updateCount();
|
||||||
|
|
||||||
|
self.viewer.viewport.fitBounds(new OpenSeadragon.Rect(0, 0,
|
||||||
|
self.positionRange + self.sizeRange,
|
||||||
|
self.positionRange + self.sizeRange));
|
||||||
|
|
||||||
|
self.animate();
|
||||||
|
});
|
||||||
|
|
||||||
|
var $pause = $('.toggle-pause').click(function() {
|
||||||
|
self.paused = !self.paused;
|
||||||
|
$pause.text(self.paused ? 'Play' : 'Pause');
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.add').click(function() {
|
||||||
|
for (var i = 0; i < self.itemCount; i++) {
|
||||||
|
self.viewer.addTiledImage({
|
||||||
|
tileSource: tileSource,
|
||||||
|
x: Math.random() * self.positionRange,
|
||||||
|
y: Math.random() * self.positionRange,
|
||||||
|
width: Math.random() * self.sizeRange,
|
||||||
|
success: function() {
|
||||||
|
self.updateCount();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
animate: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (!this.paused) {
|
||||||
|
var item = this.viewer.world.getItemAt(this.index);
|
||||||
|
item.setPosition(new OpenSeadragon.Point(Math.random() * this.positionRange,
|
||||||
|
Math.random() * this.positionRange));
|
||||||
|
|
||||||
|
item.setWidth(Math.random() * this.sizeRange);
|
||||||
|
|
||||||
|
this.index = (this.index + 1) % this.viewer.world.getItemCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
self.animate();
|
||||||
|
}, this.delay);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
updateCount: function() {
|
||||||
|
$('.count').text(this.viewer.world.getItemCount());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
$(document).ready(function() {
|
||||||
|
App.init();
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="contentDiv" class="openseadragon1"></div>
|
||||||
|
<div class="controls">
|
||||||
|
<button class="toggle-pause">Pause</button>
|
||||||
|
<button class="add">Add More</button>
|
||||||
|
Image Count: <span class="count"></span>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
20
test/demo/m2/README.md
Normal file
20
test/demo/m2/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# M2 Demo
|
||||||
|
|
||||||
|
This is an advanced demo/testbed, for proposed improvements to the new version of the Mirador project:
|
||||||
|
|
||||||
|
https://github.com/IIIF/m2/
|
||||||
|
|
||||||
|
You can see a previous version of Mirador here:
|
||||||
|
|
||||||
|
http://showcase.iiif.io/viewer/mirador/
|
||||||
|
|
||||||
|
## To Do
|
||||||
|
|
||||||
|
* Choosing between multiple versions of a page
|
||||||
|
* Detail images overlaid on the page
|
||||||
|
* Cropped images
|
||||||
|
|
||||||
|
### Maybe
|
||||||
|
|
||||||
|
* Show/hide pages?
|
||||||
|
* Lazyloading tilesources?
|
78
test/demo/m2/index.html
Normal file
78
test/demo/m2/index.html
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Mirador POC</title>
|
||||||
|
<script type="text/javascript" src='../../../build/openseadragon/openseadragon.js'></script>
|
||||||
|
<script type="text/javascript" src='../../lib/jquery-1.9.1.min.js'></script>
|
||||||
|
<script src="//d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
||||||
|
<script src="js/main.js"></script>
|
||||||
|
<!-- <script src="js/harvard-tilesources.js"></script> -->
|
||||||
|
<script src="js/openseadragon-svg-overlay.js"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #eee;
|
||||||
|
overflow: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
height: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active {
|
||||||
|
background: #ddf;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.openseadragon1 {
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.viewer-position {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 30px;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-cover {
|
||||||
|
display: none;
|
||||||
|
overflow: scroll;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="header">
|
||||||
|
<button class="thumbs">Thumbnails</button>
|
||||||
|
<button class="scroll">Scroll</button>
|
||||||
|
<button class="book">Book</button>
|
||||||
|
<button class="page">Page</button>
|
||||||
|
<div class="nav">
|
||||||
|
<button class="previous">Previous</button>
|
||||||
|
<button class="next">Next</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="contentDiv" class="openseadragon1 viewer-position"></div>
|
||||||
|
<div class="scroll-cover viewer-position">
|
||||||
|
<div class="scroll-inner"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
1
test/demo/m2/js/.gitignore
vendored
Normal file
1
test/demo/m2/js/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
harvard-tilesources.js
|
670
test/demo/m2/js/main.js
Normal file
670
test/demo/m2/js/main.js
Normal file
@ -0,0 +1,670 @@
|
|||||||
|
/* globals $, App, d3 */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
// ----------
|
||||||
|
window.App = {
|
||||||
|
// ----------
|
||||||
|
init: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.maxImages = 500;
|
||||||
|
this.mode = 'none';
|
||||||
|
this.pageBuffer = 0.05;
|
||||||
|
this.bigBuffer = 0.2;
|
||||||
|
this.page = 0;
|
||||||
|
this.modeNames = [
|
||||||
|
'thumbs',
|
||||||
|
'scroll',
|
||||||
|
'book',
|
||||||
|
'page'
|
||||||
|
];
|
||||||
|
|
||||||
|
this.viewer = OpenSeadragon({
|
||||||
|
id: "contentDiv",
|
||||||
|
prefixUrl: "../../../build/openseadragon/images/",
|
||||||
|
autoResize: false,
|
||||||
|
showHomeControl: false,
|
||||||
|
tileSources: this.getTileSources()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.addHandler('open', function() {
|
||||||
|
self.$el = $(self.viewer.element);
|
||||||
|
self.setMode({
|
||||||
|
mode: 'thumbs',
|
||||||
|
immediately: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.addHandler('canvas-drag', function() {
|
||||||
|
if (self.mode === 'scroll') {
|
||||||
|
var result = self.hitTest(self.viewer.viewport.getCenter());
|
||||||
|
if (result) {
|
||||||
|
self.page = result.index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.addHandler('viewport-change', function(event) {
|
||||||
|
self.applyConstraints();
|
||||||
|
});
|
||||||
|
|
||||||
|
$.each(this.modeNames, function(i, v) {
|
||||||
|
$('.' + v).click(function() {
|
||||||
|
self.setMode({
|
||||||
|
mode: v
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.next').click(function() {
|
||||||
|
self.next();
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.previous').click(function() {
|
||||||
|
self.previous();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).keyup(function(event) {
|
||||||
|
if (self.mode === 'thumbs') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.which === 39) { // Right arrow
|
||||||
|
self.next();
|
||||||
|
} else if (event.which === 37) { // Left arrow
|
||||||
|
self.previous();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$scrollInner = $('.scroll-inner');
|
||||||
|
|
||||||
|
this.$scrollCover = $('.scroll-cover')
|
||||||
|
.scroll(function(event) {
|
||||||
|
var info = self.getScrollInfo();
|
||||||
|
if (!info || self.ignoreScroll) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos = new OpenSeadragon.Point(info.thumbBounds.getCenter().x,
|
||||||
|
info.thumbBounds.y + (info.viewportHeight / 2) +
|
||||||
|
(info.viewportMax * info.scrollFactor));
|
||||||
|
|
||||||
|
self.viewer.viewport.panTo(pos, true);
|
||||||
|
})
|
||||||
|
.mousemove(function(event) {
|
||||||
|
var pixel = new OpenSeadragon.Point(event.clientX, event.clientY);
|
||||||
|
var result = self.hitTest(self.viewer.viewport.pointFromPixel(pixel));
|
||||||
|
self.updateHover(result ? result.index : -1);
|
||||||
|
})
|
||||||
|
.click(function(event) {
|
||||||
|
var pixel = new OpenSeadragon.Point(event.clientX, event.clientY);
|
||||||
|
var result = self.hitTest(self.viewer.viewport.pointFromPixel(pixel));
|
||||||
|
if (result) {
|
||||||
|
self.setMode({
|
||||||
|
mode: 'page',
|
||||||
|
page: result.index
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var svgNode = this.viewer.svgOverlay();
|
||||||
|
|
||||||
|
this.highlight = d3.select(svgNode).append("rect")
|
||||||
|
.style('fill', 'none')
|
||||||
|
.style('stroke', '#08f')
|
||||||
|
.style('opacity', 0)
|
||||||
|
.style('stroke-width', 0.05)
|
||||||
|
.attr("pointer-events", "none");
|
||||||
|
|
||||||
|
this.hover = d3.select(svgNode).append("rect")
|
||||||
|
.style('fill', 'none')
|
||||||
|
.style('stroke', '#08f')
|
||||||
|
.style('opacity', 0)
|
||||||
|
.style('stroke-width', 0.05)
|
||||||
|
.attr("pointer-events", "none");
|
||||||
|
|
||||||
|
$(window).resize(function() {
|
||||||
|
var newSize = new OpenSeadragon.Point(self.$el.width(), self.$el.height());
|
||||||
|
self.viewer.viewport.resize(newSize, false);
|
||||||
|
self.setMode({
|
||||||
|
mode: self.mode,
|
||||||
|
immediately: true
|
||||||
|
});
|
||||||
|
|
||||||
|
self.viewer.forceRedraw();
|
||||||
|
|
||||||
|
self.viewer.svgOverlay('resize');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
next: function() {
|
||||||
|
var page = this.page + (this.mode === 'book' ? 2 : 1);
|
||||||
|
if (this.mode === 'book' && page % 2 === 0 && page !== 0) {
|
||||||
|
page --;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.goToPage({
|
||||||
|
page: page
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
previous: function() {
|
||||||
|
var page = this.page - (this.mode === 'book' ? 2 : 1);
|
||||||
|
if (this.mode === 'book' && page % 2 === 0 && page !== 0) {
|
||||||
|
page --;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.goToPage({
|
||||||
|
page: page
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
hitTest: function(pos) {
|
||||||
|
var count = this.viewer.world.getItemCount();
|
||||||
|
var item, box;
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
item = this.viewer.world.getItemAt(i);
|
||||||
|
box = item.getBounds();
|
||||||
|
if (pos.x > box.x && pos.y > box.y && pos.x < box.x + box.width &&
|
||||||
|
pos.y < box.y + box.height) {
|
||||||
|
return {
|
||||||
|
item: item,
|
||||||
|
index: i
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
getScrollInfo: function() {
|
||||||
|
if (!this.thumbBounds) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var output = {};
|
||||||
|
|
||||||
|
var viewerWidth = this.$el.width();
|
||||||
|
var viewerHeight = this.$el.height();
|
||||||
|
var scrollTop = this.$scrollCover.scrollTop();
|
||||||
|
output.scrollMax = this.$scrollInner.height() - this.$scrollCover.height();
|
||||||
|
output.scrollFactor = (output.scrollMax > 0 ? scrollTop / output.scrollMax : 0);
|
||||||
|
|
||||||
|
output.thumbBounds = this.thumbBounds;
|
||||||
|
output.viewportHeight = output.thumbBounds.width * (viewerHeight / viewerWidth);
|
||||||
|
output.viewportMax = Math.max(0, output.thumbBounds.height - output.viewportHeight);
|
||||||
|
return output;
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
update: function() {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
$('.nav').toggle(this.mode === 'scroll' || this.mode === 'book' || this.mode === 'page');
|
||||||
|
$('.previous').toggleClass('hidden', this.page <= 0);
|
||||||
|
$('.next').toggleClass('hidden', this.page >= this.viewer.world.getItemCount() - 1);
|
||||||
|
|
||||||
|
$.each(this.modeNames, function(i, v) {
|
||||||
|
$('.' + v).toggleClass('active', v === self.mode);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
applyConstraints: function() {
|
||||||
|
if (this.mode === 'thumbs') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.panBounds) {
|
||||||
|
var center = this.viewer.viewport.getCenter(true);
|
||||||
|
var viewBounds = this.viewer.viewport.getBounds(true);
|
||||||
|
var bounds = this.panBounds.clone();
|
||||||
|
var left = bounds.x + (viewBounds.width / 2);
|
||||||
|
var top = bounds.y + (viewBounds.height / 2);
|
||||||
|
var right = (bounds.x + bounds.width) - (viewBounds.width / 2);
|
||||||
|
var bottom = (bounds.y + bounds.height) - (viewBounds.height / 2);
|
||||||
|
|
||||||
|
var x;
|
||||||
|
if (left <= right) {
|
||||||
|
x = Math.max(left, Math.min(right, center.x));
|
||||||
|
} else {
|
||||||
|
x = bounds.x + (bounds.width / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var y;
|
||||||
|
if (top <= bottom) {
|
||||||
|
y = Math.max(top, Math.min(bottom, center.y));
|
||||||
|
} else {
|
||||||
|
y = bounds.y + (bounds.height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x !== center.x || y !== center.y) {
|
||||||
|
this.viewer.viewport.centerSpringX.current.value = x;
|
||||||
|
this.viewer.viewport.centerSpringY.current.value = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
setMode: function(config) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.mode = config.mode;
|
||||||
|
|
||||||
|
if (config.page !== undefined) {
|
||||||
|
this.page = config.page; // Need to do this before layout
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ignoreScroll = true;
|
||||||
|
this.thumbBounds = null;
|
||||||
|
|
||||||
|
var layout = this.createLayout();
|
||||||
|
|
||||||
|
if (this.mode === 'thumbs') {
|
||||||
|
this.viewer.gestureSettingsMouse.scrollToZoom = false;
|
||||||
|
this.viewer.zoomPerClick = 1;
|
||||||
|
this.viewer.panHorizontal = false;
|
||||||
|
this.viewer.panVertical = false;
|
||||||
|
var viewerWidth = this.$el.width();
|
||||||
|
var width = layout.bounds.width + (this.bigBuffer * 2);
|
||||||
|
var height = layout.bounds.height + (this.bigBuffer * 2);
|
||||||
|
var newHeight = viewerWidth * (height / width);
|
||||||
|
this.$scrollCover.show();
|
||||||
|
this.$scrollInner
|
||||||
|
.css({
|
||||||
|
height: newHeight
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.viewer.gestureSettingsMouse.scrollToZoom = true;
|
||||||
|
this.viewer.zoomPerClick = 2;
|
||||||
|
this.viewer.panHorizontal = true;
|
||||||
|
this.viewer.panVertical = true;
|
||||||
|
this.$scrollCover.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setLayout({
|
||||||
|
layout: layout,
|
||||||
|
immediately: config.immediately
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.mode === 'thumbs') {
|
||||||
|
// Set up thumbBounds
|
||||||
|
this.thumbBounds = this.viewer.world.getHomeBounds();
|
||||||
|
this.thumbBounds.x -= this.bigBuffer;
|
||||||
|
this.thumbBounds.y -= this.bigBuffer;
|
||||||
|
this.thumbBounds.width += (this.bigBuffer * 2);
|
||||||
|
this.thumbBounds.height += (this.bigBuffer * 2);
|
||||||
|
|
||||||
|
// Scroll to the appropriate location
|
||||||
|
var info = this.getScrollInfo();
|
||||||
|
|
||||||
|
var viewportBounds = this.thumbBounds.clone();
|
||||||
|
viewportBounds.y += info.viewportMax * info.scrollFactor;
|
||||||
|
viewportBounds.height = info.viewportHeight;
|
||||||
|
|
||||||
|
var itemBounds = this.viewer.world.getItemAt(this.page).getBounds();
|
||||||
|
var top = itemBounds.y - this.bigBuffer;
|
||||||
|
var bottom = top + itemBounds.height + (this.bigBuffer * 2);
|
||||||
|
|
||||||
|
var normalY;
|
||||||
|
if (top < viewportBounds.y) {
|
||||||
|
normalY = top - this.thumbBounds.y;
|
||||||
|
} else if (bottom > viewportBounds.y + viewportBounds.height) {
|
||||||
|
normalY = (bottom - info.viewportHeight) - this.thumbBounds.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalY !== undefined) {
|
||||||
|
var viewportFactor = normalY / info.viewportMax;
|
||||||
|
this.$scrollCover.scrollTop(info.scrollMax * viewportFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.goHome({
|
||||||
|
immediately: config.immediately
|
||||||
|
});
|
||||||
|
|
||||||
|
this.viewer.viewport.minZoomLevel = this.viewer.viewport.getZoom();
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
this.updateHighlight();
|
||||||
|
this.updateHover(-1);
|
||||||
|
|
||||||
|
clearTimeout(this.scrollTimeout);
|
||||||
|
this.scrollTimeout = setTimeout(function() {
|
||||||
|
self.ignoreScroll = false;
|
||||||
|
}, this.viewer.animationTime * 1000);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
updateHighlight: function() {
|
||||||
|
if (this.mode !== 'thumbs') {
|
||||||
|
this.highlight.style('opacity', 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = this.viewer.world.getItemAt(this.page);
|
||||||
|
var box = item.getBounds();
|
||||||
|
|
||||||
|
this.highlight
|
||||||
|
.style('opacity', 1)
|
||||||
|
.attr("x", box.x)
|
||||||
|
.attr("width", box.width)
|
||||||
|
.attr("y", box.y)
|
||||||
|
.attr("height", box.height);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
updateHover: function(page) {
|
||||||
|
if (page === -1 || this.mode !== 'thumbs') {
|
||||||
|
this.hover.style('opacity', 0);
|
||||||
|
this.$scrollCover.css({
|
||||||
|
'cursor': 'default'
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$scrollCover.css({
|
||||||
|
'cursor': 'pointer'
|
||||||
|
});
|
||||||
|
|
||||||
|
var item = this.viewer.world.getItemAt(page);
|
||||||
|
var box = item.getBounds();
|
||||||
|
|
||||||
|
this.hover
|
||||||
|
.style('opacity', 0.3)
|
||||||
|
.attr("x", box.x)
|
||||||
|
.attr("width", box.width)
|
||||||
|
.attr("y", box.y)
|
||||||
|
.attr("height", box.height);
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
goToPage: function(config) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var itemCount = this.viewer.world.getItemCount();
|
||||||
|
this.page = Math.max(0, Math.min(itemCount - 1, config.page));
|
||||||
|
|
||||||
|
var viewerWidth = this.$el.width();
|
||||||
|
var viewerHeight = this.$el.height();
|
||||||
|
var bounds = this.viewer.world.getItemAt(this.page).getBounds();
|
||||||
|
var x = bounds.x;
|
||||||
|
var y = bounds.y;
|
||||||
|
var width = bounds.width;
|
||||||
|
var height = bounds.height;
|
||||||
|
var box;
|
||||||
|
|
||||||
|
if (this.mode === 'book') {
|
||||||
|
var item;
|
||||||
|
if (this.page % 2) { // First in a pair
|
||||||
|
item = this.viewer.world.getItemAt(this.page + 1);
|
||||||
|
if (item) {
|
||||||
|
width += item.getBounds().width;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
item = this.viewer.world.getItemAt(this.page - 1);
|
||||||
|
if (item) {
|
||||||
|
box = item.getBounds();
|
||||||
|
x -= width;
|
||||||
|
width += box.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
x -= this.pageBuffer;
|
||||||
|
y -= this.pageBuffer;
|
||||||
|
width += (this.pageBuffer * 2);
|
||||||
|
height += (this.pageBuffer * 2);
|
||||||
|
|
||||||
|
if (this.mode === 'scroll') {
|
||||||
|
if (this.page === 0) {
|
||||||
|
x = bounds.x - this.pageBuffer;
|
||||||
|
width = height * (viewerWidth / viewerHeight);
|
||||||
|
} else if (this.page === this.viewer.world.getItemCount() - 1) {
|
||||||
|
width = height * (viewerWidth / viewerHeight);
|
||||||
|
x = (bounds.x + bounds.width + this.pageBuffer) - width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
box = new OpenSeadragon.Rect(x, y, width, height);
|
||||||
|
this.viewer.viewport.fitBounds(box, config.immediately);
|
||||||
|
|
||||||
|
this.panBounds = null;
|
||||||
|
|
||||||
|
var setPanBounds = function() {
|
||||||
|
if (self.mode === 'page' || self.mode === 'book') {
|
||||||
|
self.panBounds = box;
|
||||||
|
} else if (self.mode === 'scroll') {
|
||||||
|
self.panBounds = self.viewer.world.getItemAt(0).getBounds()
|
||||||
|
.union(self.viewer.world.getItemAt(itemCount - 1).getBounds());
|
||||||
|
|
||||||
|
self.panBounds.x -= self.pageBuffer;
|
||||||
|
self.panBounds.y -= self.pageBuffer;
|
||||||
|
self.panBounds.width += (self.pageBuffer * 2);
|
||||||
|
self.panBounds.height += (self.pageBuffer * 2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clearTimeout(this.panBoundsTimeout);
|
||||||
|
if (config.immediately) {
|
||||||
|
setPanBounds();
|
||||||
|
} else {
|
||||||
|
this.panBoundsTimeout = setTimeout(setPanBounds, this.viewer.animationTime * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.viewer.viewport.minZoomLevel = this.viewer.viewport.getZoom();
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
createLayout: function() {
|
||||||
|
var viewerWidth = this.$el.width();
|
||||||
|
var viewerHeight = this.$el.height();
|
||||||
|
var layoutConfig = {};
|
||||||
|
|
||||||
|
if (this.mode === 'thumbs') {
|
||||||
|
layoutConfig.columns = Math.floor(viewerWidth / 150);
|
||||||
|
layoutConfig.buffer = this.bigBuffer;
|
||||||
|
layoutConfig.sameWidth = true;
|
||||||
|
} else if (this.mode === 'scroll') {
|
||||||
|
layoutConfig.buffer = this.pageBuffer;
|
||||||
|
} else if (this.mode === 'book' || this.mode === 'page') {
|
||||||
|
layoutConfig.book = (this.mode === 'book');
|
||||||
|
var height = 1 + (this.pageBuffer * 2);
|
||||||
|
// Note that using window here is approximate, but that's close enough.
|
||||||
|
// We can't use viewer, because it may be stretched for the thumbs view.
|
||||||
|
layoutConfig.buffer = (height * ($(window).width() / $(window).height())) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var layout = {
|
||||||
|
bounds: null,
|
||||||
|
specs: []
|
||||||
|
};
|
||||||
|
|
||||||
|
var count = this.viewer.world.getItemCount();
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
var offset = new OpenSeadragon.Point();
|
||||||
|
var rowHeight = 0;
|
||||||
|
var item, box;
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
item = this.viewer.world.getItemAt(i);
|
||||||
|
box = item.getBounds();
|
||||||
|
|
||||||
|
if (i === this.page) {
|
||||||
|
offset = box.getTopLeft().minus(new OpenSeadragon.Point(x, y));
|
||||||
|
}
|
||||||
|
|
||||||
|
box.x = x;
|
||||||
|
box.y = y;
|
||||||
|
if (layoutConfig.sameWidth) {
|
||||||
|
box.height = box.height / box.width;
|
||||||
|
box.width = 1;
|
||||||
|
} else {
|
||||||
|
box.width = box.width / box.height;
|
||||||
|
box.height = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rowHeight = Math.max(rowHeight, box.height);
|
||||||
|
|
||||||
|
layout.specs.push({
|
||||||
|
item: item,
|
||||||
|
bounds: box
|
||||||
|
});
|
||||||
|
|
||||||
|
if (layoutConfig.columns && i % layoutConfig.columns === layoutConfig.columns - 1) {
|
||||||
|
x = 0;
|
||||||
|
y += rowHeight + layoutConfig.buffer;
|
||||||
|
rowHeight = 0;
|
||||||
|
} else {
|
||||||
|
if (!layoutConfig.book || i % 2 === 0) {
|
||||||
|
x += layoutConfig.buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
x += box.width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var pos, spec;
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
spec = layout.specs[i];
|
||||||
|
pos = spec.bounds.getTopLeft().plus(offset);
|
||||||
|
spec.bounds.x = pos.x;
|
||||||
|
spec.bounds.y = pos.y;
|
||||||
|
|
||||||
|
if (layout.bounds) {
|
||||||
|
layout.bounds = layout.bounds.union(spec.bounds);
|
||||||
|
} else {
|
||||||
|
layout.bounds = spec.bounds.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
setLayout: function(config) {
|
||||||
|
var spec;
|
||||||
|
|
||||||
|
for (var i = 0; i < config.layout.specs.length; i++) {
|
||||||
|
spec = config.layout.specs[i];
|
||||||
|
spec.item.setPosition(spec.bounds.getTopLeft(), config.immediately);
|
||||||
|
spec.item.setWidth(spec.bounds.width, config.immediately);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
goHome: function(config) {
|
||||||
|
var viewerWidth = this.$el.width();
|
||||||
|
var viewerHeight = this.$el.height();
|
||||||
|
var layoutConfig = {};
|
||||||
|
|
||||||
|
if (this.mode === 'thumbs') {
|
||||||
|
var info = this.getScrollInfo();
|
||||||
|
var box = this.thumbBounds.clone();
|
||||||
|
box.height = box.width * (viewerHeight / viewerWidth);
|
||||||
|
box.y += info.viewportMax * info.scrollFactor;
|
||||||
|
this.viewer.viewport.fitBounds(box, config.immediately);
|
||||||
|
} else {
|
||||||
|
this.goToPage({
|
||||||
|
page: this.page,
|
||||||
|
immediately: config.immediately
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
getTileSources: function() {
|
||||||
|
if (this.tileSources) {
|
||||||
|
return $.map(this.tileSources.slice(0, this.maxImages), function(v, i) {
|
||||||
|
return new OpenSeadragon.IIIFTileSource(v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputs = [
|
||||||
|
{
|
||||||
|
Image: {
|
||||||
|
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
Url: "http://openseadragon.github.io/example-images/highsmith/highsmith_files/",
|
||||||
|
Format: "jpg",
|
||||||
|
Overlap: "2",
|
||||||
|
TileSize: "256",
|
||||||
|
Size: {
|
||||||
|
Width: "7026",
|
||||||
|
Height: "9221"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
Image: {
|
||||||
|
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
Url: "http://openseadragon.github.io/example-images/duomo/duomo_files/",
|
||||||
|
Format: "jpg",
|
||||||
|
Overlap: "2",
|
||||||
|
TileSize: "256",
|
||||||
|
Size: {
|
||||||
|
Width: "13920",
|
||||||
|
Height: "10200"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
// Image: {
|
||||||
|
// xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
// Url: "../../data/tall_files/",
|
||||||
|
// Format: "jpg",
|
||||||
|
// Overlap: "1",
|
||||||
|
// TileSize: "254",
|
||||||
|
// Size: {
|
||||||
|
// Width: "500",
|
||||||
|
// Height: "2000"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }, {
|
||||||
|
// Image: {
|
||||||
|
// xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
// Url: "../../data/wide_files/",
|
||||||
|
// Format: "jpg",
|
||||||
|
// Overlap: "1",
|
||||||
|
// TileSize: "254",
|
||||||
|
// Size: {
|
||||||
|
// Width: "2000",
|
||||||
|
// Height: "500"
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }, {
|
||||||
|
Image: {
|
||||||
|
xmlns: "http://schemas.microsoft.com/deepzoom/2008",
|
||||||
|
Url: "../../data/testpattern_files/",
|
||||||
|
Format: "jpg",
|
||||||
|
Overlap: "1",
|
||||||
|
TileSize: "254",
|
||||||
|
Size: {
|
||||||
|
Width: "1000",
|
||||||
|
Height: "1000"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
var outputs = [];
|
||||||
|
for (var i = 0; i < this.maxImages; i++) {
|
||||||
|
outputs.push(inputs[Math.floor(Math.random() * inputs.length)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
$(document).ready(function() {
|
||||||
|
App.init();
|
||||||
|
});
|
||||||
|
})();
|
73
test/demo/m2/js/openseadragon-svg-overlay.js
Normal file
73
test/demo/m2/js/openseadragon-svg-overlay.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
(function() {
|
||||||
|
|
||||||
|
if (!window.OpenSeadragon) {
|
||||||
|
console.error('[openseadragon-svg-overlay] requires OpenSeadragon');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var svgNS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
|
var update = function(viewer) {
|
||||||
|
var info = viewer._svgOverlayInfo;
|
||||||
|
|
||||||
|
if (info.containerWidth !== viewer.container.clientWidth) {
|
||||||
|
info.containerWidth = viewer.container.clientWidth;
|
||||||
|
info.svg.setAttribute('width', info.containerWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.containerHeight !== viewer.container.clientHeight) {
|
||||||
|
info.containerHeight = viewer.container.clientHeight;
|
||||||
|
info.svg.setAttribute('height', info.containerHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = viewer.viewport.pixelFromPoint(new OpenSeadragon.Point(0, 0), true);
|
||||||
|
var zoom = viewer.viewport.getZoom(true);
|
||||||
|
var scale = viewer.container.clientWidth * zoom;
|
||||||
|
info.node.setAttribute('transform',
|
||||||
|
'translate(' + p.x + ',' + p.y + ') scale(' + scale + ')');
|
||||||
|
};
|
||||||
|
|
||||||
|
OpenSeadragon.Viewer.prototype.svgOverlay = function(command) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
if (command === undefined) {
|
||||||
|
if (this._svgOverlayInfo) {
|
||||||
|
console.error('[openseadragon-svg-overlay] already initialized on this viewer');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var info = this._svgOverlayInfo = {
|
||||||
|
containerWidth: 0,
|
||||||
|
containerHeight: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
info.svg = document.createElementNS(svgNS, 'svg');
|
||||||
|
info.svg.setAttribute('pointer-events', 'none');
|
||||||
|
info.svg.style.position = 'absolute';
|
||||||
|
info.svg.style.left = 0;
|
||||||
|
info.svg.style.top = 0;
|
||||||
|
info.svg.style.width = '100%';
|
||||||
|
info.svg.style.height = '100%';
|
||||||
|
this.container.insertBefore(info.svg, this.canvas.nextSibling);
|
||||||
|
|
||||||
|
info.node = document.createElementNS(svgNS, 'g');
|
||||||
|
info.svg.appendChild(info.node);
|
||||||
|
|
||||||
|
this.addHandler('animation', function() {
|
||||||
|
update(self);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.addHandler('open', function() {
|
||||||
|
update(self);
|
||||||
|
});
|
||||||
|
|
||||||
|
update(this);
|
||||||
|
return info.node;
|
||||||
|
} else if (command === 'resize') {
|
||||||
|
update(this);
|
||||||
|
} else {
|
||||||
|
console.error('[openseadragon-svg-overlay] unknown command: ' + command);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
@ -50,6 +50,7 @@
|
|||||||
.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', event );
|
.simulate( OpenSeadragon.MouseTracker.haveMouseEnter ? 'mouseleave' : 'mouseout', event );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
initializeTestDOM: function () {
|
initializeTestDOM: function () {
|
||||||
$( "#qunit-fixture" )
|
$( "#qunit-fixture" )
|
||||||
.append( '<div><div id="example"></div><div id="exampleNavigator"></div></div>' )
|
.append( '<div><div id="example"></div><div id="exampleNavigator"></div></div>' )
|
||||||
@ -57,14 +58,17 @@
|
|||||||
.append( '<div id="tallexample"></div>' );
|
.append( '<div id="tallexample"></div>' );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
equalsWithVariance: function ( value1, value2, variance ) {
|
equalsWithVariance: function ( value1, value2, variance ) {
|
||||||
return Math.abs( value1 - value2 ) <= variance;
|
return Math.abs( value1 - value2 ) <= variance;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
assessNumericValue: function ( value1, value2, variance, message ) {
|
assessNumericValue: function ( value1, value2, variance, message ) {
|
||||||
ok( Util.equalsWithVariance( value1, value2, variance ), message + " Expected:" + value1 + " Found: " + value2 + " Variance: " + variance );
|
ok( Util.equalsWithVariance( value1, value2, variance ), message + " Expected:" + value1 + " Found: " + value2 + " Variance: " + variance );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
timeWatcher: function ( time ) {
|
timeWatcher: function ( time ) {
|
||||||
time = time || 2000;
|
time = time || 2000;
|
||||||
var finished = false;
|
var finished = false;
|
||||||
@ -85,8 +89,46 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
spyOnce: function(obj, functionName, callback) {
|
||||||
|
var original = obj[functionName];
|
||||||
|
obj[functionName] = function() {
|
||||||
|
obj[functionName] = original;
|
||||||
|
var result = callback.apply(this, arguments);
|
||||||
|
if (result === undefined) {
|
||||||
|
result = original.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
testDeprecation: function(obj0, member0, obj1, member1) {
|
||||||
|
var called = false;
|
||||||
|
var errored = false;
|
||||||
|
|
||||||
|
if (obj1 && member1) {
|
||||||
|
this.spyOnce(obj1, member1, function() {
|
||||||
|
called = true;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.spyOnce(OpenSeadragon.console, 'error', function(message) {
|
||||||
|
if (/deprecated/.test(message)) {
|
||||||
|
errored = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
obj0[member0]();
|
||||||
|
equal(called, true, 'called through for ' + member0);
|
||||||
|
equal(errored, true, 'errored for ' + member0);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -134,6 +176,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testConsole.assert = function(condition, message) {
|
||||||
|
if (condition) {
|
||||||
|
testConsole.error(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
OpenSeadragon.console = testConsole;
|
OpenSeadragon.console = testConsole;
|
||||||
} )();
|
} )();
|
||||||
|
|
278
test/layers.js
278
test/layers.js
@ -1,278 +0,0 @@
|
|||||||
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
|
||||||
|
|
||||||
( function() {
|
|
||||||
var viewer;
|
|
||||||
|
|
||||||
module( 'Layers', {
|
|
||||||
setup: function() {
|
|
||||||
$( '<div id="layersexample"></div>' ).appendTo( "#qunit-fixture" );
|
|
||||||
|
|
||||||
testLog.reset();
|
|
||||||
|
|
||||||
viewer = OpenSeadragon( {
|
|
||||||
id: 'layersexample',
|
|
||||||
prefixUrl: '/build/openseadragon/images/',
|
|
||||||
springStiffness: 100 // Faster animation = faster tests
|
|
||||||
});
|
|
||||||
},
|
|
||||||
teardown: function() {
|
|
||||||
if ( viewer && viewer.close ) {
|
|
||||||
viewer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
viewer = null;
|
|
||||||
$( "#layersexample" ).remove();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
// ----------
|
|
||||||
asyncTest( 'Layers operations', function() {
|
|
||||||
expect( 23 );
|
|
||||||
viewer.addHandler( "open", function( ) {
|
|
||||||
equal( 1, viewer.getLayersCount( ),
|
|
||||||
"One layer should be present after opening." );
|
|
||||||
var options = {
|
|
||||||
tileSource: {
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [ {
|
|
||||||
url: "data/A.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
viewer.addLayer( options );
|
|
||||||
viewer.addHandler( "add-layer", function addFirstLayerHandler( event ) {
|
|
||||||
viewer.removeHandler( "add-layer", addFirstLayerHandler );
|
|
||||||
var layer1 = event.drawer;
|
|
||||||
equal( viewer.getLayersCount( ), 2,
|
|
||||||
"2 layers should be present after adding a layer." );
|
|
||||||
equal( options, event.options,
|
|
||||||
"The options should be transmitted via the event." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer1 ), 1,
|
|
||||||
"The first added layer should have a level of 1" );
|
|
||||||
equal( viewer.getLayerAtLevel( 1 ), layer1,
|
|
||||||
"The layer at level 1 should be the first added layer." );
|
|
||||||
|
|
||||||
viewer.addLayer( options );
|
|
||||||
viewer.addHandler( "add-layer", function addSecondLayerHandler( event ) {
|
|
||||||
viewer.removeHandler( "add-layer", addSecondLayerHandler );
|
|
||||||
var layer2 = event.drawer;
|
|
||||||
equal( viewer.getLayersCount( ), 3,
|
|
||||||
"3 layers should be present after adding a second layer." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer2 ), 2,
|
|
||||||
"If not specified, a layer should be added with the highest level." );
|
|
||||||
equal( viewer.getLayerAtLevel( 2 ), layer2,
|
|
||||||
"The layer at level 2 should be the second added layer." );
|
|
||||||
|
|
||||||
viewer.addHandler( "layer-level-changed",
|
|
||||||
function layerLevelChangedHandler( event ) {
|
|
||||||
viewer.removeHandler( "layer-level-changed",
|
|
||||||
layerLevelChangedHandler );
|
|
||||||
equal( event.drawer, layer2,
|
|
||||||
"The layer which changed level should be layer2" );
|
|
||||||
equal( event.previousLevel, 2, "Previous level should be 2." );
|
|
||||||
equal( event.newLevel, 1, "New level should be 1." );
|
|
||||||
});
|
|
||||||
viewer.setLayerLevel( layer2, 1 );
|
|
||||||
equal( viewer.getLevelOfLayer( layer2 ), 1,
|
|
||||||
"Layer2 level should be 1 after setLayerLevel." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer1 ), 2,
|
|
||||||
"Layer1 level should be 2 after setLayerLevel." );
|
|
||||||
equal( viewer.getLayerAtLevel( 1 ), layer2,
|
|
||||||
"The layer at level 1 should be layer2." );
|
|
||||||
equal( viewer.getLayerAtLevel( 2 ), layer1,
|
|
||||||
"The layer at level 2 should be layer1." );
|
|
||||||
|
|
||||||
options.level = 2;
|
|
||||||
options.tileSource.levels[0].url = "data/CCyan.png";
|
|
||||||
options.opacity = 0.5;
|
|
||||||
viewer.addLayer( options );
|
|
||||||
viewer.addHandler( "add-layer", function addThirdLayerHandler( event ) {
|
|
||||||
viewer.removeHandler( "add-layer", addThirdLayerHandler );
|
|
||||||
var layer3 = event.drawer;
|
|
||||||
equal( viewer.getLayersCount( ), 4,
|
|
||||||
"4 layers should be present after adding a third layer." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer3 ), 2,
|
|
||||||
"Layer 3 should be added with level 2." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer2 ), 1,
|
|
||||||
"Layer 2 should stay at level 1." );
|
|
||||||
|
|
||||||
viewer.addHandler( "remove-layer", function removeLayerHandler( event ) {
|
|
||||||
viewer.removeHandler( "remove-layer", removeLayerHandler );
|
|
||||||
|
|
||||||
equal( layer2, event.drawer, "Removed layer should be layer2." );
|
|
||||||
|
|
||||||
equal( viewer.getLevelOfLayer( layer1 ), 2,
|
|
||||||
"Layer 1 should be at level 2." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer2 ), -1,
|
|
||||||
"Layer 2 should be at level -1." );
|
|
||||||
equal( viewer.getLevelOfLayer( layer3 ), 1,
|
|
||||||
"Layer 3 should be at level 1." );
|
|
||||||
|
|
||||||
});
|
|
||||||
viewer.removeLayer( layer2 );
|
|
||||||
|
|
||||||
options.tileSource.levels[0].width = 500;
|
|
||||||
viewer.addHandler( "add-layer-failed", function addLayerFailed( event ) {
|
|
||||||
viewer.removeHandler( "add-layer-failed", addLayerFailed );
|
|
||||||
|
|
||||||
equal( viewer.getLayersCount(), 3 );
|
|
||||||
|
|
||||||
start();
|
|
||||||
});
|
|
||||||
viewer.addLayer( options );
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
viewer.open( '/test/data/testpattern.dzi' );
|
|
||||||
});
|
|
||||||
|
|
||||||
asyncTest( 'Sequences as layers', function() {
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
tileSource: [{
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [{
|
|
||||||
url: "data/A.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
}]
|
|
||||||
}, {
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [{
|
|
||||||
url: "data/BBlue.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
};
|
|
||||||
|
|
||||||
viewer.addHandler( "open", function openHandler() {
|
|
||||||
viewer.removeHandler( "open", openHandler );
|
|
||||||
|
|
||||||
viewer.addHandler( "add-layer-failed",
|
|
||||||
function addLayerFailedHandler( event ) {
|
|
||||||
viewer.removeHandler( "add-layer-failed", addLayerFailedHandler );
|
|
||||||
equal( event.message, "Sequences can not be added as layers." );
|
|
||||||
equal( event.options, options, "Layer failed event should give the options." );
|
|
||||||
start();
|
|
||||||
} );
|
|
||||||
viewer.addLayer( options );
|
|
||||||
|
|
||||||
});
|
|
||||||
viewer.open( '/test/data/testpattern.dzi' );
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
asyncTest( 'Reassign base layer', function() {
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
tileSource: {
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [{
|
|
||||||
url: "data/A.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
level: 0
|
|
||||||
};
|
|
||||||
viewer.addHandler( "open", function openHandler( ) {
|
|
||||||
viewer.removeHandler( "open", openHandler );
|
|
||||||
var testPatternDrawer = viewer.drawer;
|
|
||||||
equal( viewer.drawer, testPatternDrawer, "Viewer.drawer should be set to testPatternDrawer." );
|
|
||||||
viewer.addHandler( "add-layer", function addLayerHandler( event ) {
|
|
||||||
viewer.removeHandler( "add-layer", addLayerHandler );
|
|
||||||
var aDrawer = event.drawer;
|
|
||||||
equal( viewer.drawer, aDrawer, "Viewer.drawer should be set to aDrawer." );
|
|
||||||
viewer.setLayerLevel( aDrawer, 1 );
|
|
||||||
equal( viewer.drawer, testPatternDrawer, "Viewer.drawer should be set back to testPatternDrawer." );
|
|
||||||
|
|
||||||
viewer.removeLayer( viewer.drawer );
|
|
||||||
equal( viewer.drawer, aDrawer, "Viewer.drawer must be reassigned when removing base layer." );
|
|
||||||
|
|
||||||
viewer.removeLayer( viewer.drawer );
|
|
||||||
ok( !viewer.isOpen(), "Viewer should be closed when removing last layer." );
|
|
||||||
|
|
||||||
start();
|
|
||||||
});
|
|
||||||
viewer.addLayer( options );
|
|
||||||
});
|
|
||||||
viewer.open( '/test/data/testpattern.dzi' );
|
|
||||||
});
|
|
||||||
|
|
||||||
asyncTest( 'Layers and sequences', function() {
|
|
||||||
expect( 1 );
|
|
||||||
|
|
||||||
// TODO: Remove workaround when issue #321 is fixed.
|
|
||||||
// https://github.com/openseadragon/openseadragon/issues/321
|
|
||||||
// viewer.open( [{
|
|
||||||
// type: 'legacy-image-pyramid',
|
|
||||||
// levels: [ {
|
|
||||||
// url: "data/A.png",
|
|
||||||
// width: 1000,
|
|
||||||
// height: 1000
|
|
||||||
// }]
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// type: 'legacy-image-pyramid',
|
|
||||||
// levels: [ {
|
|
||||||
// url: "data/BBlue.png",
|
|
||||||
// width: 1000,
|
|
||||||
// height: 1000
|
|
||||||
// }]}] );
|
|
||||||
|
|
||||||
viewer.close();
|
|
||||||
viewer = OpenSeadragon({
|
|
||||||
id: 'layersexample',
|
|
||||||
prefixUrl: '/build/openseadragon/images/',
|
|
||||||
springStiffness: 100, // Faster animation = faster tests
|
|
||||||
tileSources: [{
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [{
|
|
||||||
url: "data/A.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [{
|
|
||||||
url: "data/BBlue.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
}]
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
// End workaround
|
|
||||||
|
|
||||||
var options = {
|
|
||||||
tileSource: {
|
|
||||||
type: 'legacy-image-pyramid',
|
|
||||||
levels: [{
|
|
||||||
url: "data/CCyan.png",
|
|
||||||
width: 1000,
|
|
||||||
height: 1000
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
viewer.addHandler( "open", function openHandler() {
|
|
||||||
viewer.addHandler( "add-layer", function addLayerHandler( event ) {
|
|
||||||
viewer.removeHandler( "add-layer", addLayerHandler );
|
|
||||||
|
|
||||||
var layer = event.drawer;
|
|
||||||
try {
|
|
||||||
viewer.setLayerLevel( layer, 0 );
|
|
||||||
} catch (e) {
|
|
||||||
ok( true );
|
|
||||||
}
|
|
||||||
start();
|
|
||||||
} );
|
|
||||||
viewer.addLayer( options );
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
})();
|
|
@ -95,7 +95,8 @@
|
|||||||
var panHandler = function() {
|
var panHandler = function() {
|
||||||
viewer.removeHandler('animation-finish', panHandler);
|
viewer.removeHandler('animation-finish', panHandler);
|
||||||
center = viewport.getCenter();
|
center = viewport.getCenter();
|
||||||
ok(center.x === 0.1 && center.y === 0.1, 'Panned correctly');
|
Util.assessNumericValue(center.x, 0.1, 0.00001, 'panned horizontally');
|
||||||
|
Util.assessNumericValue(center.y, 0.1, 0.00001, 'panned vertically');
|
||||||
start();
|
start();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -133,7 +134,7 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
viewer.addHandler('animation-finish', homeHandler);
|
viewer.addHandler('animation-finish', homeHandler);
|
||||||
viewport.goHome(true);
|
viewer.viewport.goHome(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
viewer.addHandler("open", opener);
|
viewer.addHandler("open", opener);
|
||||||
@ -260,9 +261,8 @@
|
|||||||
viewer.removeHandler('close', closeHandler);
|
viewer.removeHandler('close', closeHandler);
|
||||||
ok(!viewer.source, 'no source');
|
ok(!viewer.source, 'no source');
|
||||||
ok(true, 'Close event was sent');
|
ok(true, 'Close event was sent');
|
||||||
ok(!viewer._updateRequestId, 'timer is off');
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
ok(!viewer._updateRequestId, 'timer is still off');
|
ok(!viewer._updateRequestId, 'timer is off');
|
||||||
start();
|
start();
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
9
test/controls.js → test/modules/controls.js
vendored
9
test/controls.js → test/modules/controls.js
vendored
@ -5,7 +5,12 @@
|
|||||||
|
|
||||||
module('Controls', {
|
module('Controls', {
|
||||||
setup: function () {
|
setup: function () {
|
||||||
var example = $('<div id="controlsTests"></div>').appendTo("#qunit-fixture");
|
var example = $('<div id="controlsTests"></div>')
|
||||||
|
.css({
|
||||||
|
width: 1000,
|
||||||
|
height: 1000
|
||||||
|
})
|
||||||
|
.appendTo("#qunit-fixture");
|
||||||
|
|
||||||
testLog.reset();
|
testLog.reset();
|
||||||
|
|
||||||
@ -324,6 +329,7 @@
|
|||||||
],
|
],
|
||||||
springStiffness: 100, // Faster animation = faster tests
|
springStiffness: 100, // Faster animation = faster tests
|
||||||
showSequenceControl: true,
|
showSequenceControl: true,
|
||||||
|
sequenceMode: true,
|
||||||
navPrevNextWrap: false
|
navPrevNextWrap: false
|
||||||
});
|
});
|
||||||
viewer.addHandler('open', openHandler);
|
viewer.addHandler('open', openHandler);
|
||||||
@ -375,6 +381,7 @@
|
|||||||
],
|
],
|
||||||
springStiffness: 100, // Faster animation = faster tests
|
springStiffness: 100, // Faster animation = faster tests
|
||||||
showSequenceControl: true,
|
showSequenceControl: true,
|
||||||
|
sequenceMode: true,
|
||||||
navPrevNextWrap: true
|
navPrevNextWrap: true
|
||||||
});
|
});
|
||||||
viewer.addHandler('open', openHandler);
|
viewer.addHandler('open', openHandler);
|
84
test/modules/drawer.js
Normal file
84
test/modules/drawer.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var viewer;
|
||||||
|
|
||||||
|
module('Drawer', {
|
||||||
|
setup: function () {
|
||||||
|
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
|
||||||
|
|
||||||
|
testLog.reset();
|
||||||
|
},
|
||||||
|
teardown: function () {
|
||||||
|
if (viewer && viewer.close) {
|
||||||
|
viewer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
viewer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
var createViewer = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
viewer = OpenSeadragon(OpenSeadragon.extend({
|
||||||
|
id: 'example',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
springStiffness: 100 // Faster animation = faster tests
|
||||||
|
}, options));
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('basics', function() {
|
||||||
|
createViewer();
|
||||||
|
ok(viewer.drawer, 'Drawer exists');
|
||||||
|
equal(viewer.drawer.canRotate(), OpenSeadragon.supportsCanvas, 'we can rotate if we have canvas');
|
||||||
|
equal(viewer.drawer.getOpacity(), 1, 'starts with full opacity');
|
||||||
|
viewer.drawer.setOpacity(0.4);
|
||||||
|
equal(viewer.drawer.getOpacity(), 0.4, 'setting opacity works');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('rotation', function() {
|
||||||
|
createViewer({
|
||||||
|
tileSources: '/test/data/testpattern.dzi'
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.addHandler('open', function handler(event) {
|
||||||
|
viewer.viewport.setRotation(30);
|
||||||
|
Util.spyOnce(viewer.drawer.context, 'rotate', function() {
|
||||||
|
ok(true, 'drawing with new rotation');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('debug', function() {
|
||||||
|
createViewer({
|
||||||
|
tileSources: '/test/data/testpattern.dzi',
|
||||||
|
debugMode: true
|
||||||
|
});
|
||||||
|
|
||||||
|
Util.spyOnce(viewer.drawer, 'drawDebugInfo', function() {
|
||||||
|
ok(true, 'drawDebugInfo is called');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('deprecations', function() {
|
||||||
|
createViewer();
|
||||||
|
Util.testDeprecation(viewer.drawer, 'addOverlay', viewer, 'addOverlay');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'updateOverlay', viewer, 'updateOverlay');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'removeOverlay', viewer, 'removeOverlay');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'clearOverlays', viewer, 'clearOverlays');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'needsUpdate', viewer.world, 'needsDraw');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'numTilesLoaded', viewer.tileCache, 'numTilesLoaded');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'reset', viewer.world, 'resetItems');
|
||||||
|
Util.testDeprecation(viewer.drawer, 'update', viewer.world, 'draw');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
178
test/modules/multi-image.js
Normal file
178
test/modules/multi-image.js
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog, expect */
|
||||||
|
|
||||||
|
( function() {
|
||||||
|
var viewer;
|
||||||
|
|
||||||
|
module( 'Multi-Image', {
|
||||||
|
setup: function() {
|
||||||
|
$( '<div id="itemsexample"></div>' ).appendTo( "#qunit-fixture" );
|
||||||
|
|
||||||
|
testLog.reset();
|
||||||
|
|
||||||
|
viewer = OpenSeadragon( {
|
||||||
|
id: 'itemsexample',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
springStiffness: 100 // Faster animation = faster tests
|
||||||
|
});
|
||||||
|
},
|
||||||
|
teardown: function() {
|
||||||
|
if ( viewer && viewer.close ) {
|
||||||
|
viewer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
viewer = null;
|
||||||
|
$( "#itemsexample" ).remove();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest( 'Multi-image operations', function() {
|
||||||
|
expect( 21 );
|
||||||
|
viewer.addHandler( "open", function( ) {
|
||||||
|
equal( 1, viewer.world.getItemCount( ),
|
||||||
|
"One item should be present after opening." );
|
||||||
|
var options = {
|
||||||
|
tileSource: {
|
||||||
|
type: 'legacy-image-pyramid',
|
||||||
|
levels: [ {
|
||||||
|
url: "data/A.png",
|
||||||
|
width: 1000,
|
||||||
|
height: 1000
|
||||||
|
} ]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
viewer.addTiledImage( options );
|
||||||
|
viewer.world.addHandler( "add-item", function addFirstItemHandler( event ) {
|
||||||
|
viewer.world.removeHandler( "add-item", addFirstItemHandler );
|
||||||
|
var item1 = event.item;
|
||||||
|
equal( viewer.world.getItemCount( ), 2,
|
||||||
|
"2 items should be present after adding a item." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item1 ), 1,
|
||||||
|
"The first added item should have a index of 1" );
|
||||||
|
equal( viewer.world.getItemAt( 1 ), item1,
|
||||||
|
"The item at index 1 should be the first added item." );
|
||||||
|
|
||||||
|
viewer.addTiledImage( options );
|
||||||
|
viewer.world.addHandler( "add-item", function addSecondItemHandler( event ) {
|
||||||
|
viewer.world.removeHandler( "add-item", addSecondItemHandler );
|
||||||
|
var item2 = event.item;
|
||||||
|
equal( viewer.world.getItemCount( ), 3,
|
||||||
|
"3 items should be present after adding a second item." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item2 ), 2,
|
||||||
|
"If not specified, a item should be added with the highest index." );
|
||||||
|
equal( viewer.world.getItemAt( 2 ), item2,
|
||||||
|
"The item at index 2 should be the second added item." );
|
||||||
|
|
||||||
|
viewer.world.addHandler( "item-index-change",
|
||||||
|
function itemIndexChangedHandler( event ) {
|
||||||
|
viewer.world.removeHandler( "item-index-change",
|
||||||
|
itemIndexChangedHandler );
|
||||||
|
equal( event.item, item2,
|
||||||
|
"The item which changed index should be item2" );
|
||||||
|
equal( event.previousIndex, 2, "Previous index should be 2." );
|
||||||
|
equal( event.newIndex, 1, "New index should be 1." );
|
||||||
|
});
|
||||||
|
viewer.world.setItemIndex( item2, 1 );
|
||||||
|
equal( viewer.world.getIndexOfItem( item2 ), 1,
|
||||||
|
"Item2 index should be 1 after setItemIndex." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item1 ), 2,
|
||||||
|
"Item1 index should be 2 after setItemIndex." );
|
||||||
|
equal( viewer.world.getItemAt( 1 ), item2,
|
||||||
|
"The item at index 1 should be item2." );
|
||||||
|
equal( viewer.world.getItemAt( 2 ), item1,
|
||||||
|
"The item at index 2 should be item1." );
|
||||||
|
|
||||||
|
options.index = 2;
|
||||||
|
options.tileSource.levels[0].url = "data/CCyan.png";
|
||||||
|
viewer.addTiledImage( options );
|
||||||
|
viewer.world.addHandler( "add-item", function addThirdItemHandler( event ) {
|
||||||
|
viewer.world.removeHandler( "add-item", addThirdItemHandler );
|
||||||
|
var item3 = event.item;
|
||||||
|
equal( viewer.world.getItemCount( ), 4,
|
||||||
|
"4 items should be present after adding a third item." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item3 ), 2,
|
||||||
|
"Item 3 should be added with index 2." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item2 ), 1,
|
||||||
|
"Item 2 should stay at index 1." );
|
||||||
|
|
||||||
|
viewer.world.addHandler( "remove-item", function removeItemHandler( event ) {
|
||||||
|
viewer.world.removeHandler( "remove-item", removeItemHandler );
|
||||||
|
|
||||||
|
equal( item2, event.item, "Removed item should be item2." );
|
||||||
|
|
||||||
|
equal( viewer.world.getIndexOfItem( item1 ), 2,
|
||||||
|
"Item 1 should be at index 2." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item2 ), -1,
|
||||||
|
"Item 2 should be at index -1." );
|
||||||
|
equal( viewer.world.getIndexOfItem( item3 ), 1,
|
||||||
|
"Item 3 should be at index 1." );
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.removeItem( item2 );
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
viewer.open( '/test/data/testpattern.dzi' );
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest( 'Sequences as items', function() {
|
||||||
|
var options = {
|
||||||
|
tileSource: [{
|
||||||
|
type: 'legacy-image-pyramid',
|
||||||
|
levels: [{
|
||||||
|
url: "data/A.png",
|
||||||
|
width: 1000,
|
||||||
|
height: 1000
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
type: 'legacy-image-pyramid',
|
||||||
|
levels: [{
|
||||||
|
url: "data/BBlue.png",
|
||||||
|
width: 1000,
|
||||||
|
height: 1000
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
viewer.addHandler( "open", function openHandler() {
|
||||||
|
viewer.removeHandler( "open", openHandler );
|
||||||
|
|
||||||
|
viewer.addHandler( "add-item-failed",
|
||||||
|
function addItemFailedHandler( event ) {
|
||||||
|
viewer.removeHandler( "add-item-failed", addItemFailedHandler );
|
||||||
|
equal( event.message, "[Viewer.addTiledImage] Sequences can not be added; add them one at a time instead." );
|
||||||
|
equal( event.options, options, "Item failed event should give the options." );
|
||||||
|
start();
|
||||||
|
} );
|
||||||
|
viewer.addTiledImage( options );
|
||||||
|
|
||||||
|
});
|
||||||
|
viewer.open( '/test/data/testpattern.dzi' );
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('items are added in order', function() {
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
equal(viewer.world.getItemAt(0).getContentSize().y, 2000, 'first image is tall');
|
||||||
|
equal(viewer.world.getItemAt(0).getBounds().width, 4, 'first image has 4 width');
|
||||||
|
equal(viewer.world.getItemAt(1).getContentSize().x, 2000, 'second image is wide');
|
||||||
|
equal(viewer.world.getItemAt(1).getBounds().width, 2, 'second image has 2 width');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.open([
|
||||||
|
{
|
||||||
|
tileSource: '/test/data/tall.dzi',
|
||||||
|
width: 4
|
||||||
|
}, {
|
||||||
|
tileSource: '/test/data/wide.dzi',
|
||||||
|
width: 2
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -1,6 +1,4 @@
|
|||||||
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */
|
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal, propEqual */
|
||||||
|
|
||||||
QUnit.config.autostart = false;
|
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var debug = false,
|
var debug = false,
|
||||||
@ -31,10 +29,6 @@ QUnit.config.autostart = false;
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).ready(function () {
|
|
||||||
start();
|
|
||||||
});
|
|
||||||
|
|
||||||
var resetTestVariables = function () {
|
var resetTestVariables = function () {
|
||||||
if (viewer) {
|
if (viewer) {
|
||||||
viewer.close();
|
viewer.close();
|
||||||
@ -146,7 +140,7 @@ QUnit.config.autostart = false;
|
|||||||
currentDisplayRegionLeft = displayRegion.position().left;
|
currentDisplayRegionLeft = displayRegion.position().left;
|
||||||
currentDisplayWidth = displayRegion.width();
|
currentDisplayWidth = displayRegion.width();
|
||||||
viewerAndNavigatorDisplayReady = viewer.drawer !== null &&
|
viewerAndNavigatorDisplayReady = viewer.drawer !== null &&
|
||||||
!viewer.drawer.needsUpdate() &&
|
!viewer.world.needsDraw() &&
|
||||||
currentDisplayWidth > 0 &&
|
currentDisplayWidth > 0 &&
|
||||||
Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, 0.0001) &&
|
Util.equalsWithVariance(lastDisplayRegionLeft, currentDisplayRegionLeft, 0.0001) &&
|
||||||
Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, 0.0001) &&
|
Util.equalsWithVariance(lastDisplayWidth, currentDisplayWidth, 0.0001) &&
|
||||||
@ -166,7 +160,7 @@ QUnit.config.autostart = false;
|
|||||||
else {
|
else {
|
||||||
if (count === 40) {
|
if (count === 40) {
|
||||||
console.log("waitForViewer:" +
|
console.log("waitForViewer:" +
|
||||||
viewer.drawer + ":" + viewer.drawer.needsUpdate() + ":" +
|
viewer.drawer + ":" + viewer.world.needsDraw() + ":" +
|
||||||
viewerAndNavigatorDisplayReady + ":" +
|
viewerAndNavigatorDisplayReady + ":" +
|
||||||
lastDisplayRegionLeft + ":" + currentDisplayRegionLeft + ":" +
|
lastDisplayRegionLeft + ":" + currentDisplayRegionLeft + ":" +
|
||||||
lastDisplayWidth + ":" + currentDisplayWidth + ":" +
|
lastDisplayWidth + ":" + currentDisplayWidth + ":" +
|
||||||
@ -765,11 +759,11 @@ QUnit.config.autostart = false;
|
|||||||
var openHandler1 = function(event) {
|
var openHandler1 = function(event) {
|
||||||
viewer.removeHandler('open', openHandler1);
|
viewer.removeHandler('open', openHandler1);
|
||||||
ok(viewer.navigator, 'navigator exists');
|
ok(viewer.navigator, 'navigator exists');
|
||||||
viewer.navigator.addHandler('open', navOpenHandler1);
|
viewer.navigator.world.addHandler('add-item', navOpenHandler1);
|
||||||
};
|
};
|
||||||
|
|
||||||
var navOpenHandler1 = function(event) {
|
var navOpenHandler1 = function(event) {
|
||||||
viewer.navigator.removeHandler('open', navOpenHandler1);
|
viewer.navigator.world.removeHandler('add-item', navOpenHandler1);
|
||||||
equal(viewer.navigator.source, viewer.source, 'viewer and navigator have the same source');
|
equal(viewer.navigator.source, viewer.source, 'viewer and navigator have the same source');
|
||||||
ok(viewer.navigator._updateRequestId, 'navigator timer is on');
|
ok(viewer.navigator._updateRequestId, 'navigator timer is on');
|
||||||
viewer.addHandler('close', closeHandler1);
|
viewer.addHandler('close', closeHandler1);
|
||||||
@ -785,11 +779,11 @@ QUnit.config.autostart = false;
|
|||||||
|
|
||||||
var openHandler2 = function(event) {
|
var openHandler2 = function(event) {
|
||||||
viewer.removeHandler('open', openHandler2);
|
viewer.removeHandler('open', openHandler2);
|
||||||
viewer.navigator.addHandler('open', navOpenHandler2);
|
viewer.navigator.world.addHandler('add-item', navOpenHandler2);
|
||||||
};
|
};
|
||||||
|
|
||||||
var navOpenHandler2 = function(event) {
|
var navOpenHandler2 = function(event) {
|
||||||
viewer.navigator.removeHandler('open', navOpenHandler2);
|
viewer.navigator.world.removeHandler('add-item', navOpenHandler2);
|
||||||
equal(viewer.navigator.source, viewer.source, 'viewer and navigator have the same source');
|
equal(viewer.navigator.source, viewer.source, 'viewer and navigator have the same source');
|
||||||
viewer.addHandler('close', closeHandler2);
|
viewer.addHandler('close', closeHandler2);
|
||||||
viewer.close();
|
viewer.close();
|
||||||
@ -797,13 +791,56 @@ QUnit.config.autostart = false;
|
|||||||
|
|
||||||
var closeHandler2 = function(event) {
|
var closeHandler2 = function(event) {
|
||||||
viewer.removeHandler('close', closeHandler2);
|
viewer.removeHandler('close', closeHandler2);
|
||||||
ok(!viewer.navigator._updateRequestId, 'navigator timer is off');
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
ok(!viewer.navigator._updateRequestId, 'navigator timer is still off');
|
ok(!viewer.navigator._updateRequestId, 'navigator timer is off');
|
||||||
timeWatcher.done();
|
timeWatcher.done();
|
||||||
}, 100);
|
}, 100);
|
||||||
};
|
};
|
||||||
|
|
||||||
viewer.addHandler('open', openHandler1);
|
viewer.addHandler('open', openHandler1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
asyncTest('Item positions including collection mode', function() {
|
||||||
|
var navAddCount = 0;
|
||||||
|
|
||||||
|
viewer = OpenSeadragon({
|
||||||
|
id: 'example',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
tileSources: ['/test/data/testpattern.dzi', '/test/data/testpattern.dzi'],
|
||||||
|
springStiffness: 100, // Faster animation = faster tests
|
||||||
|
showNavigator: true,
|
||||||
|
collectionMode: true
|
||||||
|
});
|
||||||
|
|
||||||
|
var openHandler = function() {
|
||||||
|
viewer.removeHandler('open', openHandler);
|
||||||
|
viewer.navigator.world.addHandler('add-item', navOpenHandler);
|
||||||
|
};
|
||||||
|
|
||||||
|
var navOpenHandler = function(event) {
|
||||||
|
navAddCount++;
|
||||||
|
if (navAddCount === 2) {
|
||||||
|
viewer.navigator.world.removeHandler('add-item', navOpenHandler);
|
||||||
|
|
||||||
|
setTimeout(function() {
|
||||||
|
// Test initial formation
|
||||||
|
equal(viewer.navigator.world.getItemCount(), 2, 'navigator has both items');
|
||||||
|
for (var i = 0; i < 2; i++) {
|
||||||
|
propEqual(viewer.navigator.world.getItemAt(i).getBounds(),
|
||||||
|
viewer.world.getItemAt(i).getBounds(), 'bounds are the same');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try moving one
|
||||||
|
viewer.world.getItemAt(0).setPosition(new OpenSeadragon.Point(-200, -200));
|
||||||
|
propEqual(viewer.navigator.world.getItemAt(0).getBounds(),
|
||||||
|
viewer.world.getItemAt(0).getBounds(), 'bounds are the same after move');
|
||||||
|
|
||||||
|
start();
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
viewer.addHandler('open', openHandler);
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
@ -1,4 +1,4 @@
|
|||||||
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */
|
/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal, testLog */
|
||||||
|
|
||||||
( function() {
|
( function() {
|
||||||
var viewer;
|
var viewer;
|
||||||
@ -29,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
var ready = viewer.isOpen() &&
|
var ready = viewer.isOpen() &&
|
||||||
viewer.drawer !== null &&
|
viewer.drawer !== null &&
|
||||||
!viewer.drawer.needsUpdate() &&
|
!viewer.world.needsDraw() &&
|
||||||
Util.equalsWithVariance( viewer.viewport.getBounds( true ).x,
|
Util.equalsWithVariance( viewer.viewport.getBounds( true ).x,
|
||||||
viewer.viewport.getBounds().x, 0.000 ) &&
|
viewer.viewport.getBounds().x, 0.000 ) &&
|
||||||
Util.equalsWithVariance( viewer.viewport.getBounds( true ).y,
|
Util.equalsWithVariance( viewer.viewport.getBounds( true ).y,
|
||||||
@ -46,7 +46,7 @@
|
|||||||
}, 100 );
|
}, 100 );
|
||||||
} else {
|
} else {
|
||||||
console.log( "waitForViewer:" + viewer.isOpen( ) + ":" + viewer.drawer +
|
console.log( "waitForViewer:" + viewer.isOpen( ) + ":" + viewer.drawer +
|
||||||
":" + viewer.drawer.needsUpdate() );
|
":" + viewer.world.needsDraw() );
|
||||||
handler();
|
handler();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -532,4 +532,35 @@
|
|||||||
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('overlays appear immediately', function() {
|
||||||
|
equal($('#immediate-overlay0').length, 0, 'overlay 0 does not exist');
|
||||||
|
equal($('#immediate-overlay1').length, 0, 'overlay 1 does not exist');
|
||||||
|
|
||||||
|
viewer = OpenSeadragon( {
|
||||||
|
id: 'example-overlays',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
tileSources: '/test/data/testpattern.dzi',
|
||||||
|
springStiffness: 100, // Faster animation = faster tests
|
||||||
|
overlays: [ {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
id: "immediate-overlay0"
|
||||||
|
} ]
|
||||||
|
} );
|
||||||
|
|
||||||
|
viewer.addHandler('open', function() {
|
||||||
|
equal($('#immediate-overlay0').length, 1, 'overlay 0 exists');
|
||||||
|
|
||||||
|
viewer.addOverlay( {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
id: "immediate-overlay1"
|
||||||
|
} );
|
||||||
|
|
||||||
|
equal($('#immediate-overlay1').length, 1, 'overlay 1 exists');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
} )( );
|
} )( );
|
46
test/modules/referencestrip.js
Normal file
46
test/modules/referencestrip.js
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var viewer;
|
||||||
|
|
||||||
|
module('ReferenceStrip', {
|
||||||
|
setup: function () {
|
||||||
|
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
|
||||||
|
|
||||||
|
testLog.reset();
|
||||||
|
},
|
||||||
|
teardown: function () {
|
||||||
|
if (viewer && viewer.close) {
|
||||||
|
viewer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
viewer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
var createViewer = function(options) {
|
||||||
|
options = options || {};
|
||||||
|
viewer = OpenSeadragon(OpenSeadragon.extend({
|
||||||
|
id: 'example',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
springStiffness: 100 // Faster animation = faster tests
|
||||||
|
}, options));
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('basics', function() {
|
||||||
|
createViewer({
|
||||||
|
sequenceMode: true,
|
||||||
|
showReferenceStrip: true,
|
||||||
|
tileSources: [
|
||||||
|
'/test/data/tall.dzi',
|
||||||
|
'/test/data/wide.dzi',
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(viewer.referenceStrip, 'referenceStrip exists');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
111
test/modules/tilecache.js
Normal file
111
test/modules/tilecache.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
module('TileCache', {
|
||||||
|
setup: function () {
|
||||||
|
testLog.reset();
|
||||||
|
},
|
||||||
|
teardown: function () {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('basics', function() {
|
||||||
|
var fakeTiledImage0 = {};
|
||||||
|
var fakeTiledImage1 = {};
|
||||||
|
|
||||||
|
var fakeTile0 = {
|
||||||
|
url: 'foo.jpg',
|
||||||
|
image: {},
|
||||||
|
unload: function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
var fakeTile1 = {
|
||||||
|
url: 'foo.jpg',
|
||||||
|
image: {},
|
||||||
|
unload: function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
var cache = new OpenSeadragon.TileCache();
|
||||||
|
equal(cache.numTilesLoaded(), 0, 'no tiles to begin with');
|
||||||
|
|
||||||
|
cache.cacheTile({
|
||||||
|
tile: fakeTile0,
|
||||||
|
tiledImage: fakeTiledImage0
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 1, 'tile count after cache');
|
||||||
|
|
||||||
|
cache.cacheTile({
|
||||||
|
tile: fakeTile1,
|
||||||
|
tiledImage: fakeTiledImage1
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 2, 'tile count after second cache');
|
||||||
|
|
||||||
|
cache.clearTilesFor(fakeTiledImage0);
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 1, 'tile count after first clear');
|
||||||
|
|
||||||
|
cache.clearTilesFor(fakeTiledImage1);
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 0, 'tile count after second clear');
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('maxImageCacheCount', function() {
|
||||||
|
var fakeTiledImage0 = {};
|
||||||
|
|
||||||
|
var fakeTile0 = {
|
||||||
|
url: 'different.jpg',
|
||||||
|
image: {},
|
||||||
|
unload: function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
var fakeTile1 = {
|
||||||
|
url: 'same.jpg',
|
||||||
|
image: {},
|
||||||
|
unload: function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
var fakeTile2 = {
|
||||||
|
url: 'same.jpg',
|
||||||
|
image: {},
|
||||||
|
unload: function() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
var cache = new OpenSeadragon.TileCache({
|
||||||
|
maxImageCacheCount: 1
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 0, 'no tiles to begin with');
|
||||||
|
|
||||||
|
cache.cacheTile({
|
||||||
|
tile: fakeTile0,
|
||||||
|
tiledImage: fakeTiledImage0
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 1, 'tile count after add');
|
||||||
|
|
||||||
|
cache.cacheTile({
|
||||||
|
tile: fakeTile1,
|
||||||
|
tiledImage: fakeTiledImage0
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 1, 'tile count after add of second image');
|
||||||
|
|
||||||
|
cache.cacheTile({
|
||||||
|
tile: fakeTile2,
|
||||||
|
tiledImage: fakeTiledImage0
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(cache.numTilesLoaded(), 2, 'tile count after additional same image');
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
194
test/modules/tiledimage.js
Normal file
194
test/modules/tiledimage.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog, propEqual */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var viewer;
|
||||||
|
|
||||||
|
module('TiledImage', {
|
||||||
|
setup: function () {
|
||||||
|
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
|
||||||
|
|
||||||
|
testLog.reset();
|
||||||
|
|
||||||
|
viewer = OpenSeadragon({
|
||||||
|
id: 'example',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
springStiffness: 100 // Faster animation = faster tests
|
||||||
|
});
|
||||||
|
},
|
||||||
|
teardown: function () {
|
||||||
|
if (viewer && viewer.close) {
|
||||||
|
viewer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
viewer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
var checkBounds = function(image, expected, message) {
|
||||||
|
var bounds = image.getBounds();
|
||||||
|
equal(bounds.x, expected.x, message + ' x');
|
||||||
|
equal(bounds.y, expected.y, message + ' y');
|
||||||
|
equal(bounds.width, expected.width, message + ' width');
|
||||||
|
equal(bounds.height, expected.height, message + ' height');
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('metrics', function() {
|
||||||
|
var handlerCount = 0;
|
||||||
|
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
var image = viewer.world.getItemAt(0);
|
||||||
|
var contentSize = image.getContentSize();
|
||||||
|
equal(contentSize.x, 500, 'contentSize.x');
|
||||||
|
equal(contentSize.y, 2000, 'contentSize.y');
|
||||||
|
|
||||||
|
checkBounds(image, new OpenSeadragon.Rect(5, 6, 10, 40), 'initial bounds');
|
||||||
|
|
||||||
|
var scale = image.getContentSize().x / image.getBounds().width;
|
||||||
|
var viewportPoint = new OpenSeadragon.Point(10, 11);
|
||||||
|
var imagePoint = viewportPoint.minus(image.getBounds().getTopLeft()).times(scale);
|
||||||
|
|
||||||
|
propEqual(image.viewportToImageCoordinates(viewportPoint), imagePoint, 'viewportToImageCoordinates');
|
||||||
|
propEqual(image.imageToViewportCoordinates(imagePoint), viewportPoint, 'imageToViewportCoordinates');
|
||||||
|
|
||||||
|
var viewportRect = new OpenSeadragon.Rect(viewportPoint.x, viewportPoint.y, 6, 7);
|
||||||
|
var imageRect = new OpenSeadragon.Rect(imagePoint.x, imagePoint.y,
|
||||||
|
viewportRect.width * scale, viewportRect.height * scale);
|
||||||
|
|
||||||
|
propEqual(image.viewportToImageRectangle(viewportRect), imageRect, 'viewportToImageRectangle');
|
||||||
|
propEqual(image.imageToViewportRectangle(imageRect), viewportRect, 'imageToViewportRectangle');
|
||||||
|
|
||||||
|
image.addHandler('bounds-change', function boundsChangeHandler(event) {
|
||||||
|
image.removeHandler('bounds-change', boundsChangeHandler);
|
||||||
|
handlerCount++;
|
||||||
|
});
|
||||||
|
|
||||||
|
image.setPosition(new OpenSeadragon.Point(7, 8));
|
||||||
|
checkBounds(image, new OpenSeadragon.Rect(7, 8, 10, 40), 'bounds after position');
|
||||||
|
|
||||||
|
image.setWidth(5);
|
||||||
|
checkBounds(image, new OpenSeadragon.Rect(7, 8, 5, 20), 'bounds after width');
|
||||||
|
|
||||||
|
image.setHeight(4);
|
||||||
|
checkBounds(image, new OpenSeadragon.Rect(7, 8, 1, 4), 'bounds after width');
|
||||||
|
|
||||||
|
equal(handlerCount, 1, 'correct number of handlers called');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.open({
|
||||||
|
tileSource: '/test/data/tall.dzi',
|
||||||
|
x: 5,
|
||||||
|
y: 6,
|
||||||
|
width: 10
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('animation', function() {
|
||||||
|
viewer.addHandler("open", function () {
|
||||||
|
var image = viewer.world.getItemAt(0);
|
||||||
|
propEqual(image.getBounds(), new OpenSeadragon.Rect(0, 0, 1, 1), 'target bounds on open');
|
||||||
|
propEqual(image.getBounds(true), new OpenSeadragon.Rect(0, 0, 1, 1), 'current bounds on open');
|
||||||
|
|
||||||
|
image.setPosition(new OpenSeadragon.Point(1, 2));
|
||||||
|
propEqual(image.getBounds(), new OpenSeadragon.Rect(1, 2, 1, 1), 'target bounds after position');
|
||||||
|
propEqual(image.getBounds(true), new OpenSeadragon.Rect(0, 0, 1, 1), 'current bounds after position');
|
||||||
|
|
||||||
|
image.setWidth(3);
|
||||||
|
propEqual(image.getBounds(), new OpenSeadragon.Rect(1, 2, 3, 3), 'target bounds after width');
|
||||||
|
propEqual(image.getBounds(true), new OpenSeadragon.Rect(0, 0, 1, 1), 'current bounds after width');
|
||||||
|
|
||||||
|
viewer.addHandler('animation-finish', function animationHandler() {
|
||||||
|
viewer.removeHandler('animation-finish', animationHandler);
|
||||||
|
propEqual(image.getBounds(), new OpenSeadragon.Rect(1, 2, 3, 3), 'target bounds after animation');
|
||||||
|
propEqual(image.getBounds(true), new OpenSeadragon.Rect(1, 2, 3, 3), 'current bounds after animation');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.open('/test/data/testpattern.dzi');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('update', function() {
|
||||||
|
var handlerCount = 0;
|
||||||
|
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
var image = viewer.world.getItemAt(0);
|
||||||
|
equal(image.needsDraw(), true, 'needs draw after open');
|
||||||
|
|
||||||
|
viewer.addHandler('update-level', function updateLevelHandler(event) {
|
||||||
|
viewer.removeHandler('update-level', updateLevelHandler);
|
||||||
|
handlerCount++;
|
||||||
|
equal(event.eventSource, viewer, 'sender of update-level event was viewer');
|
||||||
|
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
|
||||||
|
ok('havedrawn' in event, 'update-level event includes havedrawn');
|
||||||
|
ok('level' in event, 'update-level event includes level');
|
||||||
|
ok('opacity' in event, 'update-level event includes opacity');
|
||||||
|
ok('visibility' in event, 'update-level event includes visibility');
|
||||||
|
ok('topleft' in event, 'update-level event includes topleft');
|
||||||
|
ok('bottomright' in event, 'update-level event includes bottomright');
|
||||||
|
ok('currenttime' in event, 'update-level event includes currenttime');
|
||||||
|
ok('best' in event, 'update-level event includes best');
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.addHandler('update-tile', function updateTileHandler(event) {
|
||||||
|
viewer.removeHandler('update-tile', updateTileHandler);
|
||||||
|
handlerCount++;
|
||||||
|
equal(event.eventSource, viewer, 'sender of update-tile event was viewer');
|
||||||
|
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
|
||||||
|
ok(event.tile, 'update-tile event includes tile');
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.addHandler('tile-drawing', function tileDrawingHandler(event) {
|
||||||
|
viewer.removeHandler('tile-drawing', tileDrawingHandler);
|
||||||
|
handlerCount++;
|
||||||
|
equal(event.eventSource, viewer, 'sender of tile-drawing event was viewer');
|
||||||
|
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
|
||||||
|
ok(event.tile, 'tile-drawing event includes a tile');
|
||||||
|
ok(event.context, 'tile-drawing event includes a context');
|
||||||
|
ok(event.rendered, 'tile-drawing event includes a rendered');
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.addHandler('tile-drawn', function tileDrawnHandler(event) {
|
||||||
|
viewer.removeHandler('tile-drawn', tileDrawnHandler);
|
||||||
|
handlerCount++;
|
||||||
|
equal(event.eventSource, viewer, 'sender of tile-drawn event was viewer');
|
||||||
|
equal(event.tiledImage, image, 'tiledImage of update-level event is correct');
|
||||||
|
ok(event.tile, 'tile-drawn event includes tile');
|
||||||
|
|
||||||
|
equal(handlerCount, 4, 'correct number of handlers called');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
image.draw();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.open('/test/data/testpattern.dzi');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('reset', function() {
|
||||||
|
viewer.addHandler('tile-drawn', function updateHandler() {
|
||||||
|
viewer.removeHandler('tile-drawn', updateHandler);
|
||||||
|
ok(viewer.tileCache.numTilesLoaded() > 0, 'we have tiles after tile-drawn');
|
||||||
|
viewer.world.getItemAt(0).reset();
|
||||||
|
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles after reset');
|
||||||
|
|
||||||
|
viewer.addHandler('tile-drawn', function updateHandler2() {
|
||||||
|
viewer.removeHandler('tile-drawn', updateHandler2);
|
||||||
|
ok(viewer.tileCache.numTilesLoaded() > 0, 'more tiles load');
|
||||||
|
viewer.world.getItemAt(0).destroy();
|
||||||
|
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles after destroy');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles at start');
|
||||||
|
|
||||||
|
viewer.open('/test/data/testpattern.dzi');
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
20
test/modules/tilesourcecollection.js
Normal file
20
test/modules/tilesourcecollection.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var viewer;
|
||||||
|
|
||||||
|
module('TileSourceCollection', {
|
||||||
|
setup: function () {
|
||||||
|
testLog.reset();
|
||||||
|
},
|
||||||
|
teardown: function () {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('deprecation', function() {
|
||||||
|
Util.testDeprecation(OpenSeadragon, 'TileSourceCollection');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -3,7 +3,7 @@
|
|||||||
(function () {
|
(function () {
|
||||||
var viewer;
|
var viewer;
|
||||||
var VIEWER_ID = "example";
|
var VIEWER_ID = "example";
|
||||||
var PREFIX_URL = "/build/openseadragon/images";
|
var PREFIX_URL = "/build/openseadragon/images/";
|
||||||
var SPRING_STIFFNESS = 100; // Faster animation = faster tests
|
var SPRING_STIFFNESS = 100; // Faster animation = faster tests
|
||||||
|
|
||||||
module("viewport", {
|
module("viewport", {
|
||||||
@ -209,7 +209,7 @@
|
|||||||
method: 'getHomeBounds',
|
method: 'getHomeBounds',
|
||||||
processExpected: function(level, expected) {
|
processExpected: function(level, expected) {
|
||||||
// Have to special case this to avoid dividing by 0
|
// Have to special case this to avoid dividing by 0
|
||||||
if(level === 0){
|
if(level === -1 || level === 0){
|
||||||
expected = new OpenSeadragon.Rect(0, 0, 1, 1);
|
expected = new OpenSeadragon.Rect(0, 0, 1, 1);
|
||||||
} else {
|
} else {
|
||||||
var sideLength = 1.0 / viewer.defaultZoomLevel; // it's a square in this case
|
var sideLength = 1.0 / viewer.defaultZoomLevel; // it's a square in this case
|
||||||
@ -245,8 +245,10 @@
|
|||||||
viewport.zoomTo(ZOOM_FACTOR, null, true);
|
viewport.zoomTo(ZOOM_FACTOR, null, true);
|
||||||
viewport.update(); // need to call this even with immediately=true
|
viewport.update(); // need to call this even with immediately=true
|
||||||
|
|
||||||
// If the default zoom level is set to 0, then we expect the home zoom to be 1.
|
// Special cases for oddball levels
|
||||||
if(level === 0){
|
if (level === -1) {
|
||||||
|
expected = 0.25;
|
||||||
|
} else if(level === 0){
|
||||||
expected = 1;
|
expected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,11 +287,11 @@
|
|||||||
|
|
||||||
for(var i = 0; i < testRects.length; i++){
|
for(var i = 0; i < testRects.length; i++){
|
||||||
var rect = testRects[i].times(viewport.getContainerSize());
|
var rect = testRects[i].times(viewport.getContainerSize());
|
||||||
viewport.resetContentSize(rect);
|
viewport.resetContentSize(rect.getSize());
|
||||||
viewport.update();
|
viewport.update();
|
||||||
propEqual(
|
propEqual(
|
||||||
viewport.contentSize,
|
viewport.contentSize,
|
||||||
rect,
|
rect.getSize(),
|
||||||
"Reset content size correctly."
|
"Reset content size correctly."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -407,7 +409,7 @@
|
|||||||
viewport.update();
|
viewport.update();
|
||||||
propEqual(
|
propEqual(
|
||||||
viewport.getBounds(),
|
viewport.getBounds(),
|
||||||
new OpenSeadragon.Rect(-1.5,0,4,4),
|
new OpenSeadragon.Rect(0, 1.5, 1, 1),
|
||||||
"Viewport fit a tall image horizontally."
|
"Viewport fit a tall image horizontally."
|
||||||
);
|
);
|
||||||
start();
|
start();
|
||||||
@ -424,7 +426,7 @@
|
|||||||
viewport.update();
|
viewport.update();
|
||||||
propEqual(
|
propEqual(
|
||||||
viewport.getBounds(),
|
viewport.getBounds(),
|
||||||
new OpenSeadragon.Rect(0,0,0.25,0.25),
|
new OpenSeadragon.Rect(0.375, 0, 0.25, 0.25),
|
||||||
"Viewport fit a wide image vertically."
|
"Viewport fit a wide image vertically."
|
||||||
);
|
);
|
||||||
start();
|
start();
|
||||||
@ -719,9 +721,7 @@
|
|||||||
return el.times(window_boundary);
|
return el.times(window_boundary);
|
||||||
},
|
},
|
||||||
getExpected: function(orig, viewport) {
|
getExpected: function(orig, viewport) {
|
||||||
var position, pos_point;
|
var pos_point = OpenSeadragon.getElementOffset(viewer.element);
|
||||||
position = viewer.element.getBoundingClientRect();
|
|
||||||
pos_point = new OpenSeadragon.Point(position.top, position.left);
|
|
||||||
return orig.minus(pos_point).divide(viewport.getContainerSize().x * ZOOM_FACTOR).plus(VIEWER_PADDING);
|
return orig.minus(pos_point).divide(viewport.getContainerSize().x * ZOOM_FACTOR).plus(VIEWER_PADDING);
|
||||||
},
|
},
|
||||||
method: 'windowToViewportCoordinates'
|
method: 'windowToViewportCoordinates'
|
||||||
@ -735,9 +735,7 @@
|
|||||||
return el.times(viewer.source.dimensions.x);
|
return el.times(viewer.source.dimensions.x);
|
||||||
},
|
},
|
||||||
getExpected: function(orig, viewport) {
|
getExpected: function(orig, viewport) {
|
||||||
var position, pos_point;
|
var pos_point = OpenSeadragon.getElementOffset(viewer.element);
|
||||||
position = viewer.element.getBoundingClientRect();
|
|
||||||
pos_point = new OpenSeadragon.Point(position.top, position.left);
|
|
||||||
return orig.plus(pos_point).minus(VIEWER_PADDING.times(viewport.getContainerSize().x * ZOOM_FACTOR));
|
return orig.plus(pos_point).minus(VIEWER_PADDING.times(viewport.getContainerSize().x * ZOOM_FACTOR));
|
||||||
},
|
},
|
||||||
method: 'imageToWindowCoordinates'
|
method: 'imageToWindowCoordinates'
|
||||||
@ -752,9 +750,7 @@
|
|||||||
return el.times(window_boundary);
|
return el.times(window_boundary);
|
||||||
},
|
},
|
||||||
getExpected: function(orig, viewport) {
|
getExpected: function(orig, viewport) {
|
||||||
var position, pos_point;
|
var pos_point = OpenSeadragon.getElementOffset(viewer.element);
|
||||||
position = viewer.element.getBoundingClientRect();
|
|
||||||
pos_point = new OpenSeadragon.Point(position.top, position.left);
|
|
||||||
return orig.minus(pos_point).divide(viewport.getContainerSize().x * ZOOM_FACTOR).plus(VIEWER_PADDING);
|
return orig.minus(pos_point).divide(viewport.getContainerSize().x * ZOOM_FACTOR).plus(VIEWER_PADDING);
|
||||||
},
|
},
|
||||||
method: 'windowToViewportCoordinates'
|
method: 'windowToViewportCoordinates'
|
||||||
@ -768,9 +764,7 @@
|
|||||||
return el.times(viewer.source.dimensions.x);
|
return el.times(viewer.source.dimensions.x);
|
||||||
},
|
},
|
||||||
getExpected: function(orig, viewport) {
|
getExpected: function(orig, viewport) {
|
||||||
var position, pos_point;
|
var pos_point = OpenSeadragon.getElementOffset(viewer.element);
|
||||||
position = viewer.element.getBoundingClientRect();
|
|
||||||
pos_point = new OpenSeadragon.Point(position.top, position.left);
|
|
||||||
return orig.minus(VIEWER_PADDING).times(viewport.getContainerSize().x * ZOOM_FACTOR).plus(pos_point);
|
return orig.minus(VIEWER_PADDING).times(viewport.getContainerSize().x * ZOOM_FACTOR).plus(pos_point);
|
||||||
},
|
},
|
||||||
method: 'viewportToWindowCoordinates'
|
method: 'viewportToWindowCoordinates'
|
226
test/modules/world.js
Normal file
226
test/modules/world.js
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var viewer;
|
||||||
|
|
||||||
|
module('World', {
|
||||||
|
setup: function () {
|
||||||
|
var example = $('<div id="example"></div>').appendTo("#qunit-fixture");
|
||||||
|
|
||||||
|
testLog.reset();
|
||||||
|
|
||||||
|
viewer = OpenSeadragon({
|
||||||
|
id: 'example',
|
||||||
|
prefixUrl: '/build/openseadragon/images/',
|
||||||
|
springStiffness: 100 // Faster animation = faster tests
|
||||||
|
});
|
||||||
|
},
|
||||||
|
teardown: function () {
|
||||||
|
if (viewer && viewer.close) {
|
||||||
|
viewer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
viewer = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
var checkBounds = function(expected, message) {
|
||||||
|
var bounds = viewer.world.getHomeBounds();
|
||||||
|
ok(bounds.equals(expected), message + ' ' + bounds.toString());
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('adding a tiled image', function() {
|
||||||
|
ok(viewer.world, 'World exists');
|
||||||
|
|
||||||
|
viewer.world.addHandler('add-item', function(event) {
|
||||||
|
ok(event, 'add-item handler received event data');
|
||||||
|
equal(event.eventSource, viewer.world, 'sender of add-item event was world');
|
||||||
|
ok(event.item, 'add-item event includes item');
|
||||||
|
equal(viewer.world.getItemCount(), 1, 'there is now 1 item');
|
||||||
|
equal(event.item, viewer.world.getItemAt(0), 'item is accessible via getItemAt');
|
||||||
|
equal(viewer.world.getIndexOfItem(event.item), 0, 'item index is 0');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(viewer.world.getItemCount(), 0, 'no items to start with');
|
||||||
|
|
||||||
|
viewer.open('/test/data/testpattern.dzi');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('metrics', function() {
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 4, 4), 'bounds after open');
|
||||||
|
|
||||||
|
var expectedContentFactor = viewer.world.getItemAt(1).getContentSize().x / 2;
|
||||||
|
equal(viewer.world.getContentFactor(), expectedContentFactor, 'content factor has changed');
|
||||||
|
|
||||||
|
viewer.world.addHandler('metrics-change', function metricsChangeHandler(event) {
|
||||||
|
viewer.world.removeHandler('metrics-change', metricsChangeHandler);
|
||||||
|
ok(event, 'metrics-change handler received event data');
|
||||||
|
equal(event.eventSource, viewer.world, 'sender of metrics-change event was world');
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 7, 12), 'bounds after position');
|
||||||
|
viewer.world.getItemAt(0).setWidth(20);
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 20, 20), 'bounds after size');
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.getItemAt(1).setPosition(new OpenSeadragon.Point(5, 10));
|
||||||
|
});
|
||||||
|
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 1, 1), 'default bounds');
|
||||||
|
equal(viewer.world.getContentFactor(), 1, 'default content factor');
|
||||||
|
|
||||||
|
viewer.open([
|
||||||
|
{
|
||||||
|
tileSource: '/test/data/testpattern.dzi',
|
||||||
|
width: 4
|
||||||
|
}, {
|
||||||
|
tileSource: '/test/data/testpattern.dzi',
|
||||||
|
width: 2
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('remove/reorder tiled images', function() {
|
||||||
|
var handlerCount = 0;
|
||||||
|
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
equal(viewer.world.getItemCount(), 3, 'there are now 3 items');
|
||||||
|
var item0 = viewer.world.getItemAt(0);
|
||||||
|
var item1 = viewer.world.getItemAt(1);
|
||||||
|
|
||||||
|
viewer.world.addHandler('item-index-change', function(event) {
|
||||||
|
handlerCount++;
|
||||||
|
ok(event, 'item-index-change handler received event data');
|
||||||
|
equal(event.eventSource, viewer.world, 'sender of item-index-change event was world');
|
||||||
|
equal(event.item, item0, 'item-index-change event includes correct item');
|
||||||
|
equal(event.newIndex, 1, 'item-index-change event includes correct newIndex');
|
||||||
|
equal(event.previousIndex, 0, 'item-index-change event includes correct previousIndex');
|
||||||
|
equal(viewer.world.getItemAt(0), item1, 'item1 is now at index 0');
|
||||||
|
equal(viewer.world.getItemAt(1), item0, 'item0 is now at index 1');
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.setItemIndex(item0, 1);
|
||||||
|
|
||||||
|
viewer.world.addHandler('remove-item', function removeHandler(event) {
|
||||||
|
viewer.world.removeHandler('remove-item', removeHandler);
|
||||||
|
handlerCount++;
|
||||||
|
ok(event, 'remove-item handler received event data');
|
||||||
|
equal(event.eventSource, viewer.world, 'sender of remove-item event was world');
|
||||||
|
equal(event.item, item1, 'remove-item event includes correct item');
|
||||||
|
equal(viewer.world.getItemCount(), 2, 'after removal, only two items remain');
|
||||||
|
equal(viewer.world.getItemAt(0), item0, 'item0 is now at index 0');
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.removeItem(item1);
|
||||||
|
|
||||||
|
var removeCount = 0;
|
||||||
|
viewer.world.addHandler('remove-item', function() {
|
||||||
|
removeCount++;
|
||||||
|
if (removeCount === 2) {
|
||||||
|
handlerCount++;
|
||||||
|
equal(viewer.world.getItemCount(), 0, 'after removeAll, no items remain');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.removeAll();
|
||||||
|
|
||||||
|
equal(handlerCount, 3, 'correct number of handlers called');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(viewer.world.getItemCount(), 0, 'no items to start with');
|
||||||
|
|
||||||
|
viewer.open([
|
||||||
|
'/test/data/testpattern.dzi',
|
||||||
|
'/test/data/testpattern.dzi',
|
||||||
|
'/test/data/testpattern.dzi'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('draw', function() {
|
||||||
|
var handlerCount = 0;
|
||||||
|
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
equal(viewer.world.needsDraw(), true, 'needs draw after open');
|
||||||
|
|
||||||
|
viewer.addHandler('update-level', function updateHandler() {
|
||||||
|
viewer.removeHandler('update-level', updateHandler);
|
||||||
|
handlerCount++;
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.world.draw();
|
||||||
|
|
||||||
|
equal(handlerCount, 1, 'correct number of handlers called');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(viewer.world.needsDraw(), false, 'needs no draw at first');
|
||||||
|
|
||||||
|
viewer.open('/test/data/testpattern.dzi');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('resetItems', function() {
|
||||||
|
viewer.addHandler('tile-drawn', function updateHandler() {
|
||||||
|
viewer.removeHandler('tile-drawn', updateHandler);
|
||||||
|
ok(viewer.tileCache.numTilesLoaded() > 0, 'we have tiles after tile-drawn');
|
||||||
|
viewer.world.resetItems();
|
||||||
|
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles after reset');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles at start');
|
||||||
|
|
||||||
|
viewer.open('/test/data/testpattern.dzi');
|
||||||
|
});
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
asyncTest('arrange', function() {
|
||||||
|
viewer.addHandler('open', function(event) {
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 1, 1), 'all stacked');
|
||||||
|
|
||||||
|
viewer.world.arrange({
|
||||||
|
layout: 'horizontal',
|
||||||
|
rows: 1,
|
||||||
|
tileSize: 1,
|
||||||
|
tileMargin: 0.5
|
||||||
|
});
|
||||||
|
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 4, 1), 'one horizontal row');
|
||||||
|
|
||||||
|
viewer.world.arrange({
|
||||||
|
layout: 'horizontal',
|
||||||
|
rows: 2,
|
||||||
|
tileSize: 1,
|
||||||
|
tileMargin: 0.5
|
||||||
|
});
|
||||||
|
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 2.5, 2.5), 'grid');
|
||||||
|
|
||||||
|
viewer.world.arrange({
|
||||||
|
layout: 'vertical',
|
||||||
|
rows: 1,
|
||||||
|
tileSize: 1,
|
||||||
|
tileMargin: 0.5
|
||||||
|
});
|
||||||
|
|
||||||
|
checkBounds(new OpenSeadragon.Rect(0, 0, 1, 4), 'one vertical column');
|
||||||
|
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
viewer.open([
|
||||||
|
'/test/data/testpattern.dzi',
|
||||||
|
'/test/data/testpattern.dzi',
|
||||||
|
'/test/data/testpattern.dzi'
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
})();
|
@ -5,7 +5,7 @@
|
|||||||
<title>OpenSeadragon QUnit</title>
|
<title>OpenSeadragon QUnit</title>
|
||||||
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css">
|
<link rel="stylesheet" href="/node_modules/qunitjs/qunit/qunit.css">
|
||||||
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
|
<link rel="stylesheet" href="/test/lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
|
||||||
<link rel="stylesheet" href="/test/test.css">
|
<link rel="stylesheet" href="/test/helpers/test.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="qunit"></div>
|
<div id="qunit"></div>
|
||||||
@ -14,23 +14,31 @@
|
|||||||
<script src="/test/lib/jquery-1.9.1.min.js"></script>
|
<script src="/test/lib/jquery-1.9.1.min.js"></script>
|
||||||
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
|
<script src="/test/lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js"></script>
|
||||||
<script src="/test/lib/jquery.simulate.js"></script>
|
<script src="/test/lib/jquery.simulate.js"></script>
|
||||||
<script src="/build/openseadragon/openseadragon.min.js"></script>
|
<script src="/build/openseadragon/openseadragon.js"></script>
|
||||||
<script src="/test/legacy.mouse.shim.js"></script>
|
<script src="/test/helpers/legacy.mouse.shim.js"></script>
|
||||||
<script src="/test/test.js"></script>
|
<script src="/test/helpers/test.js"></script>
|
||||||
|
|
||||||
<!-- Polyfill must be inserted first because it is testing functions
|
<!-- Polyfill must be inserted first because it is testing functions
|
||||||
reassignments which could be done by other test. -->
|
reassignments which could be done by other test. -->
|
||||||
<script src="/test/polyfills.js"></script>
|
<script src="/test/modules/polyfills.js"></script>
|
||||||
<script src="/test/basic.js"></script>
|
<script src="/test/modules/basic.js"></script>
|
||||||
<script src="/test/navigator.js"></script>
|
<script src="/test/modules/strings.js"></script>
|
||||||
<script src="/test/strings.js"></script>
|
<script src="/test/modules/formats.js"></script>
|
||||||
<script src="/test/formats.js"></script>
|
<script src="/test/modules/utils.js"></script>
|
||||||
<script src="/test/utils.js"></script>
|
<script src="/test/modules/events.js"></script>
|
||||||
<script src="/test/events.js"></script>
|
<script src="/test/modules/units.js"></script>
|
||||||
<script src="/test/units.js"></script>
|
<script src="/test/modules/multi-image.js"></script>
|
||||||
<script src="/test/layers.js"></script>
|
<script src="/test/modules/overlays.js"></script>
|
||||||
<script src="/test/overlays.js"></script>
|
<script src="/test/modules/controls.js"></script>
|
||||||
<script src="/test/controls.js"></script>
|
<script src="/test/modules/viewport.js"></script>
|
||||||
<script src="/test/viewport.js"></script>
|
<script src="/test/modules/world.js"></script>
|
||||||
|
<script src="/test/modules/drawer.js"></script>
|
||||||
|
<script src="/test/modules/tiledimage.js"></script>
|
||||||
|
<script src="/test/modules/tilecache.js"></script>
|
||||||
|
<script src="/test/modules/referencestrip.js"></script>
|
||||||
|
<script src="/test/modules/tilesourcecollection.js"></script>
|
||||||
|
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||||
|
so we put them last. -->
|
||||||
|
<script src="/test/modules/navigator.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user