Merge pull request #910 from avandecreme/home-clip

Fix home bounds with clipping. Fix #891
This commit is contained in:
Ian Gilman 2016-04-22 11:01:05 -07:00
commit 5785d10cbb
5 changed files with 238 additions and 46 deletions

View File

@ -287,6 +287,26 @@ $.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadrag
return this.getBounds(); return this.getBounds();
}, },
/**
* Get the bounds of the displayed part of the tiled image.
* @param {Boolean} [current=false] Pass true for the current location,
* false for the target location.
* @returns {$.Rect} The clipped bounds in viewport coordinates.
*/
getClippedBounds: function(current) {
var bounds = this.getBounds(current);
if (this._clip) {
var ratio = this._worldWidthCurrent / this.source.dimensions.x;
var clip = this._clip.times(ratio);
bounds = new $.Rect(
bounds.x + clip.x,
bounds.y + clip.y,
clip.width,
clip.height);
}
return bounds;
},
/** /**
* @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels. * @returns {OpenSeadragon.Point} This TiledImage's content size, in original pixels.
*/ */

View File

@ -341,7 +341,9 @@ $.Viewport.prototype = {
}, margins); }, margins);
this._updateContainerInnerSize(); this._updateContainerInnerSize();
if (this.viewer) {
this.viewer.forceRedraw(); this.viewer.forceRedraw();
}
}, },
/** /**
@ -1085,8 +1087,18 @@ $.Viewport.prototype = {
return this.viewportToImageCoordinates(viewerX.x, viewerX.y); return this.viewportToImageCoordinates(viewerX.x, viewerX.y);
} }
if (this.viewer && this.viewer.world.getItemCount() > 1) { if (this.viewer) {
$.console.error('[Viewport.viewportToImageCoordinates] is not accurate with multi-image; use TiledImage.viewportToImageCoordinates instead.'); var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.viewportToImageCoordinates] is not accurate ' +
'with multi-image; use TiledImage.viewportToImageCoordinates instead.');
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageCoordinates
// because this._contentBoundsNoRotate can not be relied on
// with clipping.
var item = this.viewer.world.getItemAt(0);
return item.viewportToImageCoordinates(viewerX, viewerY, true);
}
} }
return this._viewportToImageDelta( return this._viewportToImageDelta(
@ -1119,8 +1131,18 @@ $.Viewport.prototype = {
return this.imageToViewportCoordinates(imageX.x, imageX.y); return this.imageToViewportCoordinates(imageX.x, imageX.y);
} }
if (this.viewer && this.viewer.world.getItemCount() > 1) { if (this.viewer) {
$.console.error('[Viewport.imageToViewportCoordinates] is not accurate with multi-image; use TiledImage.imageToViewportCoordinates instead.'); var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.imageToViewportCoordinates] is not accurate ' +
'with multi-image; use TiledImage.imageToViewportCoordinates instead.');
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageCoordinates
// because this._contentBoundsNoRotate can not be relied on
// with clipping.
var item = this.viewer.world.getItemAt(0);
return item.imageToViewportCoordinates(imageX, imageY, true);
}
} }
var point = this._imageToViewportDelta(imageX, imageY); var point = this._imageToViewportDelta(imageX, imageY);
@ -1150,6 +1172,21 @@ $.Viewport.prototype = {
rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight); rect = new $.Rect(imageX, imageY, pixelWidth, pixelHeight);
} }
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.imageToViewportRectangle] is not accurate ' +
'with multi-image; use TiledImage.imageToViewportRectangle instead.');
} else if (count === 1) {
// It is better to use TiledImage.imageToViewportRectangle
// because this._contentBoundsNoRotate can not be relied on
// with clipping.
var item = this.viewer.world.getItemAt(0);
return item.imageToViewportRectangle(
imageX, imageY, pixelWidth, pixelHeight, true);
}
}
var coordA = this.imageToViewportCoordinates(rect.x, rect.y); var coordA = this.imageToViewportCoordinates(rect.x, rect.y);
var coordB = this._imageToViewportDelta(rect.width, rect.height); var coordB = this._imageToViewportDelta(rect.width, rect.height);
return new $.Rect( return new $.Rect(
@ -1183,6 +1220,21 @@ $.Viewport.prototype = {
rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight); rect = new $.Rect(viewerX, viewerY, pointWidth, pointHeight);
} }
if (this.viewer) {
var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.viewportToImageRectangle] is not accurate ' +
'with multi-image; use TiledImage.viewportToImageRectangle instead.');
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageCoordinates
// because this._contentBoundsNoRotate can not be relied on
// with clipping.
var item = this.viewer.world.getItemAt(0);
return item.viewportToImageRectangle(
viewerX, viewerY, pointWidth, pointHeight, true);
}
}
var coordA = this.viewportToImageCoordinates(rect.x, rect.y); var coordA = this.viewportToImageCoordinates(rect.x, rect.y);
var coordB = this._viewportToImageDelta(rect.width, rect.height); var coordB = this._viewportToImageDelta(rect.width, rect.height);
return new $.Rect( return new $.Rect(
@ -1225,8 +1277,10 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
windowToImageCoordinates: function(pixel) { windowToImageCoordinates: function(pixel) {
$.console.assert(this.viewer,
"[Viewport.windowToImageCoordinates] the viewport must have a viewer.");
var viewerCoordinates = pixel.minus( var viewerCoordinates = pixel.minus(
OpenSeadragon.getElementPosition( this.viewer.element )); $.getElementPosition(this.viewer.element));
return this.viewerElementToImageCoordinates(viewerCoordinates); return this.viewerElementToImageCoordinates(viewerCoordinates);
}, },
@ -1237,9 +1291,11 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
imageToWindowCoordinates: function(pixel) { imageToWindowCoordinates: function(pixel) {
$.console.assert(this.viewer,
"[Viewport.imageToWindowCoordinates] the viewport must have a viewer.");
var viewerCoordinates = this.imageToViewerElementCoordinates(pixel); var viewerCoordinates = this.imageToViewerElementCoordinates(pixel);
return viewerCoordinates.plus( return viewerCoordinates.plus(
OpenSeadragon.getElementPosition( this.viewer.element )); $.getElementPosition(this.viewer.element));
}, },
/** /**
@ -1296,8 +1352,10 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
windowToViewportCoordinates: function(pixel) { windowToViewportCoordinates: function(pixel) {
$.console.assert(this.viewer,
"[Viewport.windowToViewportCoordinates] the viewport must have a viewer.");
var viewerCoordinates = pixel.minus( var viewerCoordinates = pixel.minus(
OpenSeadragon.getElementPosition( this.viewer.element )); $.getElementPosition(this.viewer.element));
return this.viewerElementToViewportCoordinates(viewerCoordinates); return this.viewerElementToViewportCoordinates(viewerCoordinates);
}, },
@ -1307,9 +1365,11 @@ $.Viewport.prototype = {
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
viewportToWindowCoordinates: function(point) { viewportToWindowCoordinates: function(point) {
$.console.assert(this.viewer,
"[Viewport.viewportToWindowCoordinates] the viewport must have a viewer.");
var viewerCoordinates = this.viewportToViewerElementCoordinates(point); var viewerCoordinates = this.viewportToViewerElementCoordinates(point);
return viewerCoordinates.plus( return viewerCoordinates.plus(
OpenSeadragon.getElementPosition( this.viewer.element )); $.getElementPosition(this.viewer.element));
}, },
/** /**
@ -1325,8 +1385,18 @@ $.Viewport.prototype = {
* @returns {Number} imageZoom The image zoom * @returns {Number} imageZoom The image zoom
*/ */
viewportToImageZoom: function(viewportZoom) { viewportToImageZoom: function(viewportZoom) {
if (this.viewer && this.viewer.world.getItemCount() > 1) { if (this.viewer) {
$.console.error('[Viewport.viewportToImageZoom] is not accurate with multi-image.'); var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.viewportToImageZoom] is not ' +
'accurate with multi-image.');
} else if (count === 1) {
// It is better to use TiledImage.viewportToImageZoom
// because this._contentBoundsNoRotate can not be relied on
// with clipping.
var item = this.viewer.world.getItemAt(0);
return item.viewportToImageZoom(viewportZoom);
}
} }
var imageWidth = this._contentSizeNoRotate.x; var imageWidth = this._contentSizeNoRotate.x;
@ -1349,8 +1419,18 @@ $.Viewport.prototype = {
* @returns {Number} viewportZoom The viewport zoom * @returns {Number} viewportZoom The viewport zoom
*/ */
imageToViewportZoom: function(imageZoom) { imageToViewportZoom: function(imageZoom) {
if (this.viewer && this.viewer.world.getItemCount() > 1) { if (this.viewer) {
$.console.error('[Viewport.imageToViewportZoom] is not accurate with multi-image.'); var count = this.viewer.world.getItemCount();
if (count > 1) {
$.console.error('[Viewport.imageToViewportZoom] is not accurate ' +
'with multi-image.');
} else if (count === 1) {
// It is better to use TiledImage.imageToViewportZoom
// because this._contentBoundsNoRotate can not be relied on
// with clipping.
var item = this.viewer.world.getItemAt(0);
return item.imageToViewportZoom(imageZoom);
}
} }
var imageWidth = this._contentSizeNoRotate.x; var imageWidth = this._contentSizeNoRotate.x;

View File

@ -380,28 +380,34 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W
this._contentSize = new $.Point(1, 1); this._contentSize = new $.Point(1, 1);
this._contentFactor = 1; this._contentFactor = 1;
} else { } else {
var bounds = this._items[0].getBounds(); var item = this._items[0];
this._contentFactor = this._items[0].getContentSize().x / bounds.width; var bounds = item.getBounds();
var left = bounds.x; this._contentFactor = item.getContentSize().x / bounds.width;
var top = bounds.y; var clippedBounds = item.getClippedBounds();
var right = bounds.x + bounds.width; var left = clippedBounds.x;
var bottom = bounds.y + bounds.height; var top = clippedBounds.y;
var box; var right = clippedBounds.x + clippedBounds.width;
var bottom = clippedBounds.y + clippedBounds.height;
for (var i = 1; i < this._items.length; i++) { for (var i = 1; i < this._items.length; i++) {
box = this._items[i].getBounds(); item = this._items[i];
this._contentFactor = Math.max(this._contentFactor, this._items[i].getContentSize().x / box.width); bounds = item.getBounds();
left = Math.min( left, box.x ); this._contentFactor = Math.max(this._contentFactor,
top = Math.min( top, box.y ); item.getContentSize().x / bounds.width);
right = Math.max( right, box.x + box.width ); clippedBounds = item.getClippedBounds();
bottom = Math.max( bottom, box.y + box.height ); left = Math.min(left, clippedBounds.x);
top = Math.min(top, clippedBounds.y);
right = Math.max(right, clippedBounds.x + clippedBounds.width);
bottom = Math.max(bottom, clippedBounds.y + clippedBounds.height);
} }
this._homeBounds = new $.Rect(left, top, right - left, bottom - top); this._homeBounds = new $.Rect(left, top, right - left, bottom - top);
this._contentSize = new $.Point(this._homeBounds.width * this._contentFactor, this._contentSize = new $.Point(
this._homeBounds.width * this._contentFactor,
this._homeBounds.height * this._contentFactor); this._homeBounds.height * this._contentFactor);
} }
if (this._contentFactor !== oldContentFactor || !this._homeBounds.equals(oldHomeBounds) || if (this._contentFactor !== oldContentFactor ||
!this._homeBounds.equals(oldHomeBounds) ||
!this._contentSize.equals(oldContentSize)) { !this._contentSize.equals(oldContentSize)) {
/** /**
* Raised when the home bounds or content factor change. * Raised when the home bounds or content factor change.

View File

@ -206,10 +206,12 @@
propEqual(image.getClip(), clip, 'clip is set correctly'); propEqual(image.getClip(), clip, 'clip is set correctly');
Util.spyOnce(viewer.drawer, 'setClip', function(rect) { Util.spyOnce(viewer.drawer, 'setClip', function(rect) {
ok(true, 'drawer.setClip is called'); var homeBounds = viewer.viewport.getHomeBounds();
var pixelRatio = viewer.viewport.getContainerSize().x / image.getContentSize().x; var canvasClip = viewer.viewport
var canvasClip = clip.times(pixelRatio * OpenSeadragon.pixelDensityRatio); .viewportToViewerElementRectangle(homeBounds);
propEqual(rect, canvasClip, 'clipping to correct rect'); var precision = 0.00000001;
Util.assertRectangleEquals(rect, canvasClip, precision,
'clipping should be ' + canvasClip);
start(); start();
}); });
}); });
@ -220,6 +222,39 @@
}); });
}); });
asyncTest('getClipBounds', function() {
var clip = new OpenSeadragon.Rect(100, 200, 800, 500);
viewer.addHandler('open', function() {
var image = viewer.world.getItemAt(0);
var bounds = image.getClippedBounds();
var expectedBounds = new OpenSeadragon.Rect(1.2, 1.4, 1.6, 1);
propEqual(bounds, expectedBounds,
'getClipBounds should take clipping into account.');
image = viewer.world.getItemAt(1);
bounds = image.getClippedBounds();
expectedBounds = new OpenSeadragon.Rect(1, 2, 2, 2);
propEqual(bounds, expectedBounds,
'getClipBounds should work when no clipping set.');
start();
});
viewer.open([{
tileSource: '/test/data/testpattern.dzi',
clip: clip,
x: 1,
y: 1,
width: 2
}, {
tileSource: '/test/data/testpattern.dzi',
x: 1,
y: 2,
width: 2
}]);
});
// ---------- // ----------
asyncTest('opacity', function() { asyncTest('opacity', function() {

View File

@ -238,6 +238,57 @@
viewer.open(DZI_PATH); viewer.open(DZI_PATH);
}); });
asyncTest('getHomeBoundsWithMultiImages', function() {
function openHandler() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
Util.assertRectangleEquals(
new OpenSeadragon.Rect(0, 0, 4, 4),
viewport.getHomeBounds(),
0.00000001,
"Test getHomeBoundsWithMultiImages");
start();
}
viewer.addHandler('open', openHandler);
viewer.open([{
tileSource: DZI_PATH,
x: 0,
y: 0,
width: 2
}, {
tileSource: DZI_PATH,
x: 3,
y: 3,
width: 1
}]);
});
asyncTest('getHomeBoundsWithMultiImagesAndClipping', function() {
function openHandler() {
viewer.removeHandler('open', openHandler);
var viewport = viewer.viewport;
Util.assertRectangleEquals(
new OpenSeadragon.Rect(1, 1, 4, 4),
viewport.getHomeBounds(),
0.00000001,
"Test getHomeBoundsWithMultiImagesAndClipping");
start();
}
viewer.addHandler('open', openHandler);
viewer.open([{
tileSource: DZI_PATH,
x: 0,
y: 0,
width: 2,
clip: new OpenSeadragon.Rect(500, 500, 500, 500)
}, {
tileSource: DZI_PATH,
x: 4,
y: 4,
width: 1
}]);
});
asyncTest('getHomeZoom', function() { asyncTest('getHomeZoom', function() {
reopenViewerHelper({ reopenViewerHelper({
property: 'defaultZoomLevel', property: 'defaultZoomLevel',