mirror of
https://github.com/openseadragon/openseadragon.git
synced 2025-02-21 01:03:14 +03:00
commit
55cc86e040
15
.editorconfig
Normal file
15
.editorconfig
Normal file
@ -0,0 +1,15 @@
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
# We need to specify each folder specifically to avoid including test/lib and test/data
|
||||
[{Gruntfile.js,src/**,test/*,test/demo/**,test/helpers/**,test/modules/**}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[{package.json,.travis.yml,.jshintrc}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
22
.jshintrc
22
.jshintrc
@ -1,14 +1,14 @@
|
||||
{
|
||||
"browser": true,
|
||||
"curly": true,
|
||||
"eqeqeq": false,
|
||||
"loopfunc": false,
|
||||
"noarg": true,
|
||||
"trailing": true,
|
||||
"undef": true,
|
||||
"unused": false,
|
||||
"browser": true,
|
||||
"curly": true,
|
||||
"eqeqeq": false,
|
||||
"loopfunc": false,
|
||||
"noarg": true,
|
||||
"trailing": true,
|
||||
"undef": true,
|
||||
"unused": false,
|
||||
|
||||
"globals": {
|
||||
"OpenSeadragon": true
|
||||
}
|
||||
"globals": {
|
||||
"OpenSeadragon": true
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ The report shows up at `coverage/html/index.html` viewable in a browser.
|
||||
|
||||
OpenSeadragon is truly a community project; we welcome your involvement!
|
||||
|
||||
When contributing, please attempt to match the code style already in the codebase. Note that we use four spaces per indentation stop. For more thoughts on code style, see https://github.com/rwldrn/idiomatic.js/.
|
||||
When contributing, please attempt to match the code style already in the codebase. Note that we use four spaces per indentation stop. For easier setup you can also install [EditorConfig](http://editorconfig.org/) if your IDE is supported. For more thoughts on code style, see [idiomatic.js](https://github.com/rwldrn/idiomatic.js/).
|
||||
|
||||
When fixing bugs and adding features, when appropriate please also:
|
||||
|
||||
@ -86,6 +86,6 @@ If you're new to open source in general, check out [GitHub's open source intro g
|
||||
|
||||
## License
|
||||
|
||||
OpenSeadragon is released under the New BSD license. For details, see the file LICENSE.txt.
|
||||
OpenSeadragon is released under the New BSD license. For details, see the file LICENSE.txt.
|
||||
|
||||
[](http://travis-ci.org/openseadragon/openseadragon)
|
||||
|
@ -1,7 +1,28 @@
|
||||
OPENSEADRAGON CHANGELOG
|
||||
=======================
|
||||
|
||||
1.3.0: (in progress)
|
||||
2.1.0: (in progress)
|
||||
* BREAKING CHANGE: the tile does not hold a reference to its image anymore. Only the tile cache keep a reference to images.
|
||||
* DEPRECATION: let ImageRecord.getRenderedContext create the rendered context instead of using ImageRecord.setRenderedContext
|
||||
* DEPRECATION: TileSource.getTileSize is deprecated. Use TileSource.getTileWidth and TileSource.getTileHeight instead.
|
||||
* Added "tile-loaded" event on the viewer allowing to modify a tile before it is marked ready to be drawn (#659)
|
||||
* Added "tile-unloaded" event on the viewer allowing to free up memory one has allocated on a tile (#659)
|
||||
* Fixed flickering tiles with useCanvas=false when no cache is used (#661)
|
||||
* Added additional coordinates conversion methods to TiledImage (#662)
|
||||
* 'display: none' no longer gets reset on overlays during draw (#668)
|
||||
* Added `preserveImageSizeOnResize` option (#666)
|
||||
* Better error reporting for tile load failures (#679)
|
||||
* Added collectionColumns as a configuration parameter (#680)
|
||||
* Added support for non-square tiles (#673)
|
||||
* TileSource.Options objects can now optionally provide tileWidth/tileHeight instead of tileSize for non-square tile support.
|
||||
* IIIFTileSources will now respect non-square tiles if available.
|
||||
* Added XDomainRequest as fallback method for ajax requests if XMLHttpRequest fails (for IE < 10) (#693)
|
||||
* Now avoiding using eval when JSON.parse is available (#696)
|
||||
* Rotation now works properly on retina display (#708)
|
||||
* Added option in addTiledImage to replace tiledImage at index (#706)
|
||||
* Changed resize behaviour to prevent "snapping" to world bounds when constraints allow more space (#711)
|
||||
|
||||
2.0.0:
|
||||
|
||||
* 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
|
||||
@ -37,6 +58,8 @@ OPENSEADRAGON CHANGELOG
|
||||
* Viewport.open supports positioning config properties
|
||||
* For multi-image open, drawing isn't started until all tileSources have been opened
|
||||
* You can specify a clip area for each image (only works on browsers that support the HTML5 canvas) (#594)
|
||||
* Added placeholderFillStyle so image rectangles can be drawn even before their tiles load (#635)
|
||||
* Ability to set opacity on individual TiledImages (#644)
|
||||
* 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)
|
||||
@ -57,6 +80,8 @@ OPENSEADRAGON CHANGELOG
|
||||
* Fixed: Cross Origin policy not working (#613)
|
||||
* Optimized tile loading by clearing the queue on a re-draw when imageLoaderLimit is set (#616)
|
||||
* Now animating zoom spring exponentially (#631)
|
||||
* Added http://editorconfig.org/ config file (#637)
|
||||
* Keyboard pan speed is now the same regardless of zoom level (#645)
|
||||
|
||||
1.2.1:
|
||||
|
||||
|
16
package.json
16
package.json
@ -1,20 +1,20 @@
|
||||
{
|
||||
"name": "OpenSeadragon",
|
||||
"version": "1.2.1",
|
||||
"version": "2.0.0",
|
||||
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
|
||||
"devDependencies": {
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-contrib-clean": "^0.5.0",
|
||||
"grunt-text-replace": "^0.3.11",
|
||||
"grunt-contrib-compress": "^0.9.1",
|
||||
"grunt-contrib-concat": "^0.4.0",
|
||||
"grunt-git-describe": "^2.3.2",
|
||||
"grunt-contrib-connect": "^0.7.1",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-uglify": "^0.4.0",
|
||||
"grunt-contrib-watch": "^0.6.1",
|
||||
"grunt-contrib-jshint": "^0.10.0",
|
||||
"grunt-contrib-compress": "^0.9.1",
|
||||
"grunt-contrib-connect": "^0.7.1",
|
||||
"qunitjs": "^1.14.0",
|
||||
"grunt-qunit-istanbul": "^0.4.5"
|
||||
"grunt-git-describe": "^2.3.2",
|
||||
"grunt-qunit-istanbul": "^0.5.0",
|
||||
"grunt-text-replace": "^0.3.11",
|
||||
"qunitjs": "^1.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "grunt test"
|
||||
|
@ -68,7 +68,7 @@ $.ButtonGroup = function( options ) {
|
||||
*/
|
||||
this.element = options.element || $.makeNeutralElement( "div" );
|
||||
|
||||
// TODO What if there IS an options.group specified?
|
||||
// TODO What if there IS an options.group specified?
|
||||
if( !options.group ){
|
||||
this.label = $.makeNeutralElement( "label" );
|
||||
//TODO: support labels for ButtonGroups
|
||||
|
346
src/drawer.js
346
src/drawer.js
@ -42,11 +42,9 @@
|
||||
* @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer.
|
||||
* @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport.
|
||||
* @param {Element} options.element - Parent element.
|
||||
* @param {Number} [options.opacity=1] - See opacity in {@link OpenSeadragon.Options} for details.
|
||||
* @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details.
|
||||
*/
|
||||
$.Drawer = function( options ) {
|
||||
var _this = this;
|
||||
|
||||
$.console.assert( options.viewer, "[Drawer] options.viewer is required" );
|
||||
|
||||
@ -72,7 +70,9 @@ $.Drawer = function( options ) {
|
||||
this.viewer = options.viewer;
|
||||
this.viewport = options.viewport;
|
||||
this.debugGridColor = options.debugGridColor || $.DEFAULT_SETTINGS.debugGridColor;
|
||||
this.opacity = options.opacity === undefined ? $.DEFAULT_SETTINGS.opacity : options.opacity;
|
||||
if (options.opacity) {
|
||||
$.console.error( "[Drawer] options.opacity is no longer accepted; set the opacity on the TiledImage instead" );
|
||||
}
|
||||
|
||||
this.useCanvas = $.supportsCanvas && ( this.viewer ? this.viewer.useCanvas : true );
|
||||
/**
|
||||
@ -96,6 +96,13 @@ $.Drawer = function( options ) {
|
||||
*/
|
||||
this.context = this.useCanvas ? this.canvas.getContext( "2d" ) : null;
|
||||
|
||||
/**
|
||||
* Sketch canvas used to temporarily draw tiles which cannot be drawn directly
|
||||
* to the main canvas due to opacity. Lazily initialized.
|
||||
*/
|
||||
this.sketchCanvas = null;
|
||||
this.sketchContext = null;
|
||||
|
||||
/**
|
||||
* @member {Element} element
|
||||
* @memberof OpenSeadragon.Drawer#
|
||||
@ -160,8 +167,11 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
* @return {OpenSeadragon.Drawer} Chainable.
|
||||
*/
|
||||
setOpacity: function( opacity ) {
|
||||
this.opacity = opacity;
|
||||
$.setElementOpacity( this.canvas, this.opacity, true );
|
||||
$.console.error("drawer.setOpacity is deprecated. Use tiledImage.setOpacity instead.");
|
||||
var world = this.viewer.world;
|
||||
for (var i = 0; i < world.getItemCount(); i++) {
|
||||
world.getItemAt( i ).setOpacity( opacity );
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
@ -170,7 +180,16 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
* @returns {Number}
|
||||
*/
|
||||
getOpacity: function() {
|
||||
return this.opacity;
|
||||
$.console.error("drawer.getOpacity is deprecated. Use tiledImage.getOpacity instead.");
|
||||
var world = this.viewer.world;
|
||||
var maxOpacity = 0;
|
||||
for (var i = 0; i < world.getItemCount(); i++) {
|
||||
var opacity = world.getItemAt( i ).getOpacity();
|
||||
if ( opacity > maxOpacity ) {
|
||||
maxOpacity = opacity;
|
||||
}
|
||||
}
|
||||
return maxOpacity;
|
||||
},
|
||||
|
||||
// deprecated
|
||||
@ -214,6 +233,8 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
//force unloading of current canvas (1x1 will be gc later, trick not necessarily needed)
|
||||
this.canvas.width = 1;
|
||||
this.canvas.height = 1;
|
||||
this.sketchCanvas = null;
|
||||
this.sketchContext = null;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -227,189 +248,260 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
|
||||
this.canvas.height != viewportSize.y ) {
|
||||
this.canvas.width = viewportSize.x;
|
||||
this.canvas.height = viewportSize.y;
|
||||
if ( this.sketchCanvas !== null ) {
|
||||
this.sketchCanvas.width = this.canvas.width;
|
||||
this.sketchCanvas.height = this.canvas.height;
|
||||
}
|
||||
}
|
||||
this.context.clearRect( 0, 0, viewportSize.x, viewportSize.y );
|
||||
this._clear();
|
||||
}
|
||||
},
|
||||
|
||||
_clear: function ( useSketch ) {
|
||||
if ( !this.useCanvas ) {
|
||||
return;
|
||||
}
|
||||
var context = this._getContext( useSketch );
|
||||
var canvas = context.canvas;
|
||||
context.clearRect( 0, 0, canvas.width, canvas.height );
|
||||
},
|
||||
|
||||
/**
|
||||
* Translates from OpenSeadragon viewer rectangle to drawer rectangle.
|
||||
* @param {OpenSeadragon.Rect} rectangle - The rectangle in viewport coordinate system.
|
||||
* @return {OpenSeadragon.Rect} Rectangle in drawer coordinate system.
|
||||
*/
|
||||
viewportToDrawerRectangle: function(rectangle) {
|
||||
var topLeft = this.viewport.pixelFromPoint(rectangle.getTopLeft(), true);
|
||||
var size = this.viewport.deltaPixelsFromPoints(rectangle.getSize(), true);
|
||||
|
||||
return new $.Rect(
|
||||
topLeft.x * $.pixelDensityRatio,
|
||||
topLeft.y * $.pixelDensityRatio,
|
||||
size.x * $.pixelDensityRatio,
|
||||
size.y * $.pixelDensityRatio
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Draws the given tile.
|
||||
* @param {OpenSeadragon.Tile} tile - The tile to draw.
|
||||
* @param {Function} drawingHandler - Method for firing the drawing event if using canvas.
|
||||
* drawingHandler({context, tile, rendered})
|
||||
* @param {Boolean} useSketch - Whether to use the sketch canvas or not.
|
||||
* where <code>rendered</code> is the context with the pre-drawn image.
|
||||
*/
|
||||
drawTile: function( tile, drawingHandler ) {
|
||||
drawTile: function( tile, drawingHandler, useSketch ) {
|
||||
$.console.assert(tile, '[Drawer.drawTile] tile is required');
|
||||
$.console.assert(drawingHandler, '[Drawer.drawTile] drawingHandler is required');
|
||||
|
||||
if ( this.useCanvas ) {
|
||||
var context = this._getContext( useSketch );
|
||||
// TODO do this in a more performant way
|
||||
// specifically, don't save,rotate,restore every time we draw a tile
|
||||
if( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation( tile, this.viewport.degrees );
|
||||
tile.drawCanvas( this.context, drawingHandler );
|
||||
this._restoreRotationChanges( tile );
|
||||
this._offsetForRotation( tile, this.viewport.degrees, useSketch );
|
||||
tile.drawCanvas( context, drawingHandler );
|
||||
this._restoreRotationChanges( tile, useSketch );
|
||||
} else {
|
||||
tile.drawCanvas( this.context, drawingHandler );
|
||||
tile.drawCanvas( context, drawingHandler );
|
||||
}
|
||||
} else {
|
||||
tile.drawHTML( this.canvas );
|
||||
}
|
||||
},
|
||||
|
||||
_getContext: function( useSketch ) {
|
||||
var context = this.context;
|
||||
if ( useSketch ) {
|
||||
if (this.sketchCanvas === null) {
|
||||
this.sketchCanvas = document.createElement( "canvas" );
|
||||
this.sketchCanvas.width = this.canvas.width;
|
||||
this.sketchCanvas.height = this.canvas.height;
|
||||
this.sketchContext = this.sketchCanvas.getContext( "2d" );
|
||||
}
|
||||
context = this.sketchContext;
|
||||
}
|
||||
return context;
|
||||
},
|
||||
|
||||
// private
|
||||
saveContext: function() {
|
||||
saveContext: function( useSketch ) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._getContext( useSketch ).save();
|
||||
},
|
||||
|
||||
// private
|
||||
restoreContext: function( useSketch ) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._getContext( useSketch ).restore();
|
||||
},
|
||||
|
||||
// private
|
||||
setClip: function(rect, useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = this._getContext( useSketch );
|
||||
context.beginPath();
|
||||
context.rect(rect.x, rect.y, rect.width, rect.height);
|
||||
context.clip();
|
||||
},
|
||||
|
||||
// private
|
||||
drawRectangle: function(rect, fillStyle, useSketch) {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
var context = this._getContext( useSketch );
|
||||
context.save();
|
||||
context.fillStyle = fillStyle;
|
||||
context.fillRect(rect.x, rect.y, rect.width, rect.height);
|
||||
context.restore();
|
||||
},
|
||||
|
||||
/**
|
||||
* Blends the sketch canvas in the main canvas.
|
||||
* @param {Float} opacity The opacity of the blending.
|
||||
* @returns {undefined}
|
||||
*/
|
||||
blendSketch: function(opacity) {
|
||||
if (!this.useCanvas || !this.sketchCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.save();
|
||||
},
|
||||
|
||||
// private
|
||||
restoreContext: function() {
|
||||
if (!this.useCanvas) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.globalAlpha = opacity;
|
||||
this.context.drawImage(this.sketchCanvas, 0, 0);
|
||||
this.context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
setClip: function(rect) {
|
||||
if (!this.useCanvas) {
|
||||
drawDebugInfo: function( tile, count, i ){
|
||||
if ( !this.useCanvas ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.context.beginPath();
|
||||
this.context.rect(rect.x, rect.y, rect.width, rect.height);
|
||||
this.context.clip();
|
||||
},
|
||||
var context = this.context;
|
||||
context.save();
|
||||
context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
|
||||
context.strokeStyle = this.debugGridColor;
|
||||
context.fillStyle = this.debugGridColor;
|
||||
|
||||
// private
|
||||
drawDebugInfo: function( tile, count, i ){
|
||||
if ( this.useCanvas ) {
|
||||
this.context.save();
|
||||
this.context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
this.context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
|
||||
this.context.strokeStyle = this.debugGridColor;
|
||||
this.context.fillStyle = this.debugGridColor;
|
||||
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation( tile, this.canvas, this.context, this.viewport.degrees );
|
||||
}
|
||||
|
||||
this.context.strokeRect(
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
tile.position.y * $.pixelDensityRatio,
|
||||
tile.size.x * $.pixelDensityRatio,
|
||||
tile.size.y * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio;
|
||||
var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio;
|
||||
|
||||
// Rotate the text the right way around.
|
||||
this.context.translate( tileCenterX, tileCenterY );
|
||||
this.context.rotate( Math.PI / 180 * -this.viewport.degrees );
|
||||
this.context.translate( -tileCenterX, -tileCenterY );
|
||||
|
||||
if( tile.x === 0 && tile.y === 0 ){
|
||||
this.context.fillText(
|
||||
"Zoom: " + this.viewport.getZoom(),
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
(tile.position.y - 30) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
"Pan: " + this.viewport.getBounds().toString(),
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
(tile.position.y - 20) * $.pixelDensityRatio
|
||||
);
|
||||
}
|
||||
this.context.fillText(
|
||||
"Level: " + tile.level,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 20) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
"Column: " + tile.x,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 30) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
"Row: " + tile.y,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 40) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
"Order: " + i + " of " + count,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 50) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
"Size: " + tile.size.toString(),
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 60) * $.pixelDensityRatio
|
||||
);
|
||||
this.context.fillText(
|
||||
"Position: " + tile.position.toString(),
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 70) * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._restoreRotationChanges( tile, this.canvas, this.context );
|
||||
}
|
||||
this.context.restore();
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._offsetForRotation( tile, this.viewport.degrees );
|
||||
}
|
||||
|
||||
context.strokeRect(
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
tile.position.y * $.pixelDensityRatio,
|
||||
tile.size.x * $.pixelDensityRatio,
|
||||
tile.size.y * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
var tileCenterX = (tile.position.x + (tile.size.x / 2)) * $.pixelDensityRatio;
|
||||
var tileCenterY = (tile.position.y + (tile.size.y / 2)) * $.pixelDensityRatio;
|
||||
|
||||
// Rotate the text the right way around.
|
||||
context.translate( tileCenterX, tileCenterY );
|
||||
context.rotate( Math.PI / 180 * -this.viewport.degrees );
|
||||
context.translate( -tileCenterX, -tileCenterY );
|
||||
|
||||
if( tile.x === 0 && tile.y === 0 ){
|
||||
context.fillText(
|
||||
"Zoom: " + this.viewport.getZoom(),
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
(tile.position.y - 30) * $.pixelDensityRatio
|
||||
);
|
||||
context.fillText(
|
||||
"Pan: " + this.viewport.getBounds().toString(),
|
||||
tile.position.x * $.pixelDensityRatio,
|
||||
(tile.position.y - 20) * $.pixelDensityRatio
|
||||
);
|
||||
}
|
||||
context.fillText(
|
||||
"Level: " + tile.level,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 20) * $.pixelDensityRatio
|
||||
);
|
||||
context.fillText(
|
||||
"Column: " + tile.x,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 30) * $.pixelDensityRatio
|
||||
);
|
||||
context.fillText(
|
||||
"Row: " + tile.y,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 40) * $.pixelDensityRatio
|
||||
);
|
||||
context.fillText(
|
||||
"Order: " + i + " of " + count,
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 50) * $.pixelDensityRatio
|
||||
);
|
||||
context.fillText(
|
||||
"Size: " + tile.size.toString(),
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 60) * $.pixelDensityRatio
|
||||
);
|
||||
context.fillText(
|
||||
"Position: " + tile.position.toString(),
|
||||
(tile.position.x + 10) * $.pixelDensityRatio,
|
||||
(tile.position.y + 70) * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
if ( this.viewport.degrees !== 0 ) {
|
||||
this._restoreRotationChanges( tile );
|
||||
}
|
||||
context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
debugRect: function(rect) {
|
||||
if ( this.useCanvas ) {
|
||||
this.context.save();
|
||||
this.context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
this.context.strokeStyle = this.debugGridColor;
|
||||
this.context.fillStyle = this.debugGridColor;
|
||||
var context = this.context;
|
||||
context.save();
|
||||
context.lineWidth = 2 * $.pixelDensityRatio;
|
||||
context.strokeStyle = this.debugGridColor;
|
||||
context.fillStyle = this.debugGridColor;
|
||||
|
||||
this.context.strokeRect(
|
||||
context.strokeRect(
|
||||
rect.x * $.pixelDensityRatio,
|
||||
rect.y * $.pixelDensityRatio,
|
||||
rect.width * $.pixelDensityRatio,
|
||||
rect.height * $.pixelDensityRatio
|
||||
);
|
||||
|
||||
this.context.restore();
|
||||
context.restore();
|
||||
}
|
||||
},
|
||||
|
||||
// private
|
||||
_offsetForRotation: function( tile, degrees ){
|
||||
_offsetForRotation: function( tile, degrees, useSketch ){
|
||||
var cx = this.canvas.width / 2,
|
||||
cy = this.canvas.height / 2,
|
||||
px = tile.position.x - cx,
|
||||
py = tile.position.y - cy;
|
||||
cy = this.canvas.height / 2;
|
||||
|
||||
this.context.save();
|
||||
var context = this._getContext( useSketch );
|
||||
context.save();
|
||||
|
||||
this.context.translate(cx, cy);
|
||||
this.context.rotate( Math.PI / 180 * degrees);
|
||||
tile.position.x = px;
|
||||
tile.position.y = py;
|
||||
context.translate(cx, cy);
|
||||
context.rotate( Math.PI / 180 * degrees);
|
||||
context.translate(-cx, -cy);
|
||||
},
|
||||
|
||||
// private
|
||||
_restoreRotationChanges: function( tile ){
|
||||
var cx = this.canvas.width / 2,
|
||||
cy = this.canvas.height / 2,
|
||||
px = tile.position.x + cx,
|
||||
py = tile.position.y + cy;
|
||||
|
||||
tile.position.x = px;
|
||||
tile.position.y = py;
|
||||
|
||||
this.context.restore();
|
||||
_restoreRotationChanges: function( tile, useSketch ){
|
||||
var context = this._getContext( useSketch );
|
||||
context.restore();
|
||||
},
|
||||
|
||||
// private
|
||||
|
@ -55,14 +55,19 @@ $.IIIFTileSource = function( options ){
|
||||
options.tileSizePerScaleFactor = {};
|
||||
|
||||
// N.B. 2.0 renamed scale_factors to scaleFactors
|
||||
if ( this.tile_width ) {
|
||||
if ( this.tile_width && this.tile_height ) {
|
||||
options.tileWidth = this.tile_width;
|
||||
options.tileHeight = this.tile_height;
|
||||
} else if ( this.tile_width ) {
|
||||
options.tileSize = this.tile_width;
|
||||
} else if ( this.tile_height ) {
|
||||
options.tileSize = this.tile_height;
|
||||
} else if ( this.tiles ) {
|
||||
// Version 2.0 forwards
|
||||
if ( this.tiles.length == 1 ) {
|
||||
options.tileSize = this.tiles[0].width;
|
||||
options.tileWidth = this.tiles[0].width;
|
||||
// Use height if provided, otherwise assume square tiles and use width.
|
||||
options.tileHeight = this.tiles[0].height || this.tiles[0].width;
|
||||
this.scale_factors = this.tiles[0].scaleFactors;
|
||||
} else {
|
||||
// Multiple tile sizes at different levels
|
||||
@ -71,13 +76,15 @@ $.IIIFTileSource = function( options ){
|
||||
for (var sf = 0; sf < this.tiles[t].scaleFactors.length; sf++) {
|
||||
var scaleFactor = this.tiles[t].scaleFactors[sf];
|
||||
this.scale_factors.push(scaleFactor);
|
||||
options.tileSizePerScaleFactor[scaleFactor] = this.tiles[t].width;
|
||||
options.tileSizePerScaleFactor[scaleFactor] = {
|
||||
width: this.tiles[t].width,
|
||||
height: this.tiles[t].height || this.tiles[t].width
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// use the largest of tileOptions that is smaller than the short dimension
|
||||
|
||||
var shortDim = Math.min( this.height, this.width ),
|
||||
tileOptions = [256,512,1024],
|
||||
smallerTiles = [];
|
||||
@ -94,8 +101,6 @@ $.IIIFTileSource = function( options ){
|
||||
// If we're smaller than 256, just use the short side.
|
||||
options.tileSize = shortDim;
|
||||
}
|
||||
this.tile_width = options.tileSize; // So that 'full' gets used for
|
||||
this.tile_height = options.tileSize; // the region below
|
||||
}
|
||||
|
||||
if ( !options.maxLevel ) {
|
||||
@ -117,6 +122,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
* @param {Object|Array} data
|
||||
* @param {String} optional - url
|
||||
*/
|
||||
|
||||
supports: function( data, url ) {
|
||||
// Version 2.0 and forwards
|
||||
if (data.protocol && data.protocol == 'http://iiif.io/api/image') {
|
||||
@ -181,20 +187,34 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileSize for the given level.
|
||||
* Return the tileWidth for the given level.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
|
||||
getTileSize: function( level ){
|
||||
*/
|
||||
getTileWidth: function( level ) {
|
||||
var scaleFactor = Math.pow(2, this.maxLevel - level);
|
||||
// cache it in case any external code is going to read it directly
|
||||
|
||||
if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {
|
||||
this.tileSize = this.tileSizePerScaleFactor[scaleFactor];
|
||||
return this.tileSizePerScaleFactor[scaleFactor].width;
|
||||
}
|
||||
return this.tileSize;
|
||||
return this._tileWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileHeight for the given level.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getTileHeight: function( level ) {
|
||||
var scaleFactor = Math.pow(2, this.maxLevel - level);
|
||||
|
||||
if (this.tileSizePerScaleFactor && this.tileSizePerScaleFactor[scaleFactor]) {
|
||||
return this.tileSizePerScaleFactor[scaleFactor].height;
|
||||
}
|
||||
return this._tileHeight;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Responsible for retreiving the url which will return an image for the
|
||||
* region specified by the given x, y, and level components.
|
||||
@ -216,7 +236,8 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
levelHeight = Math.ceil( this.height * scale ),
|
||||
|
||||
//## iiif region
|
||||
tileSize,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
iiifTileSizeWidth,
|
||||
iiifTileSizeHeight,
|
||||
iiifRegion,
|
||||
@ -228,9 +249,10 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
iiifQuality,
|
||||
uri;
|
||||
|
||||
tileSize = this.getTileSize(level);
|
||||
iiifTileSizeWidth = Math.ceil( tileSize / scale );
|
||||
iiifTileSizeHeight = iiifTileSizeWidth;
|
||||
tileWidth = this.getTileWidth(level);
|
||||
tileHeight = this.getTileHeight(level);
|
||||
iiifTileSizeWidth = Math.ceil( tileWidth / scale );
|
||||
iiifTileSizeHeight = Math.ceil( tileHeight / scale );
|
||||
|
||||
if ( this['@context'].indexOf('/1.0/context.json') > -1 ||
|
||||
this['@context'].indexOf('/1.1/context.json') > -1 ||
|
||||
@ -240,7 +262,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
|
||||
iiifQuality = "default.jpg";
|
||||
}
|
||||
|
||||
if ( levelWidth < tileSize && levelHeight < tileSize ){
|
||||
if ( levelWidth < tileWidth && levelHeight < tileHeight ){
|
||||
iiifSize = levelWidth + ",";
|
||||
iiifRegion = 'full';
|
||||
} else {
|
||||
|
@ -51,6 +51,7 @@ function ImageJob ( options ) {
|
||||
}
|
||||
|
||||
ImageJob.prototype = {
|
||||
errorMsg: null,
|
||||
start: function(){
|
||||
var _this = this;
|
||||
|
||||
@ -64,10 +65,12 @@ ImageJob.prototype = {
|
||||
_this.finish( true );
|
||||
};
|
||||
this.image.onabort = this.image.onerror = function(){
|
||||
_this.errorMsg = "Image load aborted";
|
||||
_this.finish( false );
|
||||
};
|
||||
|
||||
this.jobId = window.setTimeout( function(){
|
||||
_this.errorMsg = "Image load exceeded timeout";
|
||||
_this.finish( false );
|
||||
}, this.timeout);
|
||||
|
||||
@ -173,7 +176,7 @@ function completeJob( loader, job, callback ) {
|
||||
loader.jobsInProgress++;
|
||||
}
|
||||
|
||||
callback( job.image );
|
||||
callback( job.image, job.errorMsg );
|
||||
}
|
||||
|
||||
}( OpenSeadragon ));
|
||||
|
@ -133,7 +133,7 @@
|
||||
*/
|
||||
this.element = $.getElement( options.element );
|
||||
/**
|
||||
* The number of milliseconds within which a pointer down-up event combination
|
||||
* The number of milliseconds within which a pointer down-up event combination
|
||||
* will be treated as a click gesture.
|
||||
* @member {Number} clickTimeThreshold
|
||||
* @memberof OpenSeadragon.MouseTracker#
|
||||
@ -244,7 +244,7 @@
|
||||
|
||||
// Active pointers lists. Array of GesturePointList objects, one for each pointer device type.
|
||||
// GesturePointList objects are added each time a pointer is tracked by a new pointer device type (see getActivePointersListByType()).
|
||||
// Active pointers are any pointer being tracked for this element which are in the hit-test area
|
||||
// Active pointers are any pointer being tracked for this element which are in the hit-test area
|
||||
// of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.
|
||||
activePointersLists: [],
|
||||
|
||||
@ -1032,7 +1032,7 @@
|
||||
$.MouseTracker.mousePointerId = "legacy-mouse";
|
||||
$.MouseTracker.maxTouchPoints = 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Classes and typedefs
|
||||
@ -1078,7 +1078,7 @@
|
||||
/**
|
||||
* @class GesturePointList
|
||||
* @classdesc Provides an abstraction for a set of active {@link OpenSeadragon.MouseTracker.GesturePoint|GesturePoint} objects for a given pointer device type.
|
||||
* Active pointers are any pointer being tracked for this element which are in the hit-test area
|
||||
* Active pointers are any pointer being tracked for this element which are in the hit-test area
|
||||
* of the element (for hover-capable devices) and/or have contact or a button press initiated in the element.
|
||||
* @memberof OpenSeadragon.MouseTracker
|
||||
* @param {String} type - The pointer device type: "mouse", "touch", "pen", etc.
|
||||
@ -1198,7 +1198,7 @@
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Utility functions
|
||||
@ -1282,7 +1282,7 @@
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
clearTrackedPointers( tracker );
|
||||
|
||||
delegate.tracking = true;
|
||||
@ -1694,7 +1694,7 @@
|
||||
|
||||
|
||||
/**
|
||||
* Handles 'wheel' events.
|
||||
* Handles 'wheel' events.
|
||||
* The event may be simulated by the legacy mouse wheel event handler (onMouseWheel()).
|
||||
*
|
||||
* @private
|
||||
@ -1943,7 +1943,7 @@
|
||||
handleMouseMove( tracker, event );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* This handler is attached to the window object (on the capture phase) to emulate mouse capture.
|
||||
* onMouseMove is still attached to the tracked element, so stop propagation to avoid processing twice.
|
||||
@ -2191,7 +2191,7 @@
|
||||
var i,
|
||||
touchCount = event.changedTouches.length,
|
||||
gPoints = [];
|
||||
|
||||
|
||||
for ( i = 0; i < touchCount; i++ ) {
|
||||
gPoints.push( {
|
||||
id: event.changedTouches[ i ].identifier,
|
||||
@ -2420,7 +2420,7 @@
|
||||
*/
|
||||
function startTrackingPointer( pointsList, gPoint ) {
|
||||
|
||||
// If isPrimary is not known for the pointer then set it according to our rules:
|
||||
// If isPrimary is not known for the pointer then set it according to our rules:
|
||||
// true if the first pointer in the gesture, otherwise false
|
||||
if ( !gPoint.hasOwnProperty( 'isPrimary' ) ) {
|
||||
if ( pointsList.getLength() === 0 ) {
|
||||
@ -2617,7 +2617,7 @@
|
||||
* Gesture points associated with the event.
|
||||
* @param {Number} buttonChanged
|
||||
* The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
|
||||
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
|
||||
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
|
||||
* only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
|
||||
*
|
||||
* @returns {Boolean} True if pointers should be captured to the tracked element, otherwise false.
|
||||
@ -2779,7 +2779,7 @@
|
||||
* Gesture points associated with the event.
|
||||
* @param {Number} buttonChanged
|
||||
* The button involved in the event: -1: none, 0: primary/left, 1: aux/middle, 2: secondary/right, 3: X1/back, 4: X2/forward, 5: pen eraser.
|
||||
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
|
||||
* Note on chorded button presses (a button pressed when another button is already pressed): In the W3C Pointer Events model,
|
||||
* only one pointerdown/pointerup event combo is fired. Chorded button state changes instead fire pointermove events.
|
||||
*
|
||||
* @returns {Boolean} True if pointer capture should be released from the tracked element, otherwise false.
|
||||
|
@ -108,7 +108,9 @@ $.Navigator = function( options ){
|
||||
immediateRender: true,
|
||||
blendTime: 0,
|
||||
animationTime: 0,
|
||||
autoResize: options.autoResize
|
||||
autoResize: options.autoResize,
|
||||
// prevent resizing the navigator from adding unwanted space around the image
|
||||
minZoomImageRatio: 1.0
|
||||
});
|
||||
|
||||
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
|
||||
|
@ -204,7 +204,12 @@
|
||||
* If 0, adjusts to fit viewer.
|
||||
*
|
||||
* @property {Number} [opacity=1]
|
||||
* Opacity of the drawer (1=opaque, 0=transparent)
|
||||
* Default opacity of the tiled images (1=opaque, 0=transparent)
|
||||
*
|
||||
* @property {String|CanvasGradient|CanvasPattern|Function} [placeholderFillStyle=null]
|
||||
* Draws a colored rectangle behind the tile if it is not loaded yet.
|
||||
* You can pass a CSS color value like "#FF8800".
|
||||
* When passing a function the tiledImage and canvas context are available as argument which is useful when you draw a gradient or pattern.
|
||||
*
|
||||
* @property {Number} [degrees=0]
|
||||
* Initial rotation.
|
||||
@ -236,7 +241,7 @@
|
||||
* @property {Number} [minZoomImageRatio=0.9]
|
||||
* The minimum percentage ( expressed as a number between 0 and 1 ) of
|
||||
* the viewport height or width at which the zoom out will be constrained.
|
||||
* Setting it to 0, for example will allow you to zoom out infinitly.
|
||||
* Setting it to 0, for example will allow you to zoom out infinity.
|
||||
*
|
||||
* @property {Number} [maxZoomPixelRatio=1.1]
|
||||
* The maximum ratio to allow a zoom-in to affect the highest level pixel
|
||||
@ -247,6 +252,9 @@
|
||||
* @property {Boolean} [autoResize=true]
|
||||
* Set to false to prevent polling for viewer size changes. Useful for providing custom resize behavior.
|
||||
*
|
||||
* @property {Boolean} [preserveImageSizeOnResize=false]
|
||||
* Set to true to have the image size preserved when the viewer is resized. This requires autoResize=true (default).
|
||||
*
|
||||
* @property {Number} [pixelsPerWheelLine=40]
|
||||
* For pixel-resolution scrolling devices, the number of pixels equal to one scroll line.
|
||||
*
|
||||
@ -262,7 +270,7 @@
|
||||
* Possible subproperties (Numbers, in screen coordinates): left, top, right, bottom.
|
||||
*
|
||||
* @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
|
||||
* image requests in parallel as allowed by the browsers policy.
|
||||
*
|
||||
@ -348,7 +356,7 @@
|
||||
* @property {Boolean} [showNavigator=false]
|
||||
* Set to true to make the navigator minimap appear.
|
||||
*
|
||||
* @property {Boolean} [navigatorId=navigator-GENERATED DATE]
|
||||
* @property {String} [navigatorId=navigator-GENERATED DATE]
|
||||
* The ID of a div to hold the navigator minimap.
|
||||
* If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, and navigatorTop|Left|Height|Width options will be ignored.
|
||||
* If an ID is not specified, a div element will be generated and placed on top of the main image.
|
||||
@ -551,6 +559,10 @@
|
||||
* 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 {Number} [collectionColumns=0]
|
||||
* If collectionMode is true, specifies how many columns the grid should have. Use 1 to make a line.
|
||||
* If collectionLayout is 'vertical', specifies how many rows instead. Ignored if collectionRows is not set to a falsy value.
|
||||
*
|
||||
* @property {String} [collectionLayout='horizontal']
|
||||
* If collectionMode is true, specifies whether to arrange vertically or horizontally.
|
||||
*
|
||||
@ -982,6 +994,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
||||
maxZoomPixelRatio: 1.1, //-> higher allows 'over zoom' into pixels
|
||||
pixelsPerWheelLine: 40,
|
||||
autoResize: true,
|
||||
preserveImageSizeOnResize: false, // requires autoResize=true
|
||||
|
||||
//DEFAULT CONTROL SETTINGS
|
||||
showSequenceControl: true, //SEQUENCE
|
||||
@ -1013,10 +1026,11 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
||||
navigatorRotate: true,
|
||||
|
||||
// INITIAL ROTATION
|
||||
degrees: 0,
|
||||
degrees: 0,
|
||||
|
||||
// APPEARANCE
|
||||
opacity: 1,
|
||||
opacity: 1,
|
||||
placeholderFillStyle: null,
|
||||
|
||||
//REFERENCE STRIP SETTINGS
|
||||
showReferenceStrip: false,
|
||||
@ -1029,6 +1043,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
||||
|
||||
//COLLECTION VISUALIZATION SETTINGS
|
||||
collectionRows: 3, //or columns depending on layout
|
||||
collectionColumns: 0, //columns in horizontal layout, rows in vertical layout
|
||||
collectionLayout: 'horizontal', //vertical
|
||||
collectionMode: false,
|
||||
collectionTileSize: 800,
|
||||
@ -2030,8 +2045,40 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
||||
|
||||
request.onreadystatechange = function(){};
|
||||
|
||||
if ( $.isFunction( onError ) ) {
|
||||
onError( request, e );
|
||||
if (window.XDomainRequest) { // IE9 or IE8 might as well try to use XDomainRequest
|
||||
var xdr = new XDomainRequest();
|
||||
if (xdr) {
|
||||
xdr.onload = function (e) {
|
||||
if ( $.isFunction( onSuccess ) ) {
|
||||
onSuccess({ // Faking an xhr object
|
||||
responseText: xdr.responseText,
|
||||
status: 200, // XDomainRequest doesn't support status codes, so we just fake one! :/
|
||||
statusText: 'OK'
|
||||
});
|
||||
}
|
||||
};
|
||||
xdr.onerror = function (e) {
|
||||
if ( $.isFunction ( onError ) ) {
|
||||
onError({ // Faking an xhr object
|
||||
responseText: xdr.responseText,
|
||||
status: 444, // 444 No Response
|
||||
statusText: 'An error happened. Due to an XDomainRequest deficiency we can not extract any information about this error. Upgrade your browser.'
|
||||
});
|
||||
}
|
||||
};
|
||||
try {
|
||||
xdr.open('GET', url);
|
||||
xdr.send();
|
||||
} catch (e2) {
|
||||
if ( $.isFunction( onError ) ) {
|
||||
onError( request, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( $.isFunction( onError ) ) {
|
||||
onError( request, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -2161,6 +2208,24 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
|
||||
return $.parseXml( string );
|
||||
},
|
||||
|
||||
/**
|
||||
* Parses a JSON string into a Javascript object.
|
||||
* @function
|
||||
* @param {String} string
|
||||
* @returns {Object}
|
||||
*/
|
||||
parseJSON: function(string) {
|
||||
if (window.JSON && window.JSON.parse) {
|
||||
$.parseJSON = window.JSON.parse;
|
||||
} else {
|
||||
// Should only be used by IE8 in non standards mode
|
||||
$.parseJSON = function(string) {
|
||||
/*jshint evil:true*/
|
||||
return eval('(' + string + ')');
|
||||
};
|
||||
}
|
||||
return $.parseJSON(string);
|
||||
},
|
||||
|
||||
/**
|
||||
* Reports whether the image format is supported for tiling in this
|
||||
|
@ -282,7 +282,10 @@
|
||||
style.left = position.x + "px";
|
||||
style.top = position.y + "px";
|
||||
style.position = "absolute";
|
||||
style.display = 'block';
|
||||
|
||||
if (style.display != 'none') {
|
||||
style.display = 'block';
|
||||
}
|
||||
|
||||
if ( scales ) {
|
||||
style.width = size.x + "px";
|
||||
|
39
src/tile.js
39
src/tile.js
@ -67,7 +67,7 @@ $.Tile = function(level, x, y, bounds, exists, url) {
|
||||
this.y = y;
|
||||
/**
|
||||
* Where this tile fits, in normalized coordinates
|
||||
* @member {OpenSeadragon.Point} bounds
|
||||
* @member {OpenSeadragon.Rect} bounds
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.bounds = bounds;
|
||||
@ -190,7 +190,14 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
* @param {Element} container
|
||||
*/
|
||||
drawHTML: function( container ) {
|
||||
if ( !this.loaded || !this.image ) {
|
||||
if (!this.cacheImageRecord) {
|
||||
$.console.warn(
|
||||
'[Tile.drawHTML] attempting to draw tile %s when it\'s not cached',
|
||||
this.toString());
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !this.loaded ) {
|
||||
$.console.warn(
|
||||
"Attempting to draw tile %s when it's not yet loaded.",
|
||||
this.toString()
|
||||
@ -203,8 +210,7 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
|
||||
if ( !this.element ) {
|
||||
this.element = $.makeNeutralElement( "div" );
|
||||
this.imgElement = $.makeNeutralElement( "img" );
|
||||
this.imgElement.src = this.url;
|
||||
this.imgElement = this.cacheImageRecord.getImage().cloneNode();
|
||||
this.imgElement.style.msInterpolationMode = "nearest-neighbor";
|
||||
this.imgElement.style.width = "100%";
|
||||
this.imgElement.style.height = "100%";
|
||||
@ -239,17 +245,18 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
|
||||
var position = this.position,
|
||||
size = this.size,
|
||||
rendered,
|
||||
canvas;
|
||||
rendered;
|
||||
|
||||
if (!this.cacheImageRecord) {
|
||||
$.console.warn('[Tile.drawCanvas] attempting to draw tile %s when it\'s not cached', this.toString());
|
||||
$.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) ){
|
||||
if ( !this.loaded || !rendered ){
|
||||
$.console.warn(
|
||||
"Attempting to draw tile %s when it's not yet loaded.",
|
||||
this.toString()
|
||||
@ -276,19 +283,8 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
|
||||
}
|
||||
|
||||
if(!rendered){
|
||||
canvas = document.createElement( 'canvas' );
|
||||
canvas.width = this.image.width;
|
||||
canvas.height = this.image.height;
|
||||
rendered = canvas.getContext('2d');
|
||||
rendered.drawImage( this.image, 0, 0 );
|
||||
this.cacheImageRecord.setRenderedContext(rendered);
|
||||
//since we are caching the prerendered image on a canvas
|
||||
//allow the image to not be held in memory
|
||||
this.image = null;
|
||||
}
|
||||
|
||||
// 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});
|
||||
|
||||
context.drawImage(
|
||||
@ -318,7 +314,6 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
|
||||
|
||||
this.element = null;
|
||||
this.imgElement = null;
|
||||
this.image = null;
|
||||
this.loaded = false;
|
||||
this.loading = false;
|
||||
}
|
||||
|
@ -63,10 +63,23 @@ ImageRecord.prototype = {
|
||||
},
|
||||
|
||||
getRenderedContext: function() {
|
||||
if (!this._renderedContext) {
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
canvas.width = this._image.width;
|
||||
canvas.height = this._image.height;
|
||||
this._renderedContext = canvas.getContext('2d');
|
||||
this._renderedContext.drawImage( this._image, 0, 0 );
|
||||
//since we are caching the prerendered image on a canvas
|
||||
//allow the image to not be held in memory
|
||||
this._image = null;
|
||||
}
|
||||
return this._renderedContext;
|
||||
},
|
||||
|
||||
setRenderedContext: function(renderedContext) {
|
||||
$.console.error("ImageRecord.setRenderedContext is deprecated. " +
|
||||
"The rendered context should be created by the ImageRecord " +
|
||||
"itself when calling ImageRecord.getRenderedContext.");
|
||||
this._renderedContext = renderedContext;
|
||||
},
|
||||
|
||||
@ -126,6 +139,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
* 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 {Image} options.image - The image of 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
|
||||
@ -135,7 +149,6 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
$.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;
|
||||
@ -143,8 +156,9 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
|
||||
var imageRecord = this._imagesLoaded[options.tile.url];
|
||||
if (!imageRecord) {
|
||||
$.console.assert( options.image, "[TileCache.cacheTile] options.image is required to create an ImageRecord" );
|
||||
imageRecord = this._imagesLoaded[options.tile.url] = new ImageRecord({
|
||||
image: options.tile.image
|
||||
image: options.image
|
||||
});
|
||||
|
||||
this._imagesLoadedCount++;
|
||||
@ -158,6 +172,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
if ( this._imagesLoadedCount > this._maxImageCacheCount ) {
|
||||
var worstTile = null;
|
||||
var worstTileIndex = -1;
|
||||
var worstTileRecord = null;
|
||||
var prevTile, worstTime, worstLevel, prevTime, prevLevel, prevTileRecord;
|
||||
|
||||
for ( var i = this._tilesLoaded.length - 1; i >= 0; i-- ) {
|
||||
@ -169,6 +184,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
} else if ( !worstTile ) {
|
||||
worstTile = prevTile;
|
||||
worstTileIndex = i;
|
||||
worstTileRecord = prevTileRecord;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -181,11 +197,12 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
( prevTime == worstTime && prevLevel > worstLevel ) ) {
|
||||
worstTile = prevTile;
|
||||
worstTileIndex = i;
|
||||
worstTileRecord = prevTileRecord;
|
||||
}
|
||||
}
|
||||
|
||||
if ( worstTile && worstTileIndex >= 0 ) {
|
||||
this._unloadTile(worstTile);
|
||||
this._unloadTile(worstTileRecord);
|
||||
insertionIndex = worstTileIndex;
|
||||
}
|
||||
}
|
||||
@ -206,7 +223,7 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
for ( var i = 0; i < this._tilesLoaded.length; ++i ) {
|
||||
tileRecord = this._tilesLoaded[ i ];
|
||||
if ( tileRecord.tiledImage === tiledImage ) {
|
||||
this._unloadTile(tileRecord.tile);
|
||||
this._unloadTile(tileRecord);
|
||||
this._tilesLoaded.splice( i, 1 );
|
||||
i--;
|
||||
}
|
||||
@ -220,8 +237,11 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
},
|
||||
|
||||
// private
|
||||
_unloadTile: function(tile) {
|
||||
$.console.assert(tile, '[TileCache._unloadTile] tile is required');
|
||||
_unloadTile: function(tileRecord) {
|
||||
$.console.assert(tileRecord, '[TileCache._unloadTile] tileRecord is required');
|
||||
var tile = tileRecord.tile;
|
||||
var tiledImage = tileRecord.tiledImage;
|
||||
|
||||
tile.unload();
|
||||
tile.cacheImageRecord = null;
|
||||
|
||||
@ -232,6 +252,20 @@ $.TileCache.prototype = /** @lends OpenSeadragon.TileCache.prototype */{
|
||||
delete this._imagesLoaded[tile.url];
|
||||
this._imagesLoadedCount--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when a tile has just been unloaded from memory.
|
||||
*
|
||||
* @event tile-unloaded
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
* @type {object}
|
||||
* @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the unloaded tile.
|
||||
* @property {OpenSeadragon.Tile} tile - The tile which has been unloaded.
|
||||
*/
|
||||
tiledImage.viewer.raiseEvent("tile-unloaded", {
|
||||
tile: tile,
|
||||
tiledImage: tiledImage
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -64,7 +64,9 @@
|
||||
* @param {Number} [options.blendTime] - See {@link OpenSeadragon.Options}.
|
||||
* @param {Boolean} [options.alwaysBlend] - See {@link OpenSeadragon.Options}.
|
||||
* @param {Number} [options.minPixelRatio] - See {@link OpenSeadragon.Options}.
|
||||
* @param {Number} [options.opacity=1] - Opacity the tiled image should be drawn at.
|
||||
* @param {Boolean} [options.debugMode] - See {@link OpenSeadragon.Options}.
|
||||
* @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}.
|
||||
* @param {String|Boolean} [options.crossOriginPolicy] - See {@link OpenSeadragon.Options}.
|
||||
*/
|
||||
$.TiledImage = function( options ) {
|
||||
@ -126,21 +128,23 @@ $.TiledImage = function( options ) {
|
||||
coverage: {}, // A '3d' dictionary [level][x][y] --> Boolean.
|
||||
lastDrawn: [], // An unordered list of Tiles drawn last frame.
|
||||
lastResetTime: 0, // Last time for which the tiledImage was reset.
|
||||
_midDraw: false, // Is the tiledImage currently updating the viewport?
|
||||
_needsDraw: true, // Does the tiledImage need to update the viewport again?
|
||||
_midDraw: false, // Is the tiledImage currently updating the viewport?
|
||||
_needsDraw: true, // Does the tiledImage need to update the viewport again?
|
||||
|
||||
//configurable settings
|
||||
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
|
||||
animationTime: $.DEFAULT_SETTINGS.animationTime,
|
||||
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
|
||||
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
|
||||
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
||||
immediateRender: $.DEFAULT_SETTINGS.immediateRender,
|
||||
blendTime: $.DEFAULT_SETTINGS.blendTime,
|
||||
alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,
|
||||
minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio,
|
||||
debugMode: $.DEFAULT_SETTINGS.debugMode,
|
||||
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy
|
||||
springStiffness: $.DEFAULT_SETTINGS.springStiffness,
|
||||
animationTime: $.DEFAULT_SETTINGS.animationTime,
|
||||
minZoomImageRatio: $.DEFAULT_SETTINGS.minZoomImageRatio,
|
||||
wrapHorizontal: $.DEFAULT_SETTINGS.wrapHorizontal,
|
||||
wrapVertical: $.DEFAULT_SETTINGS.wrapVertical,
|
||||
immediateRender: $.DEFAULT_SETTINGS.immediateRender,
|
||||
blendTime: $.DEFAULT_SETTINGS.blendTime,
|
||||
alwaysBlend: $.DEFAULT_SETTINGS.alwaysBlend,
|
||||
minPixelRatio: $.DEFAULT_SETTINGS.minPixelRatio,
|
||||
debugMode: $.DEFAULT_SETTINGS.debugMode,
|
||||
crossOriginPolicy: $.DEFAULT_SETTINGS.crossOriginPolicy,
|
||||
placeholderFillStyle: $.DEFAULT_SETTINGS.placeholderFillStyle,
|
||||
opacity: $.DEFAULT_SETTINGS.opacity
|
||||
|
||||
}, options );
|
||||
|
||||
@ -402,6 +406,83 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert pixel coordinates relative to the viewer element to image
|
||||
* coordinates.
|
||||
* @param {OpenSeadragon.Point} pixel
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
viewerElementToImageCoordinates: function( pixel ) {
|
||||
var point = this.viewport.pointFromPixel( pixel, true );
|
||||
return this.viewportToImageCoordinates( point );
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert pixel coordinates relative to the image to
|
||||
* viewer element coordinates.
|
||||
* @param {OpenSeadragon.Point} pixel
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
imageToViewerElementCoordinates: function( pixel ) {
|
||||
var point = this.imageToViewportCoordinates( pixel );
|
||||
return this.viewport.pixelFromPoint( point, true );
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert pixel coordinates relative to the window to image coordinates.
|
||||
* @param {OpenSeadragon.Point} pixel
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
windowToImageCoordinates: function( pixel ) {
|
||||
var viewerCoordinates = pixel.minus(
|
||||
OpenSeadragon.getElementPosition( this.viewer.element ));
|
||||
return this.viewerElementToImageCoordinates( viewerCoordinates );
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert image coordinates to pixel coordinates relative to the window.
|
||||
* @param {OpenSeadragon.Point} pixel
|
||||
* @returns {OpenSeadragon.Point}
|
||||
*/
|
||||
imageToWindowCoordinates: function( pixel ) {
|
||||
var viewerCoordinates = this.imageToViewerElementCoordinates( pixel );
|
||||
return viewerCoordinates.plus(
|
||||
OpenSeadragon.getElementPosition( this.viewer.element ));
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert a viewport zoom to an image zoom.
|
||||
* Image zoom: ratio of the original image size to displayed image size.
|
||||
* 1 means original image size, 0.5 half size...
|
||||
* 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...
|
||||
* @function
|
||||
* @param {Number} viewportZoom The viewport zoom
|
||||
* @returns {Number} imageZoom The image zoom
|
||||
*/
|
||||
viewportToImageZoom: function( viewportZoom ) {
|
||||
var ratio = this._scaleSpring.current.value *
|
||||
this.viewport._containerInnerSize.x / this.source.dimensions.x;
|
||||
return ratio * viewportZoom ;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert an image zoom to a viewport zoom.
|
||||
* Image zoom: ratio of the original image size to displayed image size.
|
||||
* 1 means original image size, 0.5 half size...
|
||||
* 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...
|
||||
* Note: not accurate with multi-image.
|
||||
* @function
|
||||
* @param {Number} imageZoom The image zoom
|
||||
* @returns {Number} viewportZoom The viewport zoom
|
||||
*/
|
||||
imageToViewportZoom: function( imageZoom ) {
|
||||
var ratio = this._scaleSpring.current.value *
|
||||
this.viewport._containerInnerSize.x / this.source.dimensions.x;
|
||||
return imageZoom / ratio;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the TiledImage's position in the world.
|
||||
* @param {OpenSeadragon.Point} position - The new position, in viewport coordinates.
|
||||
@ -484,6 +565,21 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
this._needsDraw = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Number} The TiledImage's current opacity.
|
||||
*/
|
||||
getOpacity: function() {
|
||||
return this.opacity;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Number} opacity Opacity the tiled image should be drawn at.
|
||||
*/
|
||||
setOpacity: function(opacity) {
|
||||
this.opacity = opacity;
|
||||
this._needsDraw = true;
|
||||
},
|
||||
|
||||
// private
|
||||
_setScale: function(scale, immediately) {
|
||||
var sameTarget = (this._scaleSpring.target.value === scale);
|
||||
@ -696,8 +792,6 @@ function updateViewport( tiledImage ) {
|
||||
// Load the new 'best' tile
|
||||
if ( best ) {
|
||||
loadTile( tiledImage, best, currentTime );
|
||||
// because we haven't finished drawing, so
|
||||
tiledImage._needsDraw = true;
|
||||
}
|
||||
|
||||
}
|
||||
@ -843,13 +937,8 @@ function updateTile( tiledImage, drawLevel, haveDrawn, x, y, level, levelOpacity
|
||||
if (!tile.loaded) {
|
||||
var imageRecord = tiledImage._tileCache.getImageRecord(tile.url);
|
||||
if (imageRecord) {
|
||||
tile.loaded = true;
|
||||
tile.image = imageRecord.getImage();
|
||||
|
||||
tiledImage._tileCache.cacheTile({
|
||||
tile: tile,
|
||||
tiledImage: tiledImage
|
||||
});
|
||||
var image = imageRecord.getImage();
|
||||
setTileLoaded(tiledImage, tile, image);
|
||||
}
|
||||
}
|
||||
|
||||
@ -922,8 +1011,8 @@ function loadTile( tiledImage, tile, time ) {
|
||||
tiledImage._imageLoader.addJob({
|
||||
src: tile.url,
|
||||
crossOriginPolicy: tiledImage.crossOriginPolicy,
|
||||
callback: function( image ){
|
||||
onTileLoad( tiledImage, tile, time, image );
|
||||
callback: function( image, errorMsg ){
|
||||
onTileLoad( tiledImage, tile, time, image, errorMsg );
|
||||
},
|
||||
abort: function() {
|
||||
tile.loading = false;
|
||||
@ -931,9 +1020,9 @@ function loadTile( tiledImage, tile, time ) {
|
||||
});
|
||||
}
|
||||
|
||||
function onTileLoad( tiledImage, tile, time, image ) {
|
||||
function onTileLoad( tiledImage, tile, time, image, errorMsg ) {
|
||||
if ( !image ) {
|
||||
$.console.log( "Tile %s failed to load: %s", tile, tile.url );
|
||||
$.console.log( "Tile %s failed to load: %s - error: %s", tile, tile.url, errorMsg );
|
||||
if( !tiledImage.debugMode ){
|
||||
tile.loading = false;
|
||||
tile.exists = false;
|
||||
@ -946,16 +1035,9 @@ function onTileLoad( tiledImage, tile, time, image ) {
|
||||
}
|
||||
|
||||
var finish = function() {
|
||||
tile.loading = false;
|
||||
tile.loaded = true;
|
||||
tile.image = image;
|
||||
|
||||
var cutoff = Math.ceil( Math.log( tiledImage.source.getTileSize(tile.level) ) / Math.log( 2 ) );
|
||||
tiledImage._tileCache.cacheTile({
|
||||
tile: tile,
|
||||
cutoff: cutoff,
|
||||
tiledImage: tiledImage
|
||||
});
|
||||
var cutoff = Math.ceil( Math.log(
|
||||
tiledImage.source.getTileWidth(tile.level) ) / Math.log( 2 ) );
|
||||
setTileLoaded(tiledImage, tile, image, cutoff);
|
||||
};
|
||||
|
||||
// Check if we're mid-update; this can happen on IE8 because image load events for
|
||||
@ -966,10 +1048,55 @@ function onTileLoad( tiledImage, tile, time, image ) {
|
||||
// Wait until after the update, in case caching unloads any tiles
|
||||
window.setTimeout( finish, 1);
|
||||
}
|
||||
|
||||
tiledImage._needsDraw = true;
|
||||
}
|
||||
|
||||
function setTileLoaded(tiledImage, tile, image, cutoff) {
|
||||
var increment = 0;
|
||||
|
||||
function getCompletionCallback() {
|
||||
increment++;
|
||||
return completionCallback;
|
||||
}
|
||||
|
||||
function completionCallback() {
|
||||
increment--;
|
||||
if (increment === 0) {
|
||||
tile.loading = false;
|
||||
tile.loaded = true;
|
||||
tiledImage._tileCache.cacheTile({
|
||||
image: image,
|
||||
tile: tile,
|
||||
cutoff: cutoff,
|
||||
tiledImage: tiledImage
|
||||
});
|
||||
tiledImage._needsDraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when a tile has just been loaded in memory. That means that the
|
||||
* image has been downloaded and can be modified before being drawn to the canvas.
|
||||
*
|
||||
* @event tile-loaded
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
* @type {object}
|
||||
* @property {Image} image - The image of the tile.
|
||||
* @property {OpenSeadragon.TiledImage} tiledImage - The tiled image of the loaded tile.
|
||||
* @property {OpenSeadragon.Tile} tile - The tile which has been loaded.
|
||||
* @property {function} getCompletionCallback - A function giving a callback to call
|
||||
* when the asynchronous processing of the image is done. The image will be
|
||||
* marked as entirely loaded when the callback has been called once for each
|
||||
* call to getCompletionCallback.
|
||||
*/
|
||||
tiledImage.viewer.raiseEvent("tile-loaded", {
|
||||
tile: tile,
|
||||
tiledImage: tiledImage,
|
||||
image: image,
|
||||
getCompletionCallback: getCompletionCallback
|
||||
});
|
||||
// In case the completion callback is never called, we at least force it once.
|
||||
getCompletionCallback()();
|
||||
}
|
||||
|
||||
function positionTile( tile, overlap, viewport, viewportCenter, levelVisibility, tiledImage ){
|
||||
var boundsTL = tile.bounds.getTopLeft();
|
||||
@ -1148,42 +1275,49 @@ function compareTiles( previousBest, tile ) {
|
||||
return previousBest;
|
||||
}
|
||||
|
||||
function drawTiles( tiledImage, lastDrawn ){
|
||||
function drawTiles( tiledImage, lastDrawn ) {
|
||||
var i,
|
||||
tile,
|
||||
tileKey,
|
||||
viewer,
|
||||
viewport,
|
||||
position,
|
||||
tileSource;
|
||||
tile;
|
||||
|
||||
if ( tiledImage.opacity <= 0 ) {
|
||||
drawDebugInfo( tiledImage, lastDrawn );
|
||||
return;
|
||||
}
|
||||
var useSketch = tiledImage.opacity < 1;
|
||||
if ( useSketch ) {
|
||||
tiledImage._drawer._clear( true );
|
||||
}
|
||||
|
||||
var usedClip = false;
|
||||
if (tiledImage._clip) {
|
||||
tiledImage._drawer.saveContext();
|
||||
if ( tiledImage._clip ) {
|
||||
tiledImage._drawer.saveContext(useSketch);
|
||||
|
||||
var box = tiledImage.imageToViewportRectangle(tiledImage._clip, true);
|
||||
var topLeft = tiledImage.viewport.pixelFromPoint(box.getTopLeft(), true);
|
||||
var size = tiledImage.viewport.deltaPixelsFromPoints(box.getSize(), true);
|
||||
box = new OpenSeadragon.Rect(topLeft.x * $.pixelDensityRatio,
|
||||
topLeft.y * $.pixelDensityRatio,
|
||||
size.x * $.pixelDensityRatio,
|
||||
size.y * $.pixelDensityRatio);
|
||||
tiledImage._drawer.setClip(box);
|
||||
var clipRect = tiledImage._drawer.viewportToDrawerRectangle(box);
|
||||
tiledImage._drawer.setClip(clipRect, useSketch);
|
||||
|
||||
usedClip = true;
|
||||
}
|
||||
|
||||
if ( tiledImage.placeholderFillStyle && lastDrawn.length === 0 ) {
|
||||
var placeholderRect = tiledImage._drawer.viewportToDrawerRectangle(tiledImage.getBounds(true));
|
||||
|
||||
var fillStyle = null;
|
||||
if ( typeof tiledImage.placeholderFillStyle === "function" ) {
|
||||
fillStyle = tiledImage.placeholderFillStyle(tiledImage, tiledImage._drawer.context);
|
||||
}
|
||||
else {
|
||||
fillStyle = tiledImage.placeholderFillStyle;
|
||||
}
|
||||
|
||||
tiledImage._drawer.drawRectangle(placeholderRect, fillStyle, useSketch);
|
||||
}
|
||||
|
||||
for ( i = lastDrawn.length - 1; i >= 0; i-- ) {
|
||||
tile = lastDrawn[ i ];
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler );
|
||||
tiledImage._drawer.drawTile( tile, tiledImage._drawingHandler, useSketch );
|
||||
tile.beingDrawn = true;
|
||||
|
||||
if( tiledImage.debugMode ){
|
||||
try{
|
||||
tiledImage._drawer.drawDebugInfo( tile, lastDrawn.length, i );
|
||||
}catch(e){
|
||||
$.console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
if( tiledImage.viewer ){
|
||||
/**
|
||||
* <em>- Needs documentation -</em>
|
||||
@ -1203,8 +1337,26 @@ function drawTiles( tiledImage, lastDrawn ){
|
||||
}
|
||||
}
|
||||
|
||||
if (usedClip) {
|
||||
tiledImage._drawer.restoreContext();
|
||||
if ( usedClip ) {
|
||||
tiledImage._drawer.restoreContext( useSketch );
|
||||
}
|
||||
|
||||
if ( useSketch ) {
|
||||
tiledImage._drawer.blendSketch( tiledImage.opacity );
|
||||
}
|
||||
drawDebugInfo( tiledImage, lastDrawn );
|
||||
}
|
||||
|
||||
function drawDebugInfo( tiledImage, lastDrawn ) {
|
||||
if( tiledImage.debugMode ) {
|
||||
for ( var i = lastDrawn.length - 1; i >= 0; i-- ) {
|
||||
var tile = lastDrawn[ i ];
|
||||
try {
|
||||
tiledImage._drawer.drawDebugInfo( tile, lastDrawn.length, i );
|
||||
} catch(e) {
|
||||
$.console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,6 +73,11 @@
|
||||
* The size of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* Tile size determines the point at which the image pyramid must be
|
||||
* divided into a matrix of smaller images.
|
||||
* Use options.tileWidth and options.tileHeight to support non-square tiles.
|
||||
* @param {Number} [options.tileWidth]
|
||||
* The width of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* @param {Number} [options.tileHeight]
|
||||
* The height of the tiles to assumed to make up each pyramid layer in pixels.
|
||||
* @param {Number} [options.tileOverlap]
|
||||
* The number of pixels each tile is expected to overlap touching tiles.
|
||||
* @param {Number} [options.minLevel]
|
||||
@ -137,13 +142,6 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
* @member {OpenSeadragon.Point} dimensions
|
||||
* @memberof OpenSeadragon.TileSource#
|
||||
*/
|
||||
/**
|
||||
* The size of the image tiles used to compose the image.
|
||||
* Please note that tileSize may be deprecated in a future release.
|
||||
* Instead the getTileSize(level) function should be used.
|
||||
* @member {Number} tileSize
|
||||
* @memberof OpenSeadragon.TileSource#
|
||||
*/
|
||||
/**
|
||||
* The overlap in pixels each tile shares with its adjacent neighbors.
|
||||
* @member {Number} tileOverlap
|
||||
@ -174,7 +172,8 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
//async mechanism set some safe defaults first
|
||||
this.aspectRatio = 1;
|
||||
this.dimensions = new $.Point( 10, 10 );
|
||||
this.tileSize = 0;
|
||||
this._tileWidth = 0;
|
||||
this._tileHeight = 0;
|
||||
this.tileOverlap = 0;
|
||||
this.minLevel = 0;
|
||||
this.maxLevel = 0;
|
||||
@ -191,7 +190,29 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
this.aspectRatio = ( options.width && options.height ) ?
|
||||
( options.width / options.height ) : 1;
|
||||
this.dimensions = new $.Point( options.width, options.height );
|
||||
this.tileSize = options.tileSize ? options.tileSize : 0;
|
||||
|
||||
if ( this.tileSize ){
|
||||
this._tileWidth = this._tileHeight = this.tileSize;
|
||||
delete this.tileSize;
|
||||
} else {
|
||||
if( this.tileWidth ){
|
||||
// We were passed tileWidth in options, but we want to rename it
|
||||
// with a leading underscore to make clear that it is not safe to directly modify it
|
||||
this._tileWidth = this.tileWidth;
|
||||
delete this.tileWidth;
|
||||
} else {
|
||||
this._tileWidth = 0;
|
||||
}
|
||||
|
||||
if( this.tileHeight ){
|
||||
// See note above about renaming this.tileWidth
|
||||
this._tileHeight = this.tileHeight;
|
||||
delete this.tileHeight;
|
||||
} else {
|
||||
this._tileHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
this.tileOverlap = options.tileOverlap ? options.tileOverlap : 0;
|
||||
this.minLevel = options.minLevel ? options.minLevel : 0;
|
||||
this.maxLevel = ( undefined !== options.maxLevel && null !== options.maxLevel ) ?
|
||||
@ -212,16 +233,42 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
|
||||
|
||||
$.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
|
||||
getTileSize: function( level ) {
|
||||
$.console.error(
|
||||
"[TileSource.getTileSize] is deprecated." +
|
||||
"Use TileSource.getTileWidth() and TileSource.getTileHeight() instead"
|
||||
);
|
||||
return this._tileWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileSize for a given level.
|
||||
* Subclasses should override this if tileSizes can be different at different levels
|
||||
* Return the tileWidth for a given level.
|
||||
* Subclasses should override this if tileWidth can be different at different levels
|
||||
* such as in IIIFTileSource. Code should use this function rather than reading
|
||||
* from .tileSize directly. tileSize may be deprecated in a future release.
|
||||
* from ._tileWidth directly.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getTileSize: function( level ) {
|
||||
return this.tileSize;
|
||||
getTileWidth: function( level ) {
|
||||
if (!this._tileWidth) {
|
||||
return this.getTileSize(level);
|
||||
}
|
||||
return this._tileWidth;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the tileHeight for a given level.
|
||||
* Subclasses should override this if tileHeight can be different at different levels
|
||||
* such as in IIIFTileSource. Code should use this function rather than reading
|
||||
* from ._tileHeight directly.
|
||||
* @function
|
||||
* @param {Number} level
|
||||
*/
|
||||
getTileHeight: function( level ) {
|
||||
if (!this._tileHeight) {
|
||||
return this.getTileSize(level);
|
||||
}
|
||||
return this._tileHeight;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -250,8 +297,8 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
*/
|
||||
getNumTiles: function( level ) {
|
||||
var scale = this.getLevelScale( level ),
|
||||
x = Math.ceil( scale * this.dimensions.x / this.getTileSize(level) ),
|
||||
y = Math.ceil( scale * this.dimensions.y / this.getTileSize(level) );
|
||||
x = Math.ceil( scale * this.dimensions.x / this.getTileWidth(level) ),
|
||||
y = Math.ceil( scale * this.dimensions.y / this.getTileHeight(level) );
|
||||
|
||||
return new $.Point( x, y );
|
||||
},
|
||||
@ -277,10 +324,15 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
var i,
|
||||
tilesPerSide,
|
||||
tiles;
|
||||
|
||||
for( i = this.minLevel; i < this.maxLevel; i++ ){
|
||||
tiles = this.getNumTiles( i );
|
||||
tilesPerSide = Math.floor( Math.max( rect.x, rect.y ) / this.getTileSize(i) );
|
||||
if( Math.max( tiles.x, tiles.y ) + 1 >= tilesPerSide ){
|
||||
tilesPerSide = new $.Point(
|
||||
Math.floor( rect.x / this.getTileWidth(i) ),
|
||||
Math.floor( rect.y / this.getTileHeight(i) )
|
||||
);
|
||||
|
||||
if( tiles.x + 1 >= tilesPerSide.x || tiles.y + 1 >= tilesPerSide.y ){
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -293,9 +345,9 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
* @param {OpenSeadragon.Point} point
|
||||
*/
|
||||
getTileAtPoint: function( level, point ) {
|
||||
var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level ) ),
|
||||
tx = Math.floor( pixel.x / this.getTileSize(level) ),
|
||||
ty = Math.floor( pixel.y / this.getTileSize(level) );
|
||||
var pixel = point.times( this.dimensions.x ).times( this.getLevelScale(level) ),
|
||||
tx = Math.floor( pixel.x / this.getTileWidth(level) ),
|
||||
ty = Math.floor( pixel.y / this.getTileHeight(level) );
|
||||
|
||||
return new $.Point( tx, ty );
|
||||
},
|
||||
@ -308,11 +360,12 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
|
||||
*/
|
||||
getTileBounds: function( level, x, y ) {
|
||||
var dimensionsScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
tileSize = this.getTileSize(level),
|
||||
px = ( x === 0 ) ? 0 : tileSize * x - this.tileOverlap,
|
||||
py = ( y === 0 ) ? 0 : tileSize * y - this.tileOverlap,
|
||||
sx = tileSize + ( x === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
sy = tileSize + ( y === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
tileWidth = this.getTileWidth(level),
|
||||
tileHeight = this.getTileHeight(level),
|
||||
px = ( x === 0 ) ? 0 : tileWidth * x - this.tileOverlap,
|
||||
py = ( y === 0 ) ? 0 : tileHeight * y - this.tileOverlap,
|
||||
sx = tileWidth + ( x === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
sy = tileHeight + ( y === 0 ? 1 : 2 ) * this.tileOverlap,
|
||||
scale = 1.0 / dimensionsScaled.x;
|
||||
|
||||
sx = Math.min( sx, dimensionsScaled.x - px );
|
||||
@ -560,8 +613,7 @@ function processResponse( xhr ){
|
||||
data = xhr.responseText;
|
||||
}
|
||||
}else if( responseText.match(/\s*[\{\[].*/) ){
|
||||
/*jshint evil:true*/
|
||||
data = eval( '('+responseText+')' );
|
||||
data = $.parseJSON(responseText);
|
||||
}else{
|
||||
data = responseText;
|
||||
}
|
||||
|
105
src/viewer.js
105
src/viewer.js
@ -374,7 +374,6 @@ $.Viewer = function( options ) {
|
||||
viewer: this,
|
||||
viewport: this.viewport,
|
||||
element: this.canvas,
|
||||
opacity: this.opacity,
|
||||
debugGridColor: this.debugGridColor
|
||||
});
|
||||
|
||||
@ -1073,6 +1072,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
};
|
||||
/**
|
||||
* Raised when the viewer is about to change to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}).
|
||||
* Note: the pre-full-screen event is not raised when the user is exiting
|
||||
* full-screen mode by pressing the Esc key. In that case, consider using
|
||||
* the full-screen, pre-full-page or full-page events.
|
||||
*
|
||||
* @event pre-full-screen
|
||||
* @memberof OpenSeadragon.Viewer
|
||||
@ -1191,6 +1193,10 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
* named 'getTileUrl', it is treated as a custom TileSource.
|
||||
* @param {Number} [options.index] The index of the item. Added on top of
|
||||
* all other items if not specified.
|
||||
* @param {Boolean} [options.replace=false] If true, the item at options.index will be
|
||||
* removed and the new item is added in its place. options.tileSource will be
|
||||
* interpreted and fetched if necessary before the old item is removed to avoid leaving
|
||||
* a gap in the world.
|
||||
* @param {Number} [options.x=0] The X position for the image in viewport coordinates.
|
||||
* @param {Number} [options.y=0] The Y position for the image in viewport coordinates.
|
||||
* @param {Number} [options.width=1] The width for the image in viewport coordinates.
|
||||
@ -1198,6 +1204,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
* @param {OpenSeadragon.Rect} [options.clip] - An area, in image pixels, to clip to
|
||||
* (portions of the image outside of this area will not be visible). Only works on
|
||||
* browsers that support the HTML5 canvas.
|
||||
* @param {Number} [options.opacity] Opacity the tiled image should be drawn at by default.
|
||||
* @param {Function} [options.success] A function that gets called when the image is
|
||||
* successfully added. It's passed the event object which contains a single property:
|
||||
* "item", the resulting TiledImage.
|
||||
@ -1206,17 +1213,31 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
* and "source" properties.
|
||||
* @param {Boolean} [options.collectionImmediately=false] If collectionMode is on,
|
||||
* specifies whether to snap to the new arrangement immediately or to animate to it.
|
||||
* @param {String|CanvasGradient|CanvasPattern|Function} [options.placeholderFillStyle] - See {@link OpenSeadragon.Options}.
|
||||
* @fires OpenSeadragon.World.event:add-item
|
||||
* @fires OpenSeadragon.Viewer.event:add-item-failed
|
||||
*/
|
||||
addTiledImage: function( options ) {
|
||||
$.console.assert(options, "[Viewer.addTiledImage] options is required");
|
||||
$.console.assert(options.tileSource, "[Viewer.addTiledImage] options.tileSource is required");
|
||||
$.console.assert(!options.replace || (options.index > -1 && options.index < this.world.getItemCount()),
|
||||
"[Viewer.addTiledImage] if options.replace is used, options.index must be a valid index in Viewer.world");
|
||||
|
||||
var _this = this;
|
||||
|
||||
if (options.replace) {
|
||||
options.replaceItem = _this.world.getItemAt(options.index);
|
||||
}
|
||||
|
||||
this._hideMessage();
|
||||
|
||||
if (options.placeholderFillStyle === undefined) {
|
||||
options.placeholderFillStyle = this.placeholderFillStyle;
|
||||
}
|
||||
if (options.opacity === undefined) {
|
||||
options.opacity = this.opacity;
|
||||
}
|
||||
|
||||
var myQueueItem = {
|
||||
options: options
|
||||
};
|
||||
@ -1272,6 +1293,14 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
|
||||
_this._loadQueue.splice(0, 1);
|
||||
|
||||
if (queueItem.options.replace) {
|
||||
var newIndex = _this.world.getIndexOfItem(options.replaceItem);
|
||||
if (newIndex != -1) {
|
||||
options.index = newIndex;
|
||||
}
|
||||
_this.world.removeItem(options.replaceItem);
|
||||
}
|
||||
|
||||
tiledImage = new $.TiledImage({
|
||||
viewer: _this,
|
||||
source: queueItem.tileSource,
|
||||
@ -1284,6 +1313,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
width: queueItem.options.width,
|
||||
height: queueItem.options.height,
|
||||
clip: queueItem.options.clip,
|
||||
placeholderFillStyle: queueItem.options.placeholderFillStyle,
|
||||
opacity: queueItem.options.opacity,
|
||||
springStiffness: _this.springStiffness,
|
||||
animationTime: _this.animationTime,
|
||||
minZoomImageRatio: _this.minZoomImageRatio,
|
||||
@ -1305,6 +1336,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
_this.world.arrange({
|
||||
immediately: queueItem.options.collectionImmediately,
|
||||
rows: _this.collectionRows,
|
||||
columns: _this.collectionColumns,
|
||||
layout: _this.collectionLayout,
|
||||
tileSize: _this.collectionTileSize,
|
||||
tileMargin: _this.collectionTileMargin
|
||||
@ -1697,7 +1729,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
* is closed which include when changing page.
|
||||
* @method
|
||||
* @param {Element|String|Object} element - A reference to an element or an id for
|
||||
* the element which will overlayed. Or an Object specifying the configuration for the overlay
|
||||
* the element which will be overlayed. Or an Object specifying the configuration for the overlay
|
||||
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
|
||||
* rectangle which will be overlayed.
|
||||
* @param {OpenSeadragon.OverlayPlacement} placement - The position of the
|
||||
@ -1757,6 +1789,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
* Updates the overlay represented by the reference to the element or
|
||||
* element id moving it to the new location, relative to the new placement.
|
||||
* @method
|
||||
* @param {Element|String} element - A reference to an element or an id for
|
||||
* the element which is overlayed.
|
||||
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
|
||||
* rectangle which will be overlayed.
|
||||
* @param {OpenSeadragon.OverlayPlacement} placement - The position of the
|
||||
@ -1980,8 +2014,7 @@ function getTileSourceImplementation( viewer, tileSource, successCallback,
|
||||
if ( tileSource.match( /\s*<.*/ ) ) {
|
||||
tileSource = $.parseXml( tileSource );
|
||||
} else if ( tileSource.match( /\s*[\{\[].*/ ) ) {
|
||||
/*jshint evil:true*/
|
||||
tileSource = eval( '(' + tileSource + ')' );
|
||||
tileSource = $.parseJSON(tileSource);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2206,7 +2239,7 @@ function onCanvasKeyDown( event ) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(1.1);
|
||||
} else {
|
||||
this.viewport.panBy(new $.Point(0, -0.05));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
@ -2214,16 +2247,16 @@ function onCanvasKeyDown( event ) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(0.9);
|
||||
} else {
|
||||
this.viewport.panBy(new $.Point(0, 0.05));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 37://left arrow
|
||||
this.viewport.panBy(new $.Point(-0.05, 0));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 39://right arrow
|
||||
this.viewport.panBy(new $.Point(0.05, 0));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
default:
|
||||
@ -2255,7 +2288,7 @@ function onCanvasKeyPress( event ) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(1.1);
|
||||
} else {
|
||||
this.viewport.panBy(new $.Point(0, -0.05));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, -40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
@ -2264,16 +2297,16 @@ function onCanvasKeyPress( event ) {
|
||||
if ( event.shift ) {
|
||||
this.viewport.zoomBy(0.9);
|
||||
} else {
|
||||
this.viewport.panBy(new $.Point(0, 0.05));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(0, 40)));
|
||||
}
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 97://a
|
||||
this.viewport.panBy(new $.Point(-0.05, 0));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(-40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
case 100://d
|
||||
this.viewport.panBy(new $.Point(0.05, 0));
|
||||
this.viewport.panBy(this.viewport.deltaPointsFromPixels(new $.Point(40, 0)));
|
||||
this.viewport.applyConstraints();
|
||||
return false;
|
||||
default:
|
||||
@ -2811,13 +2844,31 @@ function updateOnce( viewer ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var containerSize;
|
||||
if ( viewer.autoResize ) {
|
||||
var containerSize = _getSafeElemSize( viewer.container );
|
||||
containerSize = _getSafeElemSize( viewer.container );
|
||||
if ( !containerSize.equals( THIS[ viewer.hash ].prevContainerSize ) ) {
|
||||
// maintain image position
|
||||
var oldBounds = viewer.viewport.getBounds();
|
||||
var oldCenter = viewer.viewport.getCenter();
|
||||
resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter);
|
||||
if ( viewer.preserveImageSizeOnResize ) {
|
||||
var prevContainerSize = THIS[ viewer.hash ].prevContainerSize;
|
||||
var bounds = viewer.viewport.getBounds(true);
|
||||
var deltaX = (containerSize.x - prevContainerSize.x);
|
||||
var deltaY = (containerSize.y - prevContainerSize.y);
|
||||
var viewportDiff = viewer.viewport.deltaPointsFromPixels(new OpenSeadragon.Point(deltaX, deltaY), true);
|
||||
viewer.viewport.resize(new OpenSeadragon.Point(containerSize.x, containerSize.y), false);
|
||||
|
||||
// Keep the center of the image in the center and just adjust the amount of image shown
|
||||
bounds.width += viewportDiff.x;
|
||||
bounds.height += viewportDiff.y;
|
||||
bounds.x -= (viewportDiff.x / 2);
|
||||
bounds.y -= (viewportDiff.y / 2);
|
||||
viewer.viewport.fitBoundsWithConstraints(bounds, true);
|
||||
}
|
||||
else {
|
||||
// maintain image position
|
||||
var oldBounds = viewer.viewport.getBounds();
|
||||
var oldCenter = viewer.viewport.getCenter();
|
||||
resizeViewportAndRecenter(viewer, containerSize, oldBounds, oldCenter);
|
||||
}
|
||||
THIS[ viewer.hash ].prevContainerSize = containerSize;
|
||||
THIS[ viewer.hash ].forceRedraw = true;
|
||||
}
|
||||
@ -2914,19 +2965,15 @@ function resizeViewportAndRecenter( viewer, containerSize, oldBounds, oldCenter
|
||||
|
||||
viewport.resize( containerSize, true );
|
||||
|
||||
// We try to remove blanks as much as possible
|
||||
var worldBounds = viewer.world.getHomeBounds();
|
||||
var newWidth = oldBounds.width <= worldBounds.width ? oldBounds.width : worldBounds.width;
|
||||
var newHeight = oldBounds.height <= worldBounds.height ?
|
||||
oldBounds.height : worldBounds.height;
|
||||
|
||||
var newBounds = new $.Rect(
|
||||
oldCenter.x - ( newWidth / 2.0 ),
|
||||
oldCenter.y - ( newHeight / 2.0 ),
|
||||
newWidth,
|
||||
newHeight
|
||||
);
|
||||
viewport.fitBounds( newBounds, true );
|
||||
oldCenter.x - ( oldBounds.width / 2.0 ),
|
||||
oldCenter.y - ( oldBounds.height / 2.0 ),
|
||||
oldBounds.width,
|
||||
oldBounds.height
|
||||
);
|
||||
|
||||
// let the viewport decide if the bounds are too big or too small
|
||||
viewport.fitBoundsWithConstraints( newBounds, true );
|
||||
}
|
||||
|
||||
function drawWorld( viewer ) {
|
||||
|
@ -281,6 +281,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
|
||||
* @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.columns] - See collectionColumns 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
|
||||
@ -290,10 +291,16 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
|
||||
var immediately = options.immediately || false;
|
||||
var layout = options.layout || $.DEFAULT_SETTINGS.collectionLayout;
|
||||
var rows = options.rows || $.DEFAULT_SETTINGS.collectionRows;
|
||||
var columns = options.columns || $.DEFAULT_SETTINGS.collectionColumns;
|
||||
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 wrap;
|
||||
if (!options.rows && columns) {
|
||||
wrap = columns;
|
||||
} else {
|
||||
wrap = Math.ceil(this._items.length / rows);
|
||||
}
|
||||
var x = 0;
|
||||
var y = 0;
|
||||
var item, box, width, height, position;
|
||||
|
@ -71,6 +71,7 @@
|
||||
<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/tilesource.js"></script>
|
||||
<script src="/test/modules/tilesourcecollection.js"></script>
|
||||
<script src="/test/modules/spring.js"></script>
|
||||
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||
|
@ -1,21 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenSeadragon Basic Demo</title>
|
||||
<title>OpenSeadragon Coordinates 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">
|
||||
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
}
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Simple demo page to show a default OpenSeadragon viewer.
|
||||
Simple demo page to show OpenSeadragon coordinates system.
|
||||
</div>
|
||||
<div id="contentDiv" class="openseadragon1"></div>
|
||||
<div>
|
||||
@ -24,16 +24,26 @@
|
||||
<th></th>
|
||||
<th>Window (pixel)</th>
|
||||
<th>Container (pixel)</th>
|
||||
<th>Image (pixel)</th>
|
||||
<th>Image 1 - top left (pixel)</th>
|
||||
<th>Image 2 - bottom right (pixel)</th>
|
||||
<th>Viewport (point)</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Cursor position</th>
|
||||
<td id="windowPosition"></td>
|
||||
<td id="containerPosition"></td>
|
||||
<td id="imagePosition"></td>
|
||||
<td id="image1Position"></td>
|
||||
<td id="image2Position"></td>
|
||||
<td id="viewportPosition"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Zoom</th>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td id="image1Zoom"></td>
|
||||
<td id="image2Zoom"></td>
|
||||
<td id="viewportZoom"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
@ -42,36 +52,57 @@
|
||||
// debugMode: true,
|
||||
id: "contentDiv",
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
tileSources: "../data/testpattern.dzi",
|
||||
showNavigator:true
|
||||
tileSources: [{
|
||||
tileSource: "../data/testpattern.dzi"
|
||||
},
|
||||
{
|
||||
tileSource: "../data/testpattern.dzi",
|
||||
x: 1,
|
||||
y: 1,
|
||||
width: 0.5
|
||||
}
|
||||
],
|
||||
showNavigator: true
|
||||
});
|
||||
|
||||
function pointToString(point) {
|
||||
return point.x.toPrecision(4) + "," + point.y.toPrecision(4);
|
||||
}
|
||||
|
||||
var onMouseTrackerMove = function(eventSender, eventData) {
|
||||
var viewerX = eventData.position.x;
|
||||
var viewerY = eventData.position.y;
|
||||
var onMouseTrackerMove = function (event) {
|
||||
var viewerX = event.position.x;
|
||||
var viewerY = event.position.y;
|
||||
var windowPoint = new OpenSeadragon.Point(viewerX, viewerY);
|
||||
$("#windowPosition").text( pointToString(windowPoint));
|
||||
|
||||
$("#windowPosition").text(pointToString(windowPoint));
|
||||
var containerPoint = windowPoint.minus(
|
||||
OpenSeadragon.getElementPosition(viewer.element));
|
||||
$("#containerPosition").text( pointToString(containerPoint));
|
||||
|
||||
var imagePoint = viewer.viewport.windowToImageCoordinates(windowPoint);
|
||||
$("#imagePosition").text( pointToString(imagePoint));
|
||||
|
||||
$("#containerPosition").text(pointToString(containerPoint));
|
||||
var image1 = viewer.world.getItemAt(0);
|
||||
var imagePoint = image1.windowToImageCoordinates(windowPoint);
|
||||
$("#image1Position").text(pointToString(imagePoint));
|
||||
var image2 = viewer.world.getItemAt(1);
|
||||
var imagePoint = image2.windowToImageCoordinates(windowPoint);
|
||||
$("#image2Position").text(pointToString(imagePoint));
|
||||
var viewportPoint = viewer.viewport.windowToViewportCoordinates(windowPoint);
|
||||
$("#viewportPosition").text( pointToString(viewportPoint));
|
||||
$("#viewportPosition").text(pointToString(viewportPoint));
|
||||
};
|
||||
|
||||
mouseTracker = new OpenSeadragon.MouseTracker({
|
||||
element: document,
|
||||
moveHandler: onMouseTrackerMove
|
||||
}).setTracking(true);
|
||||
|
||||
function onAnimation() {
|
||||
var viewportZoom = viewer.viewport.getZoom(true);
|
||||
$("#viewportZoom").text(viewportZoom.toFixed(3));
|
||||
var image1 = viewer.world.getItemAt(0);
|
||||
var image1Zoom = image1.viewportToImageZoom(viewportZoom);
|
||||
$("#image1Zoom").text(image1Zoom.toFixed(3));
|
||||
var image2 = viewer.world.getItemAt(1);
|
||||
var image2Zoom = image2.viewportToImageZoom(viewportZoom);
|
||||
$("#image2Zoom").text(image2Zoom.toFixed(3));
|
||||
}
|
||||
viewer.addHandler("animation", onAnimation);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -464,18 +464,22 @@
|
||||
var page = this.pages[this.pageIndex];
|
||||
var box = page.getBounds();
|
||||
|
||||
this.highlight
|
||||
.style('opacity', 1)
|
||||
.attr("x", box.x)
|
||||
.attr("width", box.width)
|
||||
.attr("y", box.y)
|
||||
.attr("height", box.height);
|
||||
if (this.highlight) {
|
||||
this.highlight
|
||||
.style('opacity', 1)
|
||||
.attr("x", box.x)
|
||||
.attr("width", box.width)
|
||||
.attr("y", box.y)
|
||||
.attr("height", box.height);
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
updateHover: function(pageIndex) {
|
||||
if (pageIndex === -1 || this.mode !== 'thumbs') {
|
||||
this.hover.style('opacity', 0);
|
||||
if (this.hover) {
|
||||
this.hover.style('opacity', 0);
|
||||
}
|
||||
this.$scrollCover.css({
|
||||
'cursor': 'default'
|
||||
});
|
||||
@ -490,12 +494,14 @@
|
||||
var page = this.pages[pageIndex];
|
||||
var box = page.getBounds();
|
||||
|
||||
this.hover
|
||||
.style('opacity', 0.3)
|
||||
.attr("x", box.x)
|
||||
.attr("width", box.width)
|
||||
.attr("y", box.y)
|
||||
.attr("height", box.height);
|
||||
if (this.hover) {
|
||||
this.hover
|
||||
.style('opacity', 0.3)
|
||||
.attr("x", box.x)
|
||||
.attr("width", box.width)
|
||||
.attr("y", box.y)
|
||||
.attr("height", box.height);
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -23,19 +23,19 @@
|
||||
<script type="text/javascript">
|
||||
|
||||
var _viewer;
|
||||
|
||||
|
||||
var generateUniqueHash = (function() {
|
||||
var counter = 0;
|
||||
return function() {
|
||||
return "openseadragon_" + (counter++);
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
function createViewer() {
|
||||
if ( _viewer ) {
|
||||
destroyViewer();
|
||||
}
|
||||
|
||||
|
||||
_viewer = OpenSeadragon({
|
||||
element: document.getElementById("contentDiv"),
|
||||
showNavigationControl: false,
|
||||
@ -44,7 +44,7 @@
|
||||
tileSources: "../data/testpattern.dzi"
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function destroyViewer() {
|
||||
if ( _viewer ) {
|
||||
_viewer.destroy();
|
||||
|
41
test/demo/overlay.html
Normal file
41
test/demo/overlay.html
Normal file
@ -0,0 +1,41 @@
|
||||
<html>
|
||||
<title>OpenSeadragon Overlay 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">
|
||||
|
||||
.openseadragon1 {
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="contentDiv" class="openseadragon1"></div>
|
||||
<div id="annotation-div">
|
||||
<input type="button" value="Hide Overlay" id="hideOverlay">
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var viewer = OpenSeadragon({
|
||||
id: "contentDiv",
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
tileSources: "../data/testpattern.dzi",
|
||||
});
|
||||
|
||||
viewer.addHandler("open", function(event) {
|
||||
var elt = document.createElement("div");
|
||||
elt.style.background = "green";
|
||||
elt.id = "runtime-overlay";
|
||||
elt.style.border = "1px solid red";
|
||||
viewer.addOverlay( elt, new OpenSeadragon.Rect(0.2, 0.2, 0.75, 0.75) );
|
||||
});
|
||||
|
||||
$("#hideOverlay").click(function(){
|
||||
$("#runtime-overlay").toggle();
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
96
test/demo/tilesource-swap.html
Normal file
96
test/demo/tilesource-swap.html
Normal file
@ -0,0 +1,96 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TileSource Swapping</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 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.viewer-position {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 30px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>This is a demo of using a single image stand-in and then swapping to a full TileSource on zooming. Click the image to see it in action.</div>
|
||||
<div id="openseadragon1" class="viewer-position"></div>
|
||||
<script>
|
||||
|
||||
var duomoStandin = {
|
||||
type: 'legacy-image-pyramid',
|
||||
levels: [
|
||||
{
|
||||
url: 'http://openseadragon.github.io/example-images/duomo/duomo_files/8/0_0.jpg',
|
||||
width: 218,
|
||||
height: 160
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
var duomo = {
|
||||
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'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var viewer = OpenSeadragon({
|
||||
id: 'openseadragon1',
|
||||
prefixUrl: '../../build/openseadragon/images/',
|
||||
tileSources: duomoStandin,
|
||||
minZoomImageRatio: 0.1,
|
||||
defaultZoomLevel: 0.1,
|
||||
zoomPerClick: 1
|
||||
});
|
||||
|
||||
viewer.addHandler('canvas-click', function(event) {
|
||||
if (event.quick) {
|
||||
var standin = viewer.world.getItemAt(0);
|
||||
var standinBounds = standin.getBounds();
|
||||
viewer.viewport.fitBounds(standinBounds);
|
||||
|
||||
viewer.addTiledImage({
|
||||
x: standinBounds.x,
|
||||
y: standinBounds.y,
|
||||
width: standinBounds.width,
|
||||
tileSource: duomo,
|
||||
index: 0, // Add the new image below the stand-in.
|
||||
success: function(event) {
|
||||
var fullImage = event.item;
|
||||
|
||||
// The changeover will look better if we wait for the first tile to be drawn.
|
||||
var tileDrawnHandler = function(event) {
|
||||
if (event.tiledImage === fullImage) {
|
||||
viewer.removeHandler('tile-drawn', tileDrawnHandler);
|
||||
viewer.world.removeItem(standin);
|
||||
}
|
||||
};
|
||||
|
||||
viewer.addHandler('tile-drawn', tileDrawnHandler);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
@ -33,9 +33,6 @@
|
||||
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();
|
||||
});
|
||||
|
||||
@ -67,18 +64,64 @@
|
||||
});
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('sketchCanvas', function() {
|
||||
createViewer({
|
||||
tileSources: '/test/data/testpattern.dzi'
|
||||
});
|
||||
var drawer = viewer.drawer;
|
||||
|
||||
viewer.addHandler('tile-drawn', function noOpacityHandler() {
|
||||
viewer.removeHandler('tile-drawn', noOpacityHandler);
|
||||
equal(drawer.sketchCanvas, null,
|
||||
'The sketch canvas should be null if no decimal opacity is used.');
|
||||
equal(drawer.sketchContext, null,
|
||||
'The sketch context should be null if no decimal opacity is used.');
|
||||
testOpacityDecimal();
|
||||
});
|
||||
|
||||
function testOpacityDecimal() {
|
||||
var tiledImage;
|
||||
viewer.addTiledImage({
|
||||
tileSource: '/test/data/testpattern.dzi',
|
||||
opacity: 0.5,
|
||||
success: function(event) {
|
||||
tiledImage = event.item;
|
||||
}
|
||||
});
|
||||
|
||||
viewer.addHandler('tile-drawn', function opacityDecimalHandler(event) {
|
||||
if (tiledImage !== event.tiledImage) {
|
||||
return;
|
||||
}
|
||||
viewer.removeHandler('tile-drawn', opacityDecimalHandler);
|
||||
notEqual(drawer.sketchCanvas, null,
|
||||
'The sketch canvas should not be null once a decimal opacity has been used.');
|
||||
notEqual(drawer.sketchContext, null,
|
||||
'The sketch context should not be null once a decimal opacity has been used.');
|
||||
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();
|
||||
createViewer({
|
||||
tileSources: '/test/data/testpattern.dzi'
|
||||
});
|
||||
viewer.world.addHandler('add-item', function() {
|
||||
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');
|
||||
Util.testDeprecation(viewer.drawer, 'setOpacity', viewer.world.getItemAt(0), 'setOpacity');
|
||||
Util.testDeprecation(viewer.drawer, 'getOpacity', viewer.world.getItemAt(0), 'getOpacity');
|
||||
start();
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
|
@ -968,4 +968,103 @@
|
||||
viewer.open( '/test/data/testpattern.dzi' );
|
||||
} );
|
||||
|
||||
// tile-loaded event tests
|
||||
asyncTest( 'Viewer: tile-loaded event without callback.', function () {
|
||||
|
||||
function tileLoaded ( event ) {
|
||||
viewer.removeHandler( 'tile-loaded', tileLoaded);
|
||||
var tile = event.tile;
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
setTimeout(function() {
|
||||
notOk( tile.loading, "The tile should not be marked as loading.");
|
||||
ok( tile.loaded, "The tile should be marked as loaded.");
|
||||
start();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
viewer.addHandler( 'tile-loaded', tileLoaded);
|
||||
viewer.open( '/test/data/testpattern.dzi' );
|
||||
} );
|
||||
|
||||
asyncTest( 'Viewer: tile-loaded event with 1 callback.', function () {
|
||||
|
||||
function tileLoaded ( event ) {
|
||||
viewer.removeHandler( 'tile-loaded', tileLoaded);
|
||||
var tile = event.tile;
|
||||
var callback = event.getCompletionCallback();
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
ok( callback, "The event should have a callback.");
|
||||
setTimeout(function() {
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
callback();
|
||||
notOk( tile.loading, "The tile should not be marked as loading.");
|
||||
ok( tile.loaded, "The tile should be marked as loaded.");
|
||||
start();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
viewer.addHandler( 'tile-loaded', tileLoaded);
|
||||
viewer.open( '/test/data/testpattern.dzi' );
|
||||
} );
|
||||
|
||||
asyncTest( 'Viewer: tile-loaded event with 2 callbacks.', function () {
|
||||
|
||||
function tileLoaded ( event ) {
|
||||
viewer.removeHandler( 'tile-loaded', tileLoaded);
|
||||
var tile = event.tile;
|
||||
var callback1 = event.getCompletionCallback();
|
||||
var callback2 = event.getCompletionCallback();
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
setTimeout(function() {
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
callback1();
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
setTimeout(function() {
|
||||
ok( tile.loading, "The tile should be marked as loading.");
|
||||
notOk( tile.loaded, "The tile should not be marked as loaded.");
|
||||
callback2();
|
||||
notOk( tile.loading, "The tile should not be marked as loading.");
|
||||
ok( tile.loaded, "The tile should be marked as loaded.");
|
||||
start();
|
||||
}, 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
viewer.addHandler( 'tile-loaded', tileLoaded);
|
||||
viewer.open( '/test/data/testpattern.dzi' );
|
||||
} );
|
||||
|
||||
asyncTest( 'Viewer: tile-unloaded event.', function() {
|
||||
var tiledImage;
|
||||
var tile;
|
||||
|
||||
function tileLoaded( event ) {
|
||||
viewer.removeHandler( 'tile-loaded', tileLoaded);
|
||||
tiledImage = event.tiledImage;
|
||||
tile = event.tile;
|
||||
setTimeout(function() {
|
||||
tiledImage.reset();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function tileUnloaded( event ) {
|
||||
viewer.removeHandler( 'tile-unloaded', tileUnloaded );
|
||||
equal( tile, event.tile,
|
||||
"The unloaded tile should be the same than the loaded one." );
|
||||
equal( tiledImage, event.tiledImage,
|
||||
"The tiledImage of the unloaded tile should be the same than the one of the loaded one." );
|
||||
start();
|
||||
}
|
||||
|
||||
viewer.addHandler( 'tile-loaded', tileLoaded );
|
||||
viewer.addHandler( 'tile-unloaded', tileUnloaded );
|
||||
viewer.open( '/test/data/testpattern.dzi' );
|
||||
} );
|
||||
|
||||
} )();
|
||||
|
@ -14,14 +14,18 @@
|
||||
var viewer = null;
|
||||
|
||||
// ----------
|
||||
var testOpen = function(name) {
|
||||
var testOpenUrl = function(relativeUrl) {
|
||||
testOpen('/test/data/' + relativeUrl);
|
||||
};
|
||||
|
||||
var testOpen = function(tileSource) {
|
||||
$(document).ready(function() {
|
||||
var timeWatcher = Util.timeWatcher(7000);
|
||||
|
||||
viewer = OpenSeadragon({
|
||||
id: 'example',
|
||||
prefixUrl: '/build/openseadragon/images/',
|
||||
tileSources: '/test/data/' + name
|
||||
tileSources: tileSource
|
||||
});
|
||||
|
||||
ok(viewer, 'Viewer exists');
|
||||
@ -52,62 +56,90 @@
|
||||
|
||||
// ----------
|
||||
asyncTest('DZI', function() {
|
||||
testOpen('testpattern.dzi');
|
||||
testOpenUrl('testpattern.dzi');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('DZI JSONp', function() {
|
||||
testOpen('testpattern.js');
|
||||
testOpenUrl('testpattern.js');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('DZI XML', function() {
|
||||
testOpen('testpattern.xml');
|
||||
testOpenUrl('testpattern.xml');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('DZI XML with query parameter', function() {
|
||||
testOpen('testpattern.xml?param=value');
|
||||
testOpenUrl('testpattern.xml?param=value');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF 1.0 JSON', function() {
|
||||
testOpen('iiif_1_0_files/info.json');
|
||||
testOpenUrl('iiif_1_0_files/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF 1.0 XML', function() {
|
||||
testOpen('iiif_1_0_files/info.xml');
|
||||
testOpenUrl('iiif_1_0_files/info.xml');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF 1.1 JSON', function() {
|
||||
testOpen('iiif_1_1_tiled/info.json');
|
||||
testOpenUrl('iiif_1_1_tiled/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF No Tiles, Less than 256', function() {
|
||||
testOpen('iiif_1_1_no_tiles_255/info.json');
|
||||
testOpenUrl('iiif_1_1_no_tiles_255/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF No Tiles, Bet. 256 and 512', function() {
|
||||
testOpen('iiif_1_1_no_tiles_384/info.json');
|
||||
testOpenUrl('iiif_1_1_no_tiles_384/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF No Tiles, Bet. 512 and 1024', function() {
|
||||
testOpen('iiif_1_1_no_tiles_768/info.json');
|
||||
testOpenUrl('iiif_1_1_no_tiles_768/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF No Tiles, Larger than 1024', function() {
|
||||
testOpen('iiif_1_1_no_tiles_1048/info.json');
|
||||
testOpenUrl('iiif_1_1_no_tiles_1048/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF 2.0 JSON', function() {
|
||||
testOpen('iiif_2_0_tiled/info.json');
|
||||
});
|
||||
testOpenUrl('iiif_2_0_tiled/info.json');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('IIIF 2.0 JSON String', function() {
|
||||
testOpen(
|
||||
'{' +
|
||||
' "@context": "http://iiif.io/api/image/2/context.json",' +
|
||||
' "@id": "http://localhost:8000/test/data/iiif_2_0_tiled",' +
|
||||
' "protocol": "http://iiif.io/api/image",' +
|
||||
' "height": 1024,' +
|
||||
' "width": 775,' +
|
||||
' "tiles" : [{"width":256, "scaleFactors":[1,2,4,8]}],' +
|
||||
' "profile": ["http://iiif.io/api/image/2/level1.json",' +
|
||||
' {' +
|
||||
' "qualities": [' +
|
||||
' "native",' +
|
||||
' "bitonal",' +
|
||||
' "grey",' +
|
||||
' "color"' +
|
||||
' ],' +
|
||||
' "formats": [' +
|
||||
' "jpg",' +
|
||||
' "png",' +
|
||||
' "gif"' +
|
||||
' ]' +
|
||||
' }' +
|
||||
' ]' +
|
||||
'}');
|
||||
});
|
||||
|
||||
})();
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
// ----------
|
||||
asyncTest( 'Multi-image operations', function() {
|
||||
expect( 21 );
|
||||
expect( 24 );
|
||||
viewer.addHandler( "open", function( ) {
|
||||
equal( 1, viewer.world.getItemCount( ),
|
||||
"One item should be present after opening." );
|
||||
@ -95,22 +95,36 @@
|
||||
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 );
|
||||
options.index = 2;
|
||||
options.replace = true;
|
||||
viewer.addTiledImage( options );
|
||||
viewer.world.addHandler( "add-item", function replaceAddItemHandler( event ) {
|
||||
viewer.world.removeHandler( "add-item", replaceAddItemHandler );
|
||||
var item4 = event.item;
|
||||
equal( viewer.world.getItemCount( ), 4,
|
||||
"4 items should still be present after replacing the second item." );
|
||||
equal( viewer.world.getIndexOfItem( item4 ), 2,
|
||||
"Item 4 should be added with index 2." );
|
||||
equal( viewer.world.getIndexOfItem( item3 ), -1,
|
||||
"Item 3 should be at index -1." );
|
||||
|
||||
equal( item2, event.item, "Removed item should be item2." );
|
||||
viewer.world.addHandler( "remove-item", function removeItemHandler( event ) {
|
||||
viewer.world.removeHandler( "remove-item", removeItemHandler );
|
||||
|
||||
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." );
|
||||
equal( item2, event.item, "Removed item should be item2." );
|
||||
|
||||
start();
|
||||
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( item4 ), 1,
|
||||
"Item 4 should be at index 1." );
|
||||
|
||||
start();
|
||||
});
|
||||
|
||||
viewer.world.removeItem( item2 );
|
||||
});
|
||||
|
||||
viewer.world.removeItem( item2 );
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -13,8 +13,15 @@
|
||||
|
||||
// ----------
|
||||
asyncTest('basics', function() {
|
||||
var fakeTiledImage0 = {};
|
||||
var fakeTiledImage1 = {};
|
||||
var fakeViewer = {
|
||||
raiseEvent: function() {}
|
||||
};
|
||||
var fakeTiledImage0 = {
|
||||
viewer: fakeViewer
|
||||
};
|
||||
var fakeTiledImage1 = {
|
||||
viewer: fakeViewer
|
||||
};
|
||||
|
||||
var fakeTile0 = {
|
||||
url: 'foo.jpg',
|
||||
@ -58,7 +65,12 @@
|
||||
|
||||
// ----------
|
||||
asyncTest('maxImageCacheCount', function() {
|
||||
var fakeTiledImage0 = {};
|
||||
var fakeViewer = {
|
||||
raiseEvent: function() {}
|
||||
};
|
||||
var fakeTiledImage0 = {
|
||||
viewer: fakeViewer
|
||||
};
|
||||
|
||||
var fakeTile0 = {
|
||||
url: 'different.jpg',
|
||||
|
@ -220,4 +220,41 @@
|
||||
});
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('opacity', function() {
|
||||
|
||||
function testDefaultOpacity() {
|
||||
viewer.removeHandler('open', testDefaultOpacity);
|
||||
var image = viewer.world.getItemAt(0);
|
||||
strictEqual(image.getOpacity(), 0.5, 'image has default opacity');
|
||||
|
||||
image.setOpacity(1);
|
||||
strictEqual(image.getOpacity(), 1, 'opacity is set correctly');
|
||||
|
||||
viewer.addHandler('open', testTileSourceOpacity);
|
||||
viewer.open({
|
||||
tileSource: '/test/data/testpattern.dzi',
|
||||
opacity: 0.25
|
||||
});
|
||||
}
|
||||
|
||||
function testTileSourceOpacity() {
|
||||
viewer.removeHandler('open', testTileSourceOpacity);
|
||||
var image = viewer.world.getItemAt(0);
|
||||
strictEqual(image.getOpacity(), 0.25, 'image has correct opacity');
|
||||
|
||||
image.setOpacity(0);
|
||||
strictEqual(image.getOpacity(), 0, 'opacity is set correctly');
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
viewer.addHandler('open', testDefaultOpacity);
|
||||
|
||||
viewer.opacity = 0.5;
|
||||
viewer.open({
|
||||
tileSource: '/test/data/testpattern.dzi',
|
||||
});
|
||||
});
|
||||
|
||||
})();
|
||||
|
51
test/modules/tilesource.js
Normal file
51
test/modules/tilesource.js
Normal file
@ -0,0 +1,51 @@
|
||||
/* global module, ok, equal, start, test, testLog, Util */
|
||||
(function() {
|
||||
|
||||
module('TileSource', {
|
||||
setup: function() {
|
||||
testLog.reset();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
test("should set sane tile size defaults", function() {
|
||||
var source = new OpenSeadragon.TileSource();
|
||||
|
||||
equal(source.getTileWidth(), 0, "getTileWidth() should return 0 if not provided a size");
|
||||
equal(source.getTileHeight(), 0, "getTileHeight() should return 0 if not provided a size");
|
||||
});
|
||||
|
||||
test("providing tileSize", function(){
|
||||
var tileSize = 256,
|
||||
source = new OpenSeadragon.TileSource({
|
||||
tileSize: tileSize
|
||||
});
|
||||
|
||||
equal(source.tileSize, undefined, "tileSize should not be set on the tileSource");
|
||||
equal(source.getTileWidth(), tileSize, "getTileWidth() should equal tileSize");
|
||||
equal(source.getTileHeight(), tileSize, "getTileHeight() should equal tileSize");
|
||||
});
|
||||
|
||||
|
||||
test("providing tileWidth and tileHeight", function(){
|
||||
var tileWidth = 256,
|
||||
tileHeight = 512,
|
||||
source = new OpenSeadragon.TileSource({
|
||||
tileWidth: tileWidth,
|
||||
tileHeight: tileHeight
|
||||
});
|
||||
|
||||
equal(source._tileWidth, tileWidth, "tileWidth option should set _tileWidth");
|
||||
equal(source._tileHeight, tileHeight, "tileHeight option should set _tileHeight");
|
||||
equal(source.tileWidth, undefined, "tileWidth should be renamed _tileWidth");
|
||||
equal(source.tileHeight, undefined, "tileHeight should be renamed _tileHeight");
|
||||
equal(source.getTileWidth(), tileWidth, "getTileWidth() should equal tileWidth");
|
||||
equal(source.getTileHeight(), tileHeight, "getTileHeight() should equal tileHeight");
|
||||
});
|
||||
|
||||
test('getTileSize() deprecation', function() {
|
||||
var source = new OpenSeadragon.TileSource();
|
||||
Util.testDeprecation(source, 'getTileSize');
|
||||
});
|
||||
|
||||
}());
|
@ -1,6 +1,6 @@
|
||||
/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */
|
||||
|
||||
(function() {
|
||||
(function () {
|
||||
var viewer;
|
||||
|
||||
module('Units', {
|
||||
@ -10,8 +10,8 @@
|
||||
testLog.reset();
|
||||
|
||||
viewer = OpenSeadragon({
|
||||
id: 'unitsexample',
|
||||
prefixUrl: '/build/openseadragon/images/',
|
||||
id: 'unitsexample',
|
||||
prefixUrl: '/build/openseadragon/images/',
|
||||
springStiffness: 100 // Faster animation = faster tests
|
||||
});
|
||||
},
|
||||
@ -30,38 +30,57 @@
|
||||
Util.assessNumericValue(a.y, b.y, 0.00000001, message);
|
||||
}
|
||||
|
||||
// ----------
|
||||
asyncTest('Coordinates conversions', function() {
|
||||
// Check that f^-1 ( f(x) ) = x
|
||||
function checkPoint(context) {
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
function checkPoint(context) {
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
var point = new OpenSeadragon.Point(15, 12);
|
||||
var result = viewport.viewerElementToImageCoordinates(
|
||||
var point = new OpenSeadragon.Point(15, 12);
|
||||
var result = viewport.viewerElementToImageCoordinates(
|
||||
viewport.imageToViewerElementCoordinates(point));
|
||||
pointEqual(result, point, 'viewerElement and image ' + context);
|
||||
pointEqual(result, point, 'viewerElement and image ' + context);
|
||||
|
||||
var result = viewport.windowToImageCoordinates(
|
||||
result = viewport.windowToImageCoordinates(
|
||||
viewport.imageToWindowCoordinates(point));
|
||||
pointEqual(result, point, 'window and image ' + context);
|
||||
pointEqual(result, point, 'window and image ' + context);
|
||||
|
||||
var result = viewport.viewerElementToViewportCoordinates(
|
||||
result = viewport.viewerElementToViewportCoordinates(
|
||||
viewport.viewportToViewerElementCoordinates(point));
|
||||
pointEqual(result, point, 'viewerElement and viewport ' + context);
|
||||
pointEqual(result, point, 'viewerElement and viewport ' + context);
|
||||
|
||||
var result = viewport.windowToViewportCoordinates(
|
||||
result = viewport.windowToViewportCoordinates(
|
||||
viewport.viewportToWindowCoordinates(point));
|
||||
pointEqual(result, point, 'window and viewport ' + context);
|
||||
pointEqual(result, point, 'window and viewport ' + context);
|
||||
|
||||
for (var i = 0; i < viewer.world.getItemCount(); i++) {
|
||||
var tiledImage = viewer.world.getItemAt(i);
|
||||
result = tiledImage.viewportToImageCoordinates(
|
||||
tiledImage.imageToViewportCoordinates(point));
|
||||
pointEqual(result, point, 'viewport and tiled image ' + i + context);
|
||||
|
||||
result = tiledImage.viewerElementToImageCoordinates(
|
||||
tiledImage.imageToViewerElementCoordinates(point));
|
||||
pointEqual(result, point, 'viewerElement and tiled image ' + i + context);
|
||||
|
||||
result = tiledImage.windowToImageCoordinates(
|
||||
tiledImage.imageToWindowCoordinates(point));
|
||||
pointEqual(result, point, 'window and tiled image ' + i + context);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------
|
||||
asyncTest('Single image coordinates conversions', function () {
|
||||
|
||||
viewer.addHandler("open", function () {
|
||||
var viewport = viewer.viewport;
|
||||
var tiledImage = viewer.world.getItemAt(0);
|
||||
|
||||
var point0_0 = new OpenSeadragon.Point(0, 0);
|
||||
var point = viewport.viewerElementToViewportCoordinates(point0_0);
|
||||
pointEqual(point, point0_0, 'When opening, viewer coordinate 0,0 is also point 0,0');
|
||||
var pixel = viewport.viewerElementToImageCoordinates(point0_0);
|
||||
pointEqual(pixel, point0_0, 'When opening, viewer coordinate 0,0 is also pixel 0,0');
|
||||
var viewportPixel = viewport.viewerElementToImageCoordinates(point0_0);
|
||||
pointEqual(viewportPixel, point0_0, 'When opening, viewer coordinate 0,0 is also viewport pixel 0,0');
|
||||
var imagePixel = tiledImage.viewerElementToImageCoordinates(point0_0);
|
||||
pointEqual(imagePixel, point0_0, 'When opening, viewer coordinate 0,0 is also image pixel 0,0');
|
||||
|
||||
var viewerWidth = $(viewer.element).width();
|
||||
var imageWidth = viewer.source.dimensions.x;
|
||||
@ -69,15 +88,17 @@
|
||||
var viewerTopRight = new OpenSeadragon.Point(viewerWidth, 0);
|
||||
var imageTopRight = new OpenSeadragon.Point(imageWidth, 0);
|
||||
|
||||
var point = viewport.viewerElementToViewportCoordinates(viewerTopRight);
|
||||
point = viewport.viewerElementToViewportCoordinates(viewerTopRight);
|
||||
pointEqual(point, point1_0, 'Viewer top right has viewport coordinates 1,0.');
|
||||
var pixel = viewport.viewerElementToImageCoordinates(viewerTopRight);
|
||||
pointEqual(pixel, imageTopRight, 'Viewer top right has viewport coordinates imageWidth,0.');
|
||||
viewportPixel = viewport.viewerElementToImageCoordinates(viewerTopRight);
|
||||
pointEqual(viewportPixel, imageTopRight, 'Viewer top right has viewport pixel coordinates imageWidth,0.');
|
||||
imagePixel = tiledImage.viewerElementToImageCoordinates(viewerTopRight);
|
||||
pointEqual(imagePixel, imageTopRight, 'Viewer top right has image pixel coordinates imageWidth,0.');
|
||||
|
||||
checkPoint('after opening');
|
||||
checkPoint(' after opening');
|
||||
viewer.addHandler('animation-finish', function animationHandler() {
|
||||
viewer.removeHandler('animation-finish', animationHandler);
|
||||
checkPoint('after zoom and pan');
|
||||
checkPoint(' after zoom and pan');
|
||||
start();
|
||||
});
|
||||
viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2));
|
||||
@ -85,19 +106,80 @@
|
||||
viewer.open('/test/data/testpattern.dzi');
|
||||
});
|
||||
|
||||
|
||||
// ---------
|
||||
asyncTest('Multiple images coordinates conversion', function () {
|
||||
|
||||
viewer.addHandler("open", function () {
|
||||
var viewport = viewer.viewport;
|
||||
var tiledImage1 = viewer.world.getItemAt(0);
|
||||
var tiledImage2 = viewer.world.getItemAt(1);
|
||||
var imageWidth = viewer.source.dimensions.x;
|
||||
var imageHeight = viewer.source.dimensions.y;
|
||||
|
||||
var point0_0 = new OpenSeadragon.Point(0, 0);
|
||||
var point = viewport.viewerElementToViewportCoordinates(point0_0);
|
||||
pointEqual(point, point0_0, 'When opening, viewer coordinate 0,0 is also point 0,0');
|
||||
var image1Pixel = tiledImage1.viewerElementToImageCoordinates(point0_0);
|
||||
pointEqual(image1Pixel, point0_0, 'When opening, viewer coordinate 0,0 is also image 1 pixel 0,0');
|
||||
var image2Pixel = tiledImage2.viewerElementToImageCoordinates(point0_0);
|
||||
pointEqual(image2Pixel,
|
||||
new OpenSeadragon.Point(-2 * imageWidth, -2 * imageHeight),
|
||||
'When opening, viewer coordinates 0,0 is also image 2 pixel -2*imageWidth, -2*imageHeight');
|
||||
|
||||
var viewerWidth = $(viewer.element).width();
|
||||
var viewerHeight = $(viewer.element).height();
|
||||
var viewerBottomRight = new OpenSeadragon.Point(viewerWidth, viewerHeight);
|
||||
|
||||
point = viewport.viewerElementToViewportCoordinates(viewerBottomRight);
|
||||
pointEqual(point, new OpenSeadragon.Point(1.5, 1.5),
|
||||
'Viewer bottom right has viewport coordinates 1.5,1.5.');
|
||||
image1Pixel = tiledImage1.viewerElementToImageCoordinates(viewerBottomRight);
|
||||
pointEqual(image1Pixel,
|
||||
new OpenSeadragon.Point(imageWidth * 1.5, imageHeight * 1.5),
|
||||
'Viewer bottom right has image 1 pixel coordinates imageWidth * 1.5, imageHeight * 1.5');
|
||||
image2Pixel = tiledImage2.viewerElementToImageCoordinates(viewerBottomRight);
|
||||
pointEqual(image2Pixel,
|
||||
new OpenSeadragon.Point(imageWidth, imageHeight),
|
||||
'Viewer bottom right has image 2 pixel coordinates imageWidth,imageHeight.');
|
||||
|
||||
|
||||
checkPoint(' after opening');
|
||||
viewer.addHandler('animation-finish', function animationHandler() {
|
||||
viewer.removeHandler('animation-finish', animationHandler);
|
||||
checkPoint(' after zoom and pan');
|
||||
start();
|
||||
});
|
||||
viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2));
|
||||
|
||||
start();
|
||||
});
|
||||
|
||||
viewer.open([{
|
||||
tileSource: "/test/data/testpattern.dzi"
|
||||
}, {
|
||||
tileSource: "/test/data/testpattern.dzi",
|
||||
x: 1,
|
||||
y: 1,
|
||||
width: 0.5
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
// ----------
|
||||
asyncTest('ZoomRatio', function() {
|
||||
asyncTest('ZoomRatio 1 image', function () {
|
||||
viewer.addHandler("open", function () {
|
||||
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
var imageWidth = 1000;
|
||||
var imageWidth = viewer.source.dimensions.x;
|
||||
|
||||
function getCurrentImageWidth() {
|
||||
return viewport.viewportToViewerElementCoordinates(
|
||||
new OpenSeadragon.Point(1, 0)).minus(
|
||||
new OpenSeadragon.Point(1, 0)).minus(
|
||||
viewport.viewportToViewerElementCoordinates(
|
||||
new OpenSeadragon.Point(0, 0))).x;
|
||||
new OpenSeadragon.Point(0, 0))).x;
|
||||
}
|
||||
|
||||
function checkZoom() {
|
||||
@ -105,16 +187,16 @@
|
||||
var expectedImageZoom = currentImageWidth / imageWidth;
|
||||
var expectedViewportZoom = viewport.getZoom(true);
|
||||
var actualImageZoom = viewport.viewportToImageZoom(
|
||||
expectedViewportZoom);
|
||||
expectedViewportZoom);
|
||||
equal(actualImageZoom, expectedImageZoom);
|
||||
|
||||
|
||||
var actualViewportZoom = viewport.imageToViewportZoom(actualImageZoom);
|
||||
equal(actualViewportZoom, expectedViewportZoom);
|
||||
}
|
||||
|
||||
checkZoom();
|
||||
|
||||
var zoomHandler = function() {
|
||||
var zoomHandler = function () {
|
||||
viewer.removeHandler('animation-finish', zoomHandler);
|
||||
checkZoom();
|
||||
start();
|
||||
@ -127,5 +209,61 @@
|
||||
viewer.open('/test/data/testpattern.dzi');
|
||||
});
|
||||
|
||||
// ----------
|
||||
asyncTest('ZoomRatio 2 images', function () {
|
||||
viewer.addHandler("open", function () {
|
||||
|
||||
var viewport = viewer.viewport;
|
||||
|
||||
var imageWidth = viewer.source.dimensions.x;
|
||||
var image1 = viewer.world.getItemAt(0);
|
||||
var image2 = viewer.world.getItemAt(1);
|
||||
|
||||
function getCurrentImageWidth(image) {
|
||||
var bounds = image.getBounds();
|
||||
return viewport.viewportToViewerElementCoordinates(
|
||||
bounds.getTopRight()).minus(
|
||||
viewport.viewportToViewerElementCoordinates(
|
||||
bounds.getTopLeft())).x;
|
||||
}
|
||||
|
||||
function checkZoom(image) {
|
||||
var currentImageWidth = getCurrentImageWidth(image);
|
||||
var expectedImageZoom = currentImageWidth / imageWidth;
|
||||
var expectedViewportZoom = viewport.getZoom(true);
|
||||
var actualImageZoom = image.viewportToImageZoom(
|
||||
expectedViewportZoom);
|
||||
Util.assessNumericValue(actualImageZoom, expectedImageZoom,
|
||||
0.00000001);
|
||||
|
||||
var actualViewportImage1Zoom = image.imageToViewportZoom(actualImageZoom);
|
||||
Util.assessNumericValue(
|
||||
actualViewportImage1Zoom, expectedViewportZoom, 0.00000001);
|
||||
}
|
||||
|
||||
checkZoom(image1);
|
||||
checkZoom(image2);
|
||||
|
||||
var zoomHandler = function () {
|
||||
viewer.removeHandler('animation-finish', zoomHandler);
|
||||
checkZoom(image1);
|
||||
checkZoom(image2);
|
||||
start();
|
||||
};
|
||||
|
||||
viewer.addHandler('animation-finish', zoomHandler);
|
||||
viewport.zoomTo(2);
|
||||
});
|
||||
|
||||
viewer.open([{
|
||||
tileSource: "/test/data/testpattern.dzi"
|
||||
}, {
|
||||
tileSource: "/test/data/testpattern.dzi",
|
||||
x: 1,
|
||||
y: 1,
|
||||
width: 0.5
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
})();
|
||||
|
@ -213,6 +213,26 @@
|
||||
|
||||
checkBounds(new OpenSeadragon.Rect(0, 0, 1, 4), 'one vertical column');
|
||||
|
||||
viewer.world.arrange({
|
||||
layout: 'horizontal',
|
||||
rows: false,
|
||||
columns: 3,
|
||||
tileSize: 1,
|
||||
tileMargin: 0.5
|
||||
});
|
||||
|
||||
checkBounds(new OpenSeadragon.Rect(0, 0, 4, 1), 'three horizontal columns (one horizontal row)');
|
||||
|
||||
viewer.world.arrange({
|
||||
layout: 'vertical',
|
||||
rows: false,
|
||||
columns: 3,
|
||||
tileSize: 1,
|
||||
tileMargin: 0.5
|
||||
});
|
||||
|
||||
checkBounds(new OpenSeadragon.Rect(0, 0, 1, 4), 'three vertical rows (one vertical column)');
|
||||
|
||||
start();
|
||||
});
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
<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/tilesource.js"></script>
|
||||
<script src="/test/modules/tilesourcecollection.js"></script>
|
||||
<script src="/test/modules/spring.js"></script>
|
||||
<!-- The navigator tests are the slowest (for now; hopefully they can be sped up)
|
||||
|
Loading…
x
Reference in New Issue
Block a user