mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-25 14:46:10 +03:00
Merge master
This commit is contained in:
commit
0a035afc2d
39
CITATION.cff
Normal file
39
CITATION.cff
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
cff-version: 1.2.0
|
||||||
|
title: OpenSeadragon
|
||||||
|
message: "If you use this software, please cite it using the metadata from this file."
|
||||||
|
type: software
|
||||||
|
authors:
|
||||||
|
- given-names: Ian
|
||||||
|
family-names: Gilman
|
||||||
|
email: ian@iangilman.com
|
||||||
|
- given-names: Aseem
|
||||||
|
family-names: Kishore
|
||||||
|
- given-names: Chris
|
||||||
|
family-names: Thatcher
|
||||||
|
- given-names: Mark
|
||||||
|
family-names: Salsbery
|
||||||
|
- given-names: Antoine
|
||||||
|
family-names: Vandecreme
|
||||||
|
- given-names: Thomas
|
||||||
|
family-names: Pearce
|
||||||
|
identifiers:
|
||||||
|
- type: url
|
||||||
|
value: https://openseadragon.github.io/
|
||||||
|
description: Homepage
|
||||||
|
- type: url
|
||||||
|
value: https://github.com/openseadragon/openseadragon
|
||||||
|
description: Repository
|
||||||
|
repository-code: https://github.com/openseadragon/openseadragon
|
||||||
|
url: https://openseadragon.github.io/
|
||||||
|
abstract: "An open-source, web-based viewer for high-resolution zoomable images, implemented in pure JavaScript, for desktop and mobile."
|
||||||
|
keywords:
|
||||||
|
- javascript
|
||||||
|
- image
|
||||||
|
- zooming
|
||||||
|
- viewer
|
||||||
|
- image-viewer
|
||||||
|
- high-resolution
|
||||||
|
- iiif
|
||||||
|
license: BSD-3-Clause
|
||||||
|
version: 4.1.1
|
||||||
|
date-released: 2024-04-01
|
@ -5,18 +5,27 @@ OPENSEADRAGON CHANGELOG
|
|||||||
|
|
||||||
* BREAKING CHANGE: Dropped support for IE11 (#2300, #2361 @AndrewADev)
|
* BREAKING CHANGE: Dropped support for IE11 (#2300, #2361 @AndrewADev)
|
||||||
* DEPRECATION: The OpenSeadragon.createCallback function is no longer recommended (#2367 @akansjain)
|
* DEPRECATION: The OpenSeadragon.createCallback function is no longer recommended (#2367 @akansjain)
|
||||||
* The viewer now uses WebGL when available (#2310, #2462, #2466, #2468, #2469, #2472, #2478 @pearcetm, @Aiosa, @thec0keman)
|
* The viewer now uses WebGL when available (#2310, #2462, #2466, #2468, #2469, #2472, #2478, #2488, #2492 @pearcetm, @Aiosa, @thec0keman)
|
||||||
* Added webp to supported image formats (#2455 @BeebBenjamin)
|
* Added webp to supported image formats (#2455 @BeebBenjamin)
|
||||||
* Introduced maxTilesPerFrame option to allow loading more tiles simultaneously (#2387 @jetic83)
|
* Introduced maxTilesPerFrame option to allow loading more tiles simultaneously (#2387 @jetic83)
|
||||||
* Now when creating a viewer or navigator, we leave its position style alone if possible (#2393 @VIRAT9358)
|
* Now when creating a viewer or navigator, we leave its position style alone if possible (#2393 @VIRAT9358)
|
||||||
|
* Added getter & setter for Viewport.maxZoomPixelRatio (#2506 @eug-L)
|
||||||
* Test improvements (#2382 @AndrewADev)
|
* Test improvements (#2382 @AndrewADev)
|
||||||
* MouseTracker options documentation fixes (#2389 @msalsbery)
|
* MouseTracker options documentation fixes (#2389 @msalsbery)
|
||||||
|
* Improved documentation and error message for Viewport.imageToViewportZoom (#2505 @eug-L)
|
||||||
|
* Fixed documentation typos (#2507 @frameflare)
|
||||||
* Fixed: Sometimes if the viewport was flipped and the user zoomed in far enough, it would flip back (#2364 @SebDelile)
|
* Fixed: Sometimes if the viewport was flipped and the user zoomed in far enough, it would flip back (#2364 @SebDelile)
|
||||||
* Fixed: Strange behavior if IIIF sizes were not in ascending order (#2416 @lutzhelm)
|
|
||||||
* Fixed: Two-finger tap on a Mac trackpad would zoom you out (#2431 @cavenel)
|
* Fixed: Two-finger tap on a Mac trackpad would zoom you out (#2431 @cavenel)
|
||||||
* Fixed: dragToPan gesture could not be disabled when flickEnabled was activated (#2464 @jonasengelmann)
|
* Fixed: dragToPan gesture could not be disabled when flickEnabled was activated (#2464 @jonasengelmann)
|
||||||
* Fixed: placeholderFillStyle didn't work properly when the image was rotated (#2469 @pearcetm)
|
* Fixed: placeholderFillStyle didn't work properly when the image was rotated (#2469 @pearcetm)
|
||||||
* Fixed: Sometimes exponential springs wouldn't ever settle (#2469 @pearcetm)
|
* Fixed: Sometimes exponential springs wouldn't ever settle (#2469 @pearcetm)
|
||||||
|
* Fixed: The navigator wouldn't update its tracking rectangle when the navigator was resized (#2491 @pearcetm)
|
||||||
|
* Fixed: The drawer would improperly crop when the viewport was flipped and a tiled image was rotated (#2511 @pearcetm, @eug-L)
|
||||||
|
* Fixed: Flipped viewport caused image to be flipped again when going fullscreen or resizing (#2518 @pearcetm)
|
||||||
|
|
||||||
|
4.1.1:
|
||||||
|
|
||||||
|
* Fixed: Strange behavior if IIIF sizes were not in ascending order (#2416 @lutzhelm)
|
||||||
|
|
||||||
4.1.0:
|
4.1.0:
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "openseadragon",
|
"name": "openseadragon",
|
||||||
"version": "4.1.0",
|
"version": "4.1.1",
|
||||||
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
|
"description": "Provides a smooth, zoomable user interface for HTML/Javascript.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"image",
|
"image",
|
||||||
|
@ -80,7 +80,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
// Canvas default is "true", so this will only be changed if user specifies "false" in the options or via setImageSmoothinEnabled.
|
// Canvas default is "true", so this will only be changed if user specifies "false" in the options or via setImageSmoothinEnabled.
|
||||||
this._imageSmoothingEnabled = true;
|
this._imageSmoothingEnabled = true;
|
||||||
|
|
||||||
|
|
||||||
// Since the tile-drawn and tile-drawing events are fired by this drawer, make sure handlers can be added for them
|
// Since the tile-drawn and tile-drawing events are fired by this drawer, make sure handlers can be added for them
|
||||||
this.viewer.allowEventHandler("tile-drawn");
|
this.viewer.allowEventHandler("tile-drawn");
|
||||||
this.viewer.allowEventHandler("tile-drawing");
|
this.viewer.allowEventHandler("tile-drawing");
|
||||||
@ -119,7 +118,9 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
*/
|
*/
|
||||||
draw(tiledImages) {
|
draw(tiledImages) {
|
||||||
this._prepareNewFrame(); // prepare to draw a new frame
|
this._prepareNewFrame(); // prepare to draw a new frame
|
||||||
|
if(this.viewer.viewport.getFlip() !== this._viewportFlipped){
|
||||||
|
this._flip();
|
||||||
|
}
|
||||||
for(const tiledImage of tiledImages){
|
for(const tiledImage of tiledImages){
|
||||||
if (tiledImage.opacity !== 0) {
|
if (tiledImage.opacity !== 0) {
|
||||||
this._drawTiles(tiledImage);
|
this._drawTiles(tiledImage);
|
||||||
@ -147,10 +148,12 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {TiledImage} tiledImage the tiled image that is calling the function
|
||||||
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
minimumOverlapRequired() {
|
minimumOverlapRequired(tiledImage) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -189,6 +192,14 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test whether the current context is flipped or not
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
get _viewportFlipped(){
|
||||||
|
return this.context.getTransform().a < 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fires the tile-drawing event.
|
* Fires the tile-drawing event.
|
||||||
* @private
|
* @private
|
||||||
@ -310,13 +321,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
tiledImage.getClippedBounds(true))
|
tiledImage.getClippedBounds(true))
|
||||||
.getIntegerBoundingBox();
|
.getIntegerBoundingBox();
|
||||||
|
|
||||||
if(this.viewer.viewport.getFlip()) {
|
|
||||||
if (this.viewport.getRotation(true) % 360 !== 0 ||
|
|
||||||
tiledImage.getRotation(true) % 360 !== 0) {
|
|
||||||
bounds.x = this.viewer.container.clientWidth - (bounds.x + bounds.width);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bounds = bounds.times($.pixelDensityRatio);
|
bounds = bounds.times($.pixelDensityRatio);
|
||||||
}
|
}
|
||||||
this._clear(true, bounds);
|
this._clear(true, bounds);
|
||||||
@ -325,27 +329,7 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
// When scaling, we must rotate only when blending the sketch canvas to
|
// When scaling, we must rotate only when blending the sketch canvas to
|
||||||
// avoid interpolation
|
// avoid interpolation
|
||||||
if (!sketchScale) {
|
if (!sketchScale) {
|
||||||
if (this.viewport.getRotation(true) % 360 !== 0) {
|
this._setRotations(tiledImage, useSketch);
|
||||||
this._offsetForRotation({
|
|
||||||
degrees: this.viewport.getRotation(true),
|
|
||||||
useSketch: useSketch
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (tiledImage.getRotation(true) % 360 !== 0) {
|
|
||||||
this._offsetForRotation({
|
|
||||||
degrees: tiledImage.getRotation(true),
|
|
||||||
point: this.viewport.pixelFromPointNoRotate(
|
|
||||||
tiledImage._getRotationPoint(true), true),
|
|
||||||
useSketch: useSketch
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.viewport.getRotation(true) % 360 === 0 &&
|
|
||||||
tiledImage.getRotation(true) % 360 === 0) {
|
|
||||||
if(this.viewer.viewport.getFlip()) {
|
|
||||||
this._flip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let usedClip = false;
|
let usedClip = false;
|
||||||
@ -465,20 +449,7 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
|
|
||||||
if (useSketch) {
|
if (useSketch) {
|
||||||
if (sketchScale) {
|
if (sketchScale) {
|
||||||
if (this.viewport.getRotation(true) % 360 !== 0) {
|
this._setRotations(tiledImage);
|
||||||
this._offsetForRotation({
|
|
||||||
degrees: this.viewport.getRotation(true),
|
|
||||||
useSketch: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (tiledImage.getRotation(true) % 360 !== 0) {
|
|
||||||
this._offsetForRotation({
|
|
||||||
degrees: tiledImage.getRotation(true),
|
|
||||||
point: this.viewport.pixelFromPointNoRotate(
|
|
||||||
tiledImage._getRotationPoint(true), true),
|
|
||||||
useSketch: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
this.blendSketch({
|
this.blendSketch({
|
||||||
opacity: tiledImage.opacity,
|
opacity: tiledImage.opacity,
|
||||||
@ -497,15 +468,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sketchScale) {
|
|
||||||
if (this.viewport.getRotation(true) % 360 === 0 &&
|
|
||||||
tiledImage.getRotation(true) % 360 === 0) {
|
|
||||||
if(this.viewer.viewport.getFlip()) {
|
|
||||||
this._flip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this._drawDebugInfo( tiledImage, lastDrawn );
|
this._drawDebugInfo( tiledImage, lastDrawn );
|
||||||
|
|
||||||
// Fire tiled-image-drawn event.
|
// Fire tiled-image-drawn event.
|
||||||
@ -587,7 +549,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
size = tile.size.times($.pixelDensityRatio);
|
size = tile.size.times($.pixelDensityRatio);
|
||||||
|
|
||||||
context.save();
|
context.save();
|
||||||
// context.globalAlpha = this.options.opacity; // this was deprecated previously and should not be applied as it is set per TiledImage
|
|
||||||
|
|
||||||
if (typeof scale === 'number' && scale !== 1) {
|
if (typeof scale === 'number' && scale !== 1) {
|
||||||
// draw tile at a different scale
|
// draw tile at a different scale
|
||||||
@ -835,21 +796,10 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
context.strokeStyle = this.debugGridColor[colorIndex];
|
context.strokeStyle = this.debugGridColor[colorIndex];
|
||||||
context.fillStyle = this.debugGridColor[colorIndex];
|
context.fillStyle = this.debugGridColor[colorIndex];
|
||||||
|
|
||||||
if (this.viewport.getRotation(true) % 360 !== 0 ) {
|
this._setRotations(tiledImage);
|
||||||
this._offsetForRotation({degrees: this.viewport.getRotation(true)});
|
|
||||||
}
|
if(this._viewportFlipped){
|
||||||
if (tiledImage.getRotation(true) % 360 !== 0) {
|
this._flip({point: tile.position.plus(tile.size.divide(2))});
|
||||||
this._offsetForRotation({
|
|
||||||
degrees: tiledImage.getRotation(true),
|
|
||||||
point: tiledImage.viewport.pixelFromPointNoRotate(
|
|
||||||
tiledImage._getRotationPoint(true), true)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
|
|
||||||
tiledImage.getRotation(true) % 360 === 0) {
|
|
||||||
if(tiledImage._drawer.viewer.viewport.getFlip()) {
|
|
||||||
tiledImage._drawer._flip();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.strokeRect(
|
context.strokeRect(
|
||||||
@ -864,7 +814,8 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
|
|
||||||
// Rotate the text the right way around.
|
// Rotate the text the right way around.
|
||||||
context.translate( tileCenterX, tileCenterY );
|
context.translate( tileCenterX, tileCenterY );
|
||||||
context.rotate( Math.PI / 180 * -this.viewport.getRotation(true) );
|
const angleInDegrees = this.viewport.getRotation(true);
|
||||||
|
context.rotate( Math.PI / 180 * -angleInDegrees );
|
||||||
context.translate( -tileCenterX, -tileCenterY );
|
context.translate( -tileCenterX, -tileCenterY );
|
||||||
|
|
||||||
if( tile.x === 0 && tile.y === 0 ){
|
if( tile.x === 0 && tile.y === 0 ){
|
||||||
@ -917,13 +868,6 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
this._restoreRotationChanges();
|
this._restoreRotationChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
|
|
||||||
tiledImage.getRotation(true) % 360 === 0) {
|
|
||||||
if(tiledImage._drawer.viewer.viewport.getFlip()) {
|
|
||||||
tiledImage._drawer._flip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -954,6 +898,33 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
return new $.Point(this.canvas.width / 2, this.canvas.height / 2);
|
return new $.Point(this.canvas.width / 2, this.canvas.height / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set rotations for viewport & tiledImage
|
||||||
|
* @private
|
||||||
|
* @param {OpenSeadragon.TiledImage} tiledImage
|
||||||
|
* @param {Boolean} [useSketch=false]
|
||||||
|
*/
|
||||||
|
_setRotations(tiledImage, useSketch = false) {
|
||||||
|
var saveContext = false;
|
||||||
|
if (this.viewport.getRotation(true) % 360 !== 0) {
|
||||||
|
this._offsetForRotation({
|
||||||
|
degrees: this.viewport.getRotation(true),
|
||||||
|
useSketch: useSketch,
|
||||||
|
saveContext: saveContext
|
||||||
|
});
|
||||||
|
saveContext = false;
|
||||||
|
}
|
||||||
|
if (tiledImage.getRotation(true) % 360 !== 0) {
|
||||||
|
this._offsetForRotation({
|
||||||
|
degrees: tiledImage.getRotation(true),
|
||||||
|
point: this.viewport.pixelFromPointNoRotate(
|
||||||
|
tiledImage._getRotationPoint(true), true),
|
||||||
|
useSketch: useSketch,
|
||||||
|
saveContext: saveContext
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
_offsetForRotation(options) {
|
_offsetForRotation(options) {
|
||||||
var point = options.point ?
|
var point = options.point ?
|
||||||
@ -964,26 +935,21 @@ class CanvasDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
context.save();
|
context.save();
|
||||||
|
|
||||||
context.translate(point.x, point.y);
|
context.translate(point.x, point.y);
|
||||||
if(this.viewer.viewport.flipped){
|
context.rotate(Math.PI / 180 * options.degrees);
|
||||||
context.rotate(Math.PI / 180 * -options.degrees);
|
|
||||||
context.scale(-1, 1);
|
|
||||||
} else{
|
|
||||||
context.rotate(Math.PI / 180 * options.degrees);
|
|
||||||
}
|
|
||||||
context.translate(-point.x, -point.y);
|
context.translate(-point.x, -point.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
_flip(options) {
|
_flip(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
var point = options.point ?
|
var point = options.point ?
|
||||||
options.point.times($.pixelDensityRatio) :
|
options.point.times($.pixelDensityRatio) :
|
||||||
this._getCanvasCenter();
|
this._getCanvasCenter();
|
||||||
var context = this._getContext(options.useSketch);
|
var context = this._getContext(options.useSketch);
|
||||||
|
|
||||||
context.translate(point.x, 0);
|
context.translate(point.x, 0);
|
||||||
context.scale(-1, 1);
|
context.scale(-1, 1);
|
||||||
context.translate(-point.x, 0);
|
context.translate(-point.x, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
|
@ -188,10 +188,11 @@ OpenSeadragon.DrawerBase = class DrawerBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {TiledImage} tiledImage the tiled image that is calling the function
|
||||||
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
minimumOverlapRequired() {
|
minimumOverlapRequired(tiledImage) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,11 +90,13 @@ class HTMLDrawer extends OpenSeadragon.DrawerBase{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param {TiledImage} tiledImage the tiled image that is calling the function
|
||||||
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
minimumOverlapRequired() {
|
minimumOverlapRequired(tiledImage) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create the HTML element (e.g. canvas, div) that the image will be drawn into
|
* create the HTML element (e.g. canvas, div) that the image will be drawn into
|
||||||
|
@ -309,6 +309,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
|||||||
this.oldContainerSize = containerSize;
|
this.oldContainerSize = containerSize;
|
||||||
this.world.update();
|
this.world.update();
|
||||||
this.world.draw();
|
this.world.draw();
|
||||||
|
this.update(this.viewer.viewport);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -355,7 +356,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
|||||||
/**
|
/**
|
||||||
* Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.
|
* Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.
|
||||||
* @function
|
* @function
|
||||||
* @param {OpenSeadragon.Viewport} The viewport this navigator is tracking.
|
* @param {OpenSeadragon.Viewport} [viewport] The viewport to display. Default: the viewport this navigator is tracking.
|
||||||
*/
|
*/
|
||||||
update: function( viewport ) {
|
update: function( viewport ) {
|
||||||
|
|
||||||
@ -366,6 +367,10 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
|||||||
topleft,
|
topleft,
|
||||||
bottomright;
|
bottomright;
|
||||||
|
|
||||||
|
if(!viewport){
|
||||||
|
viewport = this.viewer.viewport;
|
||||||
|
}
|
||||||
|
|
||||||
viewerSize = $.getElementSize( this.viewer.element );
|
viewerSize = $.getElementSize( this.viewer.element );
|
||||||
if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) {
|
if ( this._resizeWithViewer && viewerSize.x && viewerSize.y && !viewerSize.equals( this.oldViewerSize ) ) {
|
||||||
this.oldViewerSize = viewerSize;
|
this.oldViewerSize = viewerSize;
|
||||||
|
@ -1741,7 +1741,7 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
|||||||
tileCenter = positionT.plus( sizeT.divide( 2 ) ),
|
tileCenter = positionT.plus( sizeT.divide( 2 ) ),
|
||||||
tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter );
|
tileSquaredDistance = viewportCenter.squaredDistanceTo( tileCenter );
|
||||||
|
|
||||||
if(this.viewer.drawer.minimumOverlapRequired()){
|
if(this.viewer.drawer.minimumOverlapRequired(this)){
|
||||||
if ( !overlap ) {
|
if ( !overlap ) {
|
||||||
sizeC = sizeC.plus( new $.Point(1, 1));
|
sizeC = sizeC.plus( new $.Point(1, 1));
|
||||||
}
|
}
|
||||||
|
@ -585,13 +585,13 @@ $.TileSource.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible determining if a the particular TileSource supports the
|
* Responsible for determining if the particular TileSource supports the
|
||||||
* data format ( and allowed to apply logic against the url the data was
|
* data format ( and allowed to apply logic against the url the data was
|
||||||
* loaded from, if any ). Overriding implementations are expected to do
|
* loaded from, if any ). Overriding implementations are expected to do
|
||||||
* something smart with data and / or url to determine support. Also
|
* something smart with data and / or url to determine support. Also
|
||||||
* understand that iteration order of TileSources is not guarunteed so
|
* understand that iteration order of TileSources is not guaranteed so
|
||||||
* please make sure your data or url is expressive enough to ensure a simple
|
* please make sure your data or url is expressive enough to ensure a simple
|
||||||
* and sufficient mechanisim for clear determination.
|
* and sufficient mechanism for clear determination.
|
||||||
* @function
|
* @function
|
||||||
* @param {String|Object|Array|Document} data
|
* @param {String|Object|Array|Document} data
|
||||||
* @param {String} url - the url the data was loaded
|
* @param {String} url - the url the data was loaded
|
||||||
@ -828,7 +828,7 @@ $.TileSource.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Load the tile with an AJAX request if the loadWithAjax option is
|
// Load the tile with an AJAX request if the loadWithAjax option is
|
||||||
// set. Otherwise load the image by setting the source proprety of the image object.
|
// set. Otherwise load the image by setting the source property of the image object.
|
||||||
if (context.loadWithAjax) {
|
if (context.loadWithAjax) {
|
||||||
dataStore.request = $.makeAjaxRequest({
|
dataStore.request = $.makeAjaxRequest({
|
||||||
url: context.src,
|
url: context.src,
|
||||||
|
@ -2206,7 +2206,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
|||||||
* viewport which the location coordinates will be treated as relative
|
* viewport which the location coordinates will be treated as relative
|
||||||
* to.
|
* to.
|
||||||
* @param {function} [onDraw] - If supplied the callback is called when the overlay
|
* @param {function} [onDraw] - If supplied the callback is called when the overlay
|
||||||
* needs to be drawn. It it the responsibility of the callback to do any drawing/positioning.
|
* needs to be drawn. It is the responsibility of the callback to do any drawing/positioning.
|
||||||
* It is passed position, size and element.
|
* It is passed position, size and element.
|
||||||
* @returns {OpenSeadragon.Viewer} Chainable.
|
* @returns {OpenSeadragon.Viewer} Chainable.
|
||||||
* @fires OpenSeadragon.Viewer.event:add-overlay
|
* @fires OpenSeadragon.Viewer.event:add-overlay
|
||||||
|
@ -1711,7 +1711,7 @@ $.Viewport.prototype = {
|
|||||||
* 1 means original image size, 0.5 half size...
|
* 1 means original image size, 0.5 half size...
|
||||||
* Viewport zoom: ratio of the displayed image's width to viewport's width.
|
* Viewport zoom: ratio of the displayed image's width to viewport's width.
|
||||||
* 1 means identical width, 2 means image's width is twice the viewport's width...
|
* 1 means identical width, 2 means image's width is twice the viewport's width...
|
||||||
* Note: not accurate with multi-image.
|
* Note: not accurate with multi-image; use [TiledImage.imageToViewportZoom] for the specific image of interest.
|
||||||
* @function
|
* @function
|
||||||
* @param {Number} imageZoom The image zoom
|
* @param {Number} imageZoom The image zoom
|
||||||
* target zoom.
|
* target zoom.
|
||||||
@ -1723,7 +1723,7 @@ $.Viewport.prototype = {
|
|||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
if (!this.silenceMultiImageWarnings) {
|
if (!this.silenceMultiImageWarnings) {
|
||||||
$.console.error('[Viewport.imageToViewportZoom] is not accurate ' +
|
$.console.error('[Viewport.imageToViewportZoom] is not accurate ' +
|
||||||
'with multi-image.');
|
'with multi-image. Instead, use [TiledImage.imageToViewportZoom] for the specific image of interest');
|
||||||
}
|
}
|
||||||
} else if (count === 1) {
|
} else if (count === 1) {
|
||||||
// It is better to use TiledImage.imageToViewportZoom
|
// It is better to use TiledImage.imageToViewportZoom
|
||||||
@ -1789,7 +1789,41 @@ $.Viewport.prototype = {
|
|||||||
*/
|
*/
|
||||||
this.viewer.raiseEvent('flip', {flipped: state});
|
this.viewer.raiseEvent('flip', {flipped: state});
|
||||||
return this;
|
return this;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets current max zoom pixel ratio
|
||||||
|
* @function
|
||||||
|
* @returns {Number} Max zoom pixel ratio
|
||||||
|
*/
|
||||||
|
getMaxZoomPixelRatio: function() {
|
||||||
|
return this.maxZoomPixelRatio;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets max zoom pixel ratio
|
||||||
|
* @function
|
||||||
|
* @param {Number} ratio - Max zoom pixel ratio
|
||||||
|
* @param {Boolean} [applyConstraints=true] - Apply constraints after setting ratio;
|
||||||
|
* Takes effect only if current zoom is greater than set max zoom pixel ratio
|
||||||
|
* @param {Boolean} [immediately=false] - Whether to animate to new zoom
|
||||||
|
*/
|
||||||
|
setMaxZoomPixelRatio: function(ratio, applyConstraints = true, immediately = false) {
|
||||||
|
|
||||||
|
$.console.assert(!isNaN(ratio), "[Viewport.setMaxZoomPixelRatio] ratio must be a number");
|
||||||
|
|
||||||
|
if (isNaN(ratio)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.maxZoomPixelRatio = ratio;
|
||||||
|
|
||||||
|
if (applyConstraints) {
|
||||||
|
if (this.getZoom() > this.getMaxZoom()) {
|
||||||
|
this.applyConstraints(immediately);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -206,6 +206,16 @@
|
|||||||
return 'webgl';
|
return 'webgl';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {TiledImage} tiledImage the tiled image that is calling the function
|
||||||
|
* @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
minimumOverlapRequired(tiledImage) {
|
||||||
|
// return true if the tiled image is tainted, since the backup canvas drawer will be used.
|
||||||
|
return tiledImage.isTainted();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* create the HTML element (canvas in this case) that the image will be drawn into
|
* create the HTML element (canvas in this case) that the image will be drawn into
|
||||||
* @private
|
* @private
|
||||||
@ -347,7 +357,7 @@
|
|||||||
// This can apparently happen on some systems if too many WebGL contexts have been created
|
// This can apparently happen on some systems if too many WebGL contexts have been created
|
||||||
// in which case maxTextures can be null, leading to out of bounds errors with the array.
|
// in which case maxTextures can be null, leading to out of bounds errors with the array.
|
||||||
// For example, when viewers were created and not destroyed in the test suite, this error
|
// For example, when viewers were created and not destroyed in the test suite, this error
|
||||||
// occured in the TravisCI tests, though it did not happen when testing locally either in
|
// occurred in the TravisCI tests, though it did not happen when testing locally either in
|
||||||
// a browser or on the command line via grunt test.
|
// a browser or on the command line via grunt test.
|
||||||
|
|
||||||
throw(new Error(`WegGL error: bad value for gl parameter MAX_TEXTURE_IMAGE_UNITS (${maxTextures}). This could happen
|
throw(new Error(`WegGL error: bad value for gl parameter MAX_TEXTURE_IMAGE_UNITS (${maxTextures}). This could happen
|
||||||
@ -513,10 +523,14 @@
|
|||||||
}
|
}
|
||||||
this._outputContext.restore();
|
this._outputContext.restore();
|
||||||
if(tiledImage.debugMode){
|
if(tiledImage.debugMode){
|
||||||
let colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length;
|
const flipped = this.viewer.viewport.getFlip();
|
||||||
let strokeStyle = this.debugGridColor[colorIndex];
|
if(flipped){
|
||||||
let fillStyle = this.debugGridColor[colorIndex];
|
this._flip();
|
||||||
this._drawDebugInfo(tilesToDraw, tiledImage, strokeStyle, fillStyle);
|
}
|
||||||
|
this._drawDebugInfo(tilesToDraw, tiledImage, flipped);
|
||||||
|
if(flipped){
|
||||||
|
this._flip();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -998,32 +1012,64 @@
|
|||||||
this._clippingContext.restore();
|
this._clippingContext.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set rotations for viewport & tiledImage
|
||||||
|
* @private
|
||||||
|
* @param {OpenSeadragon.TiledImage} tiledImage
|
||||||
|
*/
|
||||||
|
_setRotations(tiledImage) {
|
||||||
|
var saveContext = false;
|
||||||
|
if (this.viewport.getRotation(true) % 360 !== 0) {
|
||||||
|
this._offsetForRotation({
|
||||||
|
degrees: this.viewport.getRotation(true),
|
||||||
|
saveContext: saveContext
|
||||||
|
});
|
||||||
|
saveContext = false;
|
||||||
|
}
|
||||||
|
if (tiledImage.getRotation(true) % 360 !== 0) {
|
||||||
|
this._offsetForRotation({
|
||||||
|
degrees: tiledImage.getRotation(true),
|
||||||
|
point: this.viewport.pixelFromPointNoRotate(
|
||||||
|
tiledImage._getRotationPoint(true), true),
|
||||||
|
saveContext: saveContext
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
_offsetForRotation(options) {
|
_offsetForRotation(options) {
|
||||||
var point = options.point ?
|
var point = options.point ?
|
||||||
options.point.times($.pixelDensityRatio) :
|
options.point.times($.pixelDensityRatio) :
|
||||||
new $.Point(this._outputCanvas.width / 2, this._outputCanvas.height / 2);
|
this._getCanvasCenter();
|
||||||
|
|
||||||
var context = this._outputContext;
|
var context = this._outputContext;
|
||||||
context.save();
|
context.save();
|
||||||
|
|
||||||
context.translate(point.x, point.y);
|
context.translate(point.x, point.y);
|
||||||
if(this.viewport.flipped){
|
context.rotate(Math.PI / 180 * options.degrees);
|
||||||
context.rotate(Math.PI / 180 * -options.degrees);
|
|
||||||
context.scale(-1, 1);
|
|
||||||
} else{
|
|
||||||
context.rotate(Math.PI / 180 * options.degrees);
|
|
||||||
}
|
|
||||||
context.translate(-point.x, -point.y);
|
context.translate(-point.x, -point.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
_drawDebugInfo( tilesToDraw, tiledImage, stroke, fill ) {
|
_flip(options) {
|
||||||
|
options = options || {};
|
||||||
|
var point = options.point ?
|
||||||
|
options.point.times($.pixelDensityRatio) :
|
||||||
|
this._getCanvasCenter();
|
||||||
|
var context = this._outputContext;
|
||||||
|
|
||||||
|
context.translate(point.x, 0);
|
||||||
|
context.scale(-1, 1);
|
||||||
|
context.translate(-point.x, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private
|
||||||
|
_drawDebugInfo( tilesToDraw, tiledImage, flipped ) {
|
||||||
|
|
||||||
for ( var i = tilesToDraw.length - 1; i >= 0; i-- ) {
|
for ( var i = tilesToDraw.length - 1; i >= 0; i-- ) {
|
||||||
var tile = tilesToDraw[ i ].tile;
|
var tile = tilesToDraw[ i ].tile;
|
||||||
try {
|
try {
|
||||||
this._drawDebugInfoOnTile(tile, tilesToDraw.length, i, tiledImage, stroke, fill);
|
this._drawDebugInfoOnTile(tile, tilesToDraw.length, i, tiledImage, flipped);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
$.console.error(e);
|
$.console.error(e);
|
||||||
}
|
}
|
||||||
@ -1031,30 +1077,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
_drawDebugInfoOnTile(tile, count, i, tiledImage, stroke, fill) {
|
_drawDebugInfoOnTile(tile, count, i, tiledImage, flipped) {
|
||||||
|
|
||||||
var context = this._outputContext;
|
var colorIndex = this.viewer.world.getIndexOfItem(tiledImage) % this.debugGridColor.length;
|
||||||
|
var context = this.context;
|
||||||
context.save();
|
context.save();
|
||||||
context.lineWidth = 2 * $.pixelDensityRatio;
|
context.lineWidth = 2 * $.pixelDensityRatio;
|
||||||
context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
|
context.font = 'small-caps bold ' + (13 * $.pixelDensityRatio) + 'px arial';
|
||||||
context.strokeStyle = stroke;
|
context.strokeStyle = this.debugGridColor[colorIndex];
|
||||||
context.fillStyle = fill;
|
context.fillStyle = this.debugGridColor[colorIndex];
|
||||||
|
|
||||||
if (this.viewport.getRotation(true) % 360 !== 0 ) {
|
this._setRotations(tiledImage);
|
||||||
this._offsetForRotation({degrees: this.viewport.getRotation(true)});
|
|
||||||
}
|
if(flipped){
|
||||||
if (tiledImage.getRotation(true) % 360 !== 0) {
|
this._flip({point: tile.position.plus(tile.size.divide(2))});
|
||||||
this._offsetForRotation({
|
|
||||||
degrees: tiledImage.getRotation(true),
|
|
||||||
point: tiledImage.viewport.pixelFromPointNoRotate(
|
|
||||||
tiledImage._getRotationPoint(true), true)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
|
|
||||||
tiledImage.getRotation(true) % 360 === 0) {
|
|
||||||
if(tiledImage._drawer.viewer.viewport.getFlip()) {
|
|
||||||
tiledImage._drawer._flip();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.strokeRect(
|
context.strokeRect(
|
||||||
@ -1069,7 +1105,8 @@
|
|||||||
|
|
||||||
// Rotate the text the right way around.
|
// Rotate the text the right way around.
|
||||||
context.translate( tileCenterX, tileCenterY );
|
context.translate( tileCenterX, tileCenterY );
|
||||||
context.rotate( Math.PI / 180 * -this.viewport.getRotation(true) );
|
const angleInDegrees = this.viewport.getRotation(true);
|
||||||
|
context.rotate( Math.PI / 180 * -angleInDegrees );
|
||||||
context.translate( -tileCenterX, -tileCenterY );
|
context.translate( -tileCenterX, -tileCenterY );
|
||||||
|
|
||||||
if( tile.x === 0 && tile.y === 0 ){
|
if( tile.x === 0 && tile.y === 0 ){
|
||||||
@ -1122,13 +1159,6 @@
|
|||||||
this._restoreRotationChanges();
|
this._restoreRotationChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tiledImage.viewport.getRotation(true) % 360 === 0 &&
|
|
||||||
tiledImage.getRotation(true) % 360 === 0) {
|
|
||||||
if(tiledImage._drawer.viewer.viewport.getFlip()) {
|
|
||||||
tiledImage._drawer._flip();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1156,6 +1186,15 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the canvas center
|
||||||
|
* @private
|
||||||
|
* @returns {OpenSeadragon.Point} The center point of the canvas
|
||||||
|
*/
|
||||||
|
_getCanvasCenter() {
|
||||||
|
return new $.Point(this.canvas.width / 2, this.canvas.height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
// private
|
// private
|
||||||
_restoreRotationChanges() {
|
_restoreRotationChanges() {
|
||||||
var context = this._outputContext;
|
var context = this._outputContext;
|
||||||
|
13
src/world.js
13
src/world.js
@ -277,11 +277,14 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
|
|||||||
* Draws all items.
|
* Draws all items.
|
||||||
*/
|
*/
|
||||||
draw: function() {
|
draw: function() {
|
||||||
this.viewer.drawer.draw(this._items);
|
return new $.Promise((resolve) => {
|
||||||
this._needsDraw = false;
|
this.viewer.drawer.draw(this._items);
|
||||||
for (let item of this._items) {
|
this._needsDraw = false;
|
||||||
this._needsDraw = item.setDrawn() || this._needsDraw;
|
for (let item of this._items) {
|
||||||
}
|
this._needsDraw = item.setDrawn() || this._needsDraw;
|
||||||
|
}
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
35
test/demo/basic2.html
Normal file
35
test/demo/basic2.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>OpenSeadragon maxTilesPerFrame 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: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
Simple demo page to show an OpenSeadragon viewer with a higher maxTilesPerFrame.
|
||||||
|
</div>
|
||||||
|
<div id="contentDiv" class="openseadragon1"></div>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
var viewer = OpenSeadragon({
|
||||||
|
debugMode: true,
|
||||||
|
id: "contentDiv",
|
||||||
|
prefixUrl: "../../build/openseadragon/images/",
|
||||||
|
tileSources: "https://openseadragon.github.io/example-images/duomo/duomo.dzi",
|
||||||
|
showNavigator:true,
|
||||||
|
debugMode:true,
|
||||||
|
maxTilesPerFrame:3,
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -243,7 +243,7 @@
|
|||||||
/*
|
/*
|
||||||
* FIXME: following https://iiif.io/api/image/3.0/#47-canonical-uri-syntax and
|
* FIXME: following https://iiif.io/api/image/3.0/#47-canonical-uri-syntax and
|
||||||
* https://iiif.io/api/image/2.1/#canonical-uri-syntax, I'd expect 'max' to be required to
|
* https://iiif.io/api/image/2.1/#canonical-uri-syntax, I'd expect 'max' to be required to
|
||||||
* be served by a level 0 compliant service instead of 'w,h', 'full' instead of 'w,' respectivley.
|
* be served by a level 0 compliant service instead of 'w,h', 'full' instead of 'w,' respectively.
|
||||||
*/
|
*/
|
||||||
//assert.equal(levelsVersion3[1].url, 'http://example.com/identifier/full/max/0/default.jpg');
|
//assert.equal(levelsVersion3[1].url, 'http://example.com/identifier/full/max/0/default.jpg');
|
||||||
});
|
});
|
||||||
|
@ -1407,4 +1407,25 @@
|
|||||||
viewer.open(DZI_PATH);
|
viewer.open(DZI_PATH);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
QUnit.test('setMaxZoomPixelRatio', function(assert) {
|
||||||
|
var done = assert.async();
|
||||||
|
var openHandler = function(event) {
|
||||||
|
viewer.removeHandler('open', openHandler);
|
||||||
|
var viewport = viewer.viewport;
|
||||||
|
|
||||||
|
for (var i = 0; i < testZoomLevels.length; i++) {
|
||||||
|
viewport.setMaxZoomPixelRatio(testZoomLevels[i])
|
||||||
|
assert.equal(viewport.getMaxZoomPixelRatio(), testZoomLevels[i], "Max zoom pixel ratio is set correctly.");
|
||||||
|
}
|
||||||
|
|
||||||
|
viewport.zoomTo(viewport.getMaxZoom())
|
||||||
|
viewport.setMaxZoomPixelRatio(testZoomLevels[0], true)
|
||||||
|
assert.equal(viewport.getZoom(), viewport.getMaxZoom(), "Zoom should be adjusted to max zoom level.");
|
||||||
|
|
||||||
|
done();
|
||||||
|
};
|
||||||
|
viewer.addHandler('open', openHandler);
|
||||||
|
viewer.open(DZI_PATH);
|
||||||
|
});
|
||||||
|
|
||||||
})();
|
})();
|
||||||
|
Loading…
Reference in New Issue
Block a user