mirror of
https://github.com/openseadragon/openseadragon.git
synced 2024-11-24 06:06:09 +03:00
Merge branch 'master' into ms-reference-strip
* master: (27 commits) Changelog for #1968 Fixing issue where the ajaxHeaders were not being set for image requests Changelog for #1865 Changelog for #1937 Changelog for #1903 refactor: moved methods that belongs together closer Make setFlip() update the navigator refactor: use pixelDensityRatio in getPixelRatio() fix: removes resize event on destroy docs: fixed typo and corrected the comment fix: made updatePixelDensityRatio private Improve the flipping example Tidy up the tile/image flip check Force reload tiles when the tile's flip doesn't match the image Add a basic setFlip method to TiledImage Add flipping example Correctly set the rightmost tile property when flipped Render the flipped columns in reverse order Store the flipped state in each tile and render it as such Introduce getTileBounds method for tiledImage ...
This commit is contained in:
commit
e69f8d079e
@ -44,6 +44,10 @@ OPENSEADRAGON CHANGELOG
|
||||
* Fixed test "Events: Viewer: preventDefaultAction in dblClickHandler". Fixes #1372 (#1960 @msalsbery)
|
||||
* ReferenceStrip: Fixed issue where its element was being removed from its parent element twice on destroy, causing an exception (#1958 @msalsbery)
|
||||
* ReferenceStrip: Made its element focusable for keyboard navigation (#1958 @msalsbery)
|
||||
* You can now flip individual images (not just the whole viewport) (#1903 @ali1234)
|
||||
* Accessibility: we now take the browser's zoom into account when choosing what detail level to draw (#1937 @ronnymikalsen)
|
||||
* Fixed a bug causing overlays to disappear in Sequence Mode (#1865 @gunmiosb)
|
||||
* Fixed a bug where the ajaxHeaders provided per-image were not being used for image requests (#1968 @maxshuty)
|
||||
|
||||
2.4.2:
|
||||
|
||||
|
@ -452,6 +452,7 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
|
||||
myItem.setWidth(bounds.width, immediately);
|
||||
myItem.setRotation(theirItem.getRotation(), immediately);
|
||||
myItem.setClip(theirItem.getClip());
|
||||
myItem.setFlip(theirItem.getFlip());
|
||||
},
|
||||
|
||||
// private
|
||||
|
@ -986,7 +986,7 @@ function OpenSeadragon( options ){
|
||||
* @member {Number} pixelDensityRatio
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.pixelDensityRatio = (function () {
|
||||
$.getCurrentPixelDensityRatio = function() {
|
||||
if ( $.supportsCanvas ) {
|
||||
var context = document.createElement('canvas').getContext('2d');
|
||||
var devicePixelRatio = window.devicePixelRatio || 1;
|
||||
@ -999,7 +999,13 @@ function OpenSeadragon( options ){
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}());
|
||||
};
|
||||
|
||||
/**
|
||||
* @member {Number} pixelDensityRatio
|
||||
* @memberof OpenSeadragon
|
||||
*/
|
||||
$.pixelDensityRatio = $.getCurrentPixelDensityRatio();
|
||||
|
||||
}( OpenSeadragon ));
|
||||
|
||||
|
@ -288,10 +288,7 @@
|
||||
style[transformProp] = "";
|
||||
}
|
||||
}
|
||||
|
||||
if (style.display !== 'none') {
|
||||
style.display = 'block';
|
||||
}
|
||||
style.display = 'block';
|
||||
}
|
||||
},
|
||||
|
||||
|
16
src/tile.js
16
src/tile.js
@ -176,6 +176,12 @@ $.Tile = function(level, x, y, bounds, exists, url, context2D, loadWithAjax, aja
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.size = null;
|
||||
/**
|
||||
* Whether to flip the tile when rendering.
|
||||
* @member {Boolean} flipped
|
||||
* @memberof OpenSeadragon.Tile#
|
||||
*/
|
||||
this.flipped = false;
|
||||
/**
|
||||
* The start time of this tile's blending.
|
||||
* @member {Number} blendStart
|
||||
@ -296,6 +302,10 @@ $.Tile.prototype = {
|
||||
this.style.height = this.size.y + "px";
|
||||
this.style.width = this.size.x + "px";
|
||||
|
||||
if (this.flipped) {
|
||||
this.style.transform = "scaleX(-1)";
|
||||
}
|
||||
|
||||
$.setElementOpacity( this.element, this.opacity );
|
||||
},
|
||||
|
||||
@ -376,13 +386,17 @@ $.Tile.prototype = {
|
||||
sourceHeight = rendered.canvas.height;
|
||||
}
|
||||
|
||||
context.translate(position.x + size.x / 2, 0);
|
||||
if (this.flipped) {
|
||||
context.scale(-1, 1);
|
||||
}
|
||||
context.drawImage(
|
||||
rendered.canvas,
|
||||
0,
|
||||
0,
|
||||
sourceWidth,
|
||||
sourceHeight,
|
||||
position.x,
|
||||
-size.x / 2,
|
||||
position.y,
|
||||
size.x,
|
||||
size.y
|
||||
|
@ -392,6 +392,26 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
return bounds.rotate(this.getRotation(current), this._getRotationPoint(current));
|
||||
},
|
||||
|
||||
/**
|
||||
* @function
|
||||
* @param {Number} level
|
||||
* @param {Number} x
|
||||
* @param {Number} y
|
||||
* @returns {OpenSeadragon.Rect} Where this tile fits (in normalized coordinates).
|
||||
*/
|
||||
getTileBounds: function( level, x, y ) {
|
||||
var numTiles = this.source.getNumTiles(level);
|
||||
var xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;
|
||||
var yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
|
||||
var bounds = this.source.getTileBounds(level, xMod, yMod);
|
||||
if (this.getFlip()) {
|
||||
bounds.x = 1 - bounds.x - bounds.width;
|
||||
}
|
||||
bounds.x += (x - xMod) / numTiles.x;
|
||||
bounds.y += (this._worldHeightCurrent / this._worldWidthCurrent) * ((y - yMod) / numTiles.y);
|
||||
return bounds;
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels.
|
||||
*/
|
||||
@ -832,6 +852,23 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
|
||||
this.raiseEvent('clip-change');
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Boolean} Whether the TiledImage should be flipped before rendering.
|
||||
*/
|
||||
getFlip: function() {
|
||||
return !!this.flipped;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Boolean} flip Whether the TiledImage should be flipped before rendering.
|
||||
* @fires OpenSeadragon.TiledImage.event:bounds-change
|
||||
*/
|
||||
setFlip: function(flip) {
|
||||
this.flipped = !!flip;
|
||||
this._needsDraw = true;
|
||||
this._raiseBoundsChange();
|
||||
},
|
||||
|
||||
/**
|
||||
* @returns {Number} The TiledImage's current opacity.
|
||||
*/
|
||||
@ -1255,24 +1292,41 @@ function updateLevel(tiledImage, haveDrawn, drawLevel, level, levelOpacity,
|
||||
|
||||
var viewportCenter = tiledImage.viewport.pixelFromPoint(
|
||||
tiledImage.viewport.getCenter());
|
||||
|
||||
if (tiledImage.getFlip()) {
|
||||
// The right-most tile can be narrower than the others. When flipped,
|
||||
// this tile is now on the left. Because it is narrower than the normal
|
||||
// left-most tile, the subsequent tiles may not be wide enough to completely
|
||||
// fill the viewport. Fix this by rendering an extra column of tiles. If we
|
||||
// are not wrapping, make sure we never render more than the number of tiles
|
||||
// in the image.
|
||||
bottomRightTile.x += 1;
|
||||
if (!tiledImage.wrapHorizontal) {
|
||||
bottomRightTile.x = Math.min(bottomRightTile.x, numberOfTiles.x - 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (var x = topLeftTile.x; x <= bottomRightTile.x; x++) {
|
||||
for (var y = topLeftTile.y; y <= bottomRightTile.y; y++) {
|
||||
|
||||
// Optimisation disabled with wrapping because getTileBounds does not
|
||||
// work correctly with x and y outside of the number of tiles
|
||||
if (!tiledImage.wrapHorizontal && !tiledImage.wrapVertical) {
|
||||
var tileBounds = tiledImage.source.getTileBounds(level, x, y);
|
||||
if (drawArea.intersection(tileBounds) === null) {
|
||||
// This tile is outside of the viewport, no need to draw it
|
||||
continue;
|
||||
}
|
||||
var flippedX;
|
||||
if (tiledImage.getFlip()) {
|
||||
var xMod = ( numberOfTiles.x + ( x % numberOfTiles.x ) ) % numberOfTiles.x;
|
||||
flippedX = x + numberOfTiles.x - xMod - xMod - 1;
|
||||
} else {
|
||||
flippedX = x;
|
||||
}
|
||||
|
||||
if (drawArea.intersection(tiledImage.getTileBounds(level, flippedX, y)) === null) {
|
||||
// This tile is outside of the viewport, no need to draw it
|
||||
continue;
|
||||
}
|
||||
|
||||
best = updateTile(
|
||||
tiledImage,
|
||||
drawLevel,
|
||||
haveDrawn,
|
||||
x, y,
|
||||
flippedX, y,
|
||||
level,
|
||||
levelOpacity,
|
||||
levelVisibility,
|
||||
@ -1447,10 +1501,10 @@ function getTile(
|
||||
tilesMatrix[ level ][ x ] = {};
|
||||
}
|
||||
|
||||
if ( !tilesMatrix[ level ][ x ][ y ] ) {
|
||||
if ( !tilesMatrix[ level ][ x ][ y ] || !tilesMatrix[ level ][ x ][ y ].flipped !== !tiledImage.flipped ) {
|
||||
xMod = ( numTiles.x + ( x % numTiles.x ) ) % numTiles.x;
|
||||
yMod = ( numTiles.y + ( y % numTiles.y ) ) % numTiles.y;
|
||||
bounds = tileSource.getTileBounds( level, xMod, yMod );
|
||||
bounds = tiledImage.getTileBounds( level, x, y );
|
||||
sourceBounds = tileSource.getTileBounds( level, xMod, yMod, true );
|
||||
exists = tileSource.tileExists( level, xMod, yMod );
|
||||
url = tileSource.getTileUrl( level, xMod, yMod );
|
||||
@ -1469,9 +1523,6 @@ function getTile(
|
||||
context2D = tileSource.getContext2D ?
|
||||
tileSource.getContext2D(level, xMod, yMod) : undefined;
|
||||
|
||||
bounds.x += ( x - xMod ) / numTiles.x;
|
||||
bounds.y += (worldHeight / worldWidth) * (( y - yMod ) / numTiles.y);
|
||||
|
||||
tile = new $.Tile(
|
||||
level,
|
||||
x,
|
||||
@ -1485,14 +1536,22 @@ function getTile(
|
||||
sourceBounds
|
||||
);
|
||||
|
||||
if (xMod === numTiles.x - 1) {
|
||||
tile.isRightMost = true;
|
||||
if (tiledImage.getFlip()) {
|
||||
if (xMod === 0) {
|
||||
tile.isRightMost = true;
|
||||
}
|
||||
} else {
|
||||
if (xMod === numTiles.x - 1) {
|
||||
tile.isRightMost = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (yMod === numTiles.y - 1) {
|
||||
tile.isBottomMost = true;
|
||||
}
|
||||
|
||||
tile.flipped = tiledImage.flipped;
|
||||
|
||||
tilesMatrix[ level ][ x ][ y ] = tile;
|
||||
}
|
||||
|
||||
|
@ -313,8 +313,8 @@ $.TileSource.prototype = {
|
||||
*/
|
||||
getPixelRatio: function( level ) {
|
||||
var imageSizeScaled = this.dimensions.times( this.getLevelScale( level ) ),
|
||||
rx = 1.0 / imageSizeScaled.x,
|
||||
ry = 1.0 / imageSizeScaled.y;
|
||||
rx = 1.0 / imageSizeScaled.x * $.pixelDensityRatio,
|
||||
ry = 1.0 / imageSizeScaled.y * $.pixelDensityRatio;
|
||||
|
||||
return new $.Point(rx, ry);
|
||||
},
|
||||
|
@ -220,6 +220,7 @@ $.Viewer = function( options ) {
|
||||
this._updateRequestId = null;
|
||||
this._loadQueue = [];
|
||||
this.currentOverlays = [];
|
||||
this._updatePixelDensityRatioBind = null;
|
||||
|
||||
this._lastScrollTime = $.now(); // variable used to help normalize the scroll event speed of different devices
|
||||
|
||||
@ -426,6 +427,8 @@ $.Viewer = function( options ) {
|
||||
}
|
||||
}
|
||||
|
||||
this._addUpdatePixelDensityRatioEvent();
|
||||
|
||||
//Instantiate a navigator if configured
|
||||
if ( this.showNavigator){
|
||||
this.navigator = new $.Navigator({
|
||||
@ -748,6 +751,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
return;
|
||||
}
|
||||
|
||||
this._removeUpdatePixelDensityRatioEvent();
|
||||
|
||||
this.close();
|
||||
|
||||
this.clearOverlays();
|
||||
@ -1301,6 +1306,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
* @param {Boolean} [options.preload=false] Default switch for loading hidden images (true loads, false blocks)
|
||||
* @param {Number} [options.degrees=0] Initial rotation of the tiled image around
|
||||
* its top left corner in degrees.
|
||||
* @param {Boolean} [options.flipped=false] Whether to horizontally flip the image.
|
||||
* @param {String} [options.compositeOperation] How the image is composited onto other images.
|
||||
* @param {String} [options.crossOriginPolicy] The crossOriginPolicy for this specific image,
|
||||
* overriding viewer.crossOriginPolicy.
|
||||
@ -1463,6 +1469,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
opacity: queueItem.options.opacity,
|
||||
preload: queueItem.options.preload,
|
||||
degrees: queueItem.options.degrees,
|
||||
flipped: queueItem.options.flipped,
|
||||
compositeOperation: queueItem.options.compositeOperation,
|
||||
springStiffness: _this.springStiffness,
|
||||
animationTime: _this.animationTime,
|
||||
@ -2266,6 +2273,38 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
|
||||
} else {
|
||||
$.console.warn('Attempting to display a reference strip while "sequenceMode" is off.');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds _updatePixelDensityRatio to the window resize event.
|
||||
* @private
|
||||
*/
|
||||
_addUpdatePixelDensityRatioEvent: function() {
|
||||
this._updatePixelDensityRatioBind = this._updatePixelDensityRatio.bind(this);
|
||||
$.addEvent( window, 'resize', this._updatePixelDensityRatioBind );
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes _updatePixelDensityRatio from the window resize event.
|
||||
* @private
|
||||
*/
|
||||
_removeUpdatePixelDensityRatioEvent: function() {
|
||||
$.removeEvent( window, 'resize', this._updatePixelDensityRatioBind );
|
||||
},
|
||||
|
||||
/**
|
||||
* Update pixel density ratio, clears all tiles and triggers updates for
|
||||
* all items if the ratio has changed.
|
||||
* @private
|
||||
*/
|
||||
_updatePixelDensityRatio: function() {
|
||||
var previusPixelDensityRatio = $.pixelDensityRatio;
|
||||
var currentPixelDensityRatio = $.getCurrentPixelDensityRatio();
|
||||
if (previusPixelDensityRatio !== currentPixelDensityRatio) {
|
||||
$.pixelDensityRatio = currentPixelDensityRatio;
|
||||
this.world.resetItems();
|
||||
this.forceRedraw();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -2334,7 +2373,8 @@ function getTileSourceImplementation( viewer, tileSource, imgOptions, successCal
|
||||
crossOriginPolicy: imgOptions.crossOriginPolicy !== undefined ?
|
||||
imgOptions.crossOriginPolicy : viewer.crossOriginPolicy,
|
||||
ajaxWithCredentials: viewer.ajaxWithCredentials,
|
||||
ajaxHeaders: viewer.ajaxHeaders,
|
||||
ajaxHeaders: imgOptions.ajaxHeaders ?
|
||||
imgOptions.ajaxHeaders : viewer.ajaxHeaders,
|
||||
useCanvas: viewer.useCanvas,
|
||||
success: function( event ) {
|
||||
successCallback( event.tileSource );
|
||||
|
113
test/demo/flipping.html
Normal file
113
test/demo/flipping.html
Normal file
@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>OpenSeadragon Flipping 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;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.options {
|
||||
margin: 0.5em;
|
||||
}
|
||||
|
||||
.button {
|
||||
margin: 0.3em;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
Simple demo page to show image flipping.
|
||||
</div>
|
||||
<div id="contentDiv" class="openseadragon1">
|
||||
|
||||
|
||||
</div>
|
||||
<div class="options">
|
||||
First
|
||||
<div class="button">
|
||||
<input type="checkbox" id="ffirst" onchange="flip(0, this.checked)">
|
||||
<label for="ffirst">Flip</label>
|
||||
</div>
|
||||
<div class="button">
|
||||
<input type="checkbox" id="rfirst" onchange="rotate(0, this.checked * 45)">
|
||||
<label for="rfirst">Rotate</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="options">
|
||||
Second
|
||||
<div class="button">
|
||||
<input type="checkbox" id="fsecond" onchange="flip(1, this.checked)" checked>
|
||||
<label for="fsecond">Flip</label>
|
||||
</div>
|
||||
<div class="button">
|
||||
<input type="checkbox" id="rsecond" onchange="rotate(1, this.checked * 45)">
|
||||
<label for="rsecond">Rotate</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="options">
|
||||
Viewport
|
||||
<div class="button">
|
||||
<input type="checkbox" id="fview" onchange="flipViewport(this.checked)">
|
||||
<label for="fview">Flip Viewport</label>
|
||||
</div>
|
||||
|
||||
<div class="button">
|
||||
<input type="checkbox" id="debug" onchange="debug(this.checked)">
|
||||
<label for="debug">Debug Mode</label>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
|
||||
var viewer = OpenSeadragon({
|
||||
// debugMode: true,
|
||||
id: "contentDiv",
|
||||
prefixUrl: "../../build/openseadragon/images/",
|
||||
showNavigator:true,
|
||||
tileSources: [
|
||||
{
|
||||
tileSource: "../data/testpattern.dzi",
|
||||
x: 0,
|
||||
y: 0,
|
||||
flipped: document.getElementById("ffirst").checked,
|
||||
degrees: document.getElementById("rfirst").checked * 45,
|
||||
}, {
|
||||
tileSource: "../data/testpattern.dzi",
|
||||
x: 1,
|
||||
y: 0,
|
||||
flipped: document.getElementById("fsecond").checked,
|
||||
degrees: document.getElementById("rsecond").checked * 45,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
viewer.viewport.setFlip(document.getElementById("fview").checked);
|
||||
|
||||
function debug(v) {
|
||||
viewer.setDebugMode(v);
|
||||
}
|
||||
|
||||
function flip(n, v) {
|
||||
viewer.world.getItemAt(n).setFlip(v);
|
||||
}
|
||||
|
||||
function rotate(n, v) {
|
||||
viewer.world.getItemAt(n).setRotation(v);
|
||||
}
|
||||
|
||||
function flipViewport(v) {
|
||||
viewer.viewport.setFlip(v);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user