Merge pull request #2256 from pearcetm/resize-listener

work in progress about viewer resize behavior
This commit is contained in:
Ian Gilman 2022-12-16 13:48:45 -08:00 committed by GitHub
commit 1351ac018a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 296 additions and 21 deletions

View File

@ -125,7 +125,8 @@ $.Navigator = function( options ){
immediateRender: true, immediateRender: true,
blendTime: 0, blendTime: 0,
animationTime: options.animationTime, animationTime: options.animationTime,
autoResize: options.autoResize, // disable autoResize since resize behavior is implemented differently by the navigator
autoResize: false,
// prevent resizing the navigator from adding unwanted space around the image // prevent resizing the navigator from adding unwanted space around the image
minZoomImageRatio: 1.0, minZoomImageRatio: 1.0,
background: options.background, background: options.background,

View File

@ -204,6 +204,8 @@ $.Viewer = function( options ) {
prevContainerSize: null, prevContainerSize: null,
animating: false, animating: false,
forceRedraw: false, forceRedraw: false,
needsResize: false,
forceResize: false,
mouseInside: false, mouseInside: false,
group: null, group: null,
// whether we should be continuously zooming // whether we should be continuously zooming
@ -328,6 +330,17 @@ $.Viewer = function( options ) {
THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container ); THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container );
if(window.ResizeObserver){
this._autoResizePolling = false;
this._resizeObserver = new ResizeObserver(function(){
THIS[_this.hash].needsResize = true;
});
this._resizeObserver.observe(this.container, {});
} else {
this._autoResizePolling = true;
}
// Create the world // Create the world
this.world = new $.World({ this.world = new $.World({
viewer: this viewer: this
@ -786,6 +799,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
//TODO: implement this... //TODO: implement this...
//this.unbindSequenceControls() //this.unbindSequenceControls()
//this.unbindStandardControls() //this.unbindStandardControls()
if (this._resizeObserver){
this._resizeObserver.disconnect();
}
if (this.referenceStrip) { if (this.referenceStrip) {
this.referenceStrip.destroy(); this.referenceStrip.destroy();
@ -1680,6 +1696,14 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
return this; return this;
}, },
/**
* Force the viewer to reset its size to match its container.
*/
forceResize: function() {
THIS[this.hash].needsResize = true;
THIS[this.hash].forceResize = true;
},
/** /**
* @function * @function
* @returns {OpenSeadragon.Viewer} Chainable. * @returns {OpenSeadragon.Viewer} Chainable.
@ -3547,6 +3571,27 @@ function updateMulti( viewer ) {
} }
} }
function doViewerResize(viewer, containerSize){
var viewport = viewer.viewport;
var zoom = viewport.getZoom();
var center = viewport.getCenter();
viewport.resize(containerSize, viewer.preserveImageSizeOnResize);
viewport.panTo(center, true);
var resizeRatio;
if (viewer.preserveImageSizeOnResize) {
resizeRatio = THIS[viewer.hash].prevContainerSize.x / containerSize.x;
} else {
var origin = new $.Point(0, 0);
var prevDiag = new $.Point(THIS[viewer.hash].prevContainerSize.x, THIS[viewer.hash].prevContainerSize.y).distanceTo(origin);
var newDiag = new $.Point(containerSize.x, containerSize.y).distanceTo(origin);
resizeRatio = newDiag / prevDiag * THIS[viewer.hash].prevContainerSize.x / containerSize.x;
}
viewport.zoomTo(zoom * resizeRatio, null, true);
THIS[viewer.hash].prevContainerSize = containerSize;
THIS[viewer.hash].forceRedraw = true;
THIS[viewer.hash].needsResize = false;
THIS[viewer.hash].forceResize = false;
}
function updateOnce( viewer ) { function updateOnce( viewer ) {
//viewer.profiler.beginUpdate(); //viewer.profiler.beginUpdate();
@ -3554,30 +3599,23 @@ function updateOnce( viewer ) {
if (viewer._opening || !THIS[viewer.hash]) { if (viewer._opening || !THIS[viewer.hash]) {
return; return;
} }
if (viewer.autoResize || THIS[viewer.hash].forceResize){
if (viewer.autoResize) { var containerSize;
var containerSize = _getSafeElemSize(viewer.container); if(viewer._autoResizePolling){
var prevContainerSize = THIS[viewer.hash].prevContainerSize; containerSize = _getSafeElemSize(viewer.container);
if (!containerSize.equals(prevContainerSize)) { var prevContainerSize = THIS[viewer.hash].prevContainerSize;
var viewport = viewer.viewport; if (!containerSize.equals(prevContainerSize)) {
if (viewer.preserveImageSizeOnResize) { THIS[viewer.hash].needsResize = true;
var resizeRatio = prevContainerSize.x / containerSize.x;
var zoom = viewport.getZoom() * resizeRatio;
var center = viewport.getCenter();
viewport.resize(containerSize, false);
viewport.zoomTo(zoom, null, true);
viewport.panTo(center, true);
} else {
// maintain image position
var oldBounds = viewport.getBounds();
viewport.resize(containerSize, true);
viewport.fitBoundsWithConstraints(oldBounds, true);
} }
THIS[viewer.hash].prevContainerSize = containerSize;
THIS[viewer.hash].forceRedraw = true;
} }
if(THIS[viewer.hash].needsResize){
doViewerResize(viewer, containerSize || _getSafeElemSize(viewer.container));
}
} }
var viewportChange = viewer.viewport.update(); var viewportChange = viewer.viewport.update();
var animated = viewer.world.update() || viewportChange; var animated = viewer.world.update() || viewportChange;

236
test/demo/resizeviewer.html Normal file
View File

@ -0,0 +1,236 @@
<!DOCTYPE html>
<html>
<head>
<title>OpenSeadragon Viewer Resizing Demo</title>
<script type="text/javascript" src='../../build/openseadragon/openseadragon.js'></script>
<script type="text/javascript" src='../lib/jquery-1.9.1.min.js'></script>
<script type="text/javascript" src='../lib/jquery-ui-1.10.2/js/jquery-ui-1.10.2.min.js'></script>
<link rel="stylesheet" href="../lib/jquery-ui-1.10.2/css/smoothness/jquery-ui-1.10.2.min.css">
<style type="text/css">
.outer-container{
width:800px;
height:600px;
margin-right:20px;
border: medium gray dashed;
background-color:beige;
position:relative;
display:flex;
flex-direction:row;
}
.inner-container{
width:800px;
height:600px;
border: thin black solid;
background-color:paleturquoise;
position:absolute;
left:50%;
top: 50%;
transform: translate(-50%, -50%);
}
.v2-container{
display:flex;
flex-direction:row;
height:400px;
}
.narrow{
width:50px;
background-color:pink;
height:100%;
}
.wide{
width:150px;
background-color:burlywood;
height:100%;
}
.v2-container:not([data-index="1"]) .narrow{
display:none;
}
.v2-container:not([data-index="2"]) .wide{
display:none;
}
#viewer, #viewer2 {
width: 100%;
height: 100%;
}
#buttons button{
width:18em;
text-align:center;
margin:5px;
}
.layout{
display:grid;
grid-template-columns:auto 1fr;
row-gap:10px;
padding:10px;
}
.method{
border:medium gray solid;
margin:2px;
background-color:rgb(240, 240, 240)
}
.method.selected{
border:medium red solid;
background-color: lightgoldenrodyellow;
}
.options{
display:grid;
grid-template-columns: 50% 50%;
row-gap:10px;
}
</style>
</head>
<body>
<div class="layout">
<div class="outer-container">
<div class="inner-container">
<div id="viewer"></div>
</div>
</div>
<div id="controls">
<div>
Simple demo page to show viewer behavior during resizing of the container.
The viewers' container elements are styled with width and height of 100%,
with dimensions set by CSS properties on a parent element.
</div>
<h3>Pick options to test:</h3>
<p>These options apply to both of the demo viewers on the left (top and bottom).</p>
<div class="options">
<div class="method preserve-method selected" data-value="0">
<pre>preserveImageSizeOnResize: false</pre>
</div>
<div class="method preserve-method" data-value="1">
<pre>preserveImageSizeOnResize: true</pre>
</div>
<div class="method auto-method selected" data-value="1">
<pre>autoResize: true</pre>
</div>
<div class="method auto-method" data-value="0">
<pre>autoResize: false</pre>
</div>
</div>
<h3>Click to resize the viewer:</h3>
<div id="buttons">
<div>
<button>Resize width only</button>
</div>
<div>
<button>Resize height only</button>
</div>
<div>
<button>Resize with constant aspect ratio</button>
</div>
<div>
<button>Toggle resizable inner container</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var viewer = window.v1 = OpenSeadragon({
id: "viewer",
prefixUrl: "../../build/openseadragon/images/",
tileSources: "../data/iiif_2_0_sizes/info.json",
minZoomImageRatio: 0,
maxZoomPixelRatio: 10,
visibilityRatio:0.5,
constrainDuringPan:false,
showNavigator: true,
});
updateViewer();
var buttons=$('#buttons button').on('click',function(){
switch($(this).text()){
case 'Resize width only': resizeWidth(this); break;
case 'Resize height only': resizeHeight(this); break;
case 'Resize with constant aspect ratio': resizeBoth(this); break;
case 'Toggle resizable inner container': toggleResizable(this); break;
}
});
function updateViewer(){
viewer.preserveImageSizeOnResize = !!parseInt($('.preserve-method.selected').data('value'));
viewer.autoResize = !!parseInt($('.auto-method.selected').data('value'));
}
$('.preserve-method').on('click',function(){
$('.preserve-method').removeClass('selected');
$(this).addClass('selected');
});
$('.auto-method').on('click',function(){
$('.auto-method').removeClass('selected');
$(this).addClass('selected');
});
$('.method').on('click',updateViewer);
var container = $('.inner-container');
function resizeWidth(b){
if(container.height() !== 600) return;
if(container.width()==800){
container.width(600);
$('#buttons button').prop('disabled', true);
$(b).prop('disabled', false);
} else {
container.width(800);
$('#buttons button').prop('disabled', false);
}
}
function resizeHeight(b){
if(container.width() !== 800) return;
if(container.height()==600){
container.height(450);
$('#buttons button').prop('disabled', true);
$(b).prop('disabled', false);
} else {
container.height(600);
$('#buttons button').prop('disabled', false);
}
}
function resizeBoth(b){
if(container.height()==600){
container.width(600);
container.height(450);
$('#buttons button').prop('disabled', true);
$(b).prop('disabled', false);
} else {
container.width(800);
container.height(600);
$('#buttons button').prop('disabled', false);
}
}
function toggleResizable(b){
if(container.isResizable){
container.isResizable = false;
container.resizable('destroy');
container.width(800);
container.height(600);
$('#buttons button').prop('disabled', false);
} else {
container.isResizable = true;
// container.resizable({containment:"parent", maxWidth: 800, maxHeight: 600,});
container.resizable();
$('#buttons button').prop('disabled', true);
container.width(800);
container.height(600);
$(b).prop('disabled', false);
}
}
</script>
</body>
</html>