openseadragon/src/viewport.js

387 lines
12 KiB
JavaScript
Raw Normal View History

(function( $ ){
$.Viewport = function( options ) {
var options;
if( arguments.length && arguments[ 0 ] instanceof $.Point ){
options = {
containerSize: arguments[ 0 ],
contentSize: arguments[ 1 ],
config: arguments[ 2 ]
};
} else {
options = arguments[ 0 ];
}
2012-01-05 04:45:47 +04:00
//TODO: this.config is something that should go away but currently the
// Drawer references the viewport.config
this.config = options.config;
this.zoomPoint = null;
this.containerSize = options.containerSize;
this.contentSize = options.contentSize;
this.contentAspect = this.contentSize.x / this.contentSize.y;
this.contentHeight = this.contentSize.y / this.contentSize.x;
this.centerSpringX = new $.Spring({
initial: 0,
springStiffness: this.config.springStiffness,
animationTime: this.config.animationTime
});
this.centerSpringY = new $.Spring({
initial: 0,
springStiffness: this.config.springStiffness,
animationTime: this.config.animationTime
});
this.zoomSpring = new $.Spring({
initial: 1,
springStiffness: this.config.springStiffness,
animationTime: this.config.animationTime
});
this.minZoomImageRatio = this.config.minZoomImageRatio;
this.maxZoomPixelRatio = this.config.maxZoomPixelRatio;
this.visibilityRatio = this.config.visibilityRatio;
this.wrapHorizontal = this.config.wrapHorizontal;
this.wrapVertical = this.config.wrapVertical;
2012-01-05 04:45:47 +04:00
this.homeBounds = new $.Rect( 0, 0, 1, this.contentHeight );
this.goHome( true );
this.update();
};
$.Viewport.prototype = {
getHomeZoom: function() {
var aspectFactor = this.contentAspect / this.getAspectRatio();
return (aspectFactor >= 1) ? 1 : aspectFactor;
},
getMinZoom: function() {
var homeZoom = this.getHomeZoom()
zoom = this.minZoomImageRatio * homeZoom;
return Math.min(zoom, homeZoom);
},
getMaxZoom: function() {
var zoom =
this.contentSize.x *
this.maxZoomPixelRatio /
this.containerSize.x;
return Math.max(zoom, this.getHomeZoom());
},
getAspectRatio: function() {
return this.containerSize.x / this.containerSize.y;
},
getContainerSize: function() {
return new $.Point(this.containerSize.x, this.containerSize.y);
},
2012-01-05 04:45:47 +04:00
getBounds: function( current ) {
var center = this.getCenter(current),
width = 1.0 / this.getZoom(current),
height = width / this.getAspectRatio();
return new $.Rect(
center.x - width / 2.0,
center.y - height / 2.0,
width,
height
);
},
2012-01-05 04:45:47 +04:00
getCenter: function( current ) {
var centerCurrent = new $.Point(
this.centerSpringX.current.value,
this.centerSpringY.current.value
),
centerTarget = new $.Point(
this.centerSpringX.target.value,
this.centerSpringY.target.value
),
oldZoomPixel,
zoom,
width,
height,
bounds,
newZoomPixel,
deltaZoomPixels,
deltaZoomPoints;
if (current) {
return centerCurrent;
} else if (!this.zoomPoint) {
return centerTarget;
}
oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);
zoom = this.getZoom();
width = 1.0 / zoom;
height = width / this.getAspectRatio();
bounds = new $.Rect(
centerCurrent.x - width / 2.0,
centerCurrent.y - height / 2.0,
width,
height
);
newZoomPixel = this.zoomPoint.minus(
bounds.getTopLeft()
).times(
this.containerSize.x / bounds.width
);
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel );
deltaZoomPoints = deltaZoomPixels.divide( this.containerSize.x * zoom );
return centerTarget.plus( deltaZoomPoints );
},
2012-01-05 04:45:47 +04:00
getZoom: function( current ) {
if ( current ) {
return this.zoomSpring.current.value;
} else {
return this.zoomSpring.target.value;
}
},
2012-01-05 04:45:47 +04:00
applyConstraints: function( immediately ) {
var actualZoom = this.getZoom(),
constrainedZoom = Math.max(
Math.min( actualZoom, this.getMaxZoom() ),
this.getMinZoom()
),
bounds,
horizontalThreshold,
verticalThreshold,
left,
right,
top,
bottom,
dx = 0,
dy = 0;
if ( actualZoom != constrainedZoom ) {
this.zoomTo( constrainedZoom, this.zoomPoint, immediately );
}
2012-01-05 04:45:47 +04:00
bounds = this.getBounds();
2012-01-05 04:45:47 +04:00
horizontalThreshold = this.visibilityRatio * bounds.width;
verticalThreshold = this.visibilityRatio * bounds.height;
2012-01-05 04:45:47 +04:00
left = bounds.x + bounds.width;
right = 1 - bounds.x;
top = bounds.y + bounds.height;
bottom = this.contentHeight - bounds.y;
if ( this.wrapHorizontal ) {
2012-01-05 04:45:47 +04:00
//do nothing
} else if ( left < horizontalThreshold ) {
dx = horizontalThreshold - left;
} else if ( right < horizontalThreshold ) {
dx = right - horizontalThreshold;
}
if ( this.wrapVertical ) {
2012-01-05 04:45:47 +04:00
//do nothing
} else if ( top < verticalThreshold ) {
dy = verticalThreshold - top;
} else if ( bottom < verticalThreshold ) {
dy = bottom - verticalThreshold;
}
2012-01-05 04:45:47 +04:00
if ( dx || dy ) {
bounds.x += dx;
bounds.y += dy;
2012-01-05 04:45:47 +04:00
this.fitBounds( bounds, immediately );
}
},
2012-01-05 04:45:47 +04:00
ensureVisible: function( immediately ) {
this.applyConstraints( immediately );
},
2012-01-05 04:45:47 +04:00
fitBounds: function( bounds, immediately ) {
var aspect = this.getAspectRatio(),
center = bounds.getCenter(),
newBounds = new $.Rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height
),
oldBounds,
oldZoom,
newZoom,
2012-01-05 04:45:47 +04:00
referencePoint;
if (newBounds.getAspectRatio() >= aspect) {
newBounds.height = bounds.width / aspect;
2012-01-05 04:45:47 +04:00
newBounds.y = center.y - newBounds.height / 2;
} else {
newBounds.width = bounds.height * aspect;
2012-01-05 04:45:47 +04:00
newBounds.x = center.x - newBounds.width / 2;
}
this.panTo(this.getCenter(true), true);
this.zoomTo(this.getZoom(true), null, true);
oldBounds = this.getBounds();
oldZoom = this.getZoom();
newZoom = 1.0 / newBounds.width;
if (newZoom == oldZoom || newBounds.width == oldBounds.width) {
this.panTo( center, immediately );
return;
}
2012-01-05 04:45:47 +04:00
referencePoint = oldBounds.getTopLeft().times(
this.containerSize.x / oldBounds.width
).minus(
newBounds.getTopLeft().times(
this.containerSize.x / newBounds.width
)
).divide(
this.containerSize.x / oldBounds.width -
this.containerSize.x / newBounds.width
);
2012-01-05 04:45:47 +04:00
this.zoomTo( newZoom, referencePoint, immediately );
},
goHome: function(immediately) {
var center = this.getCenter();
if ( this.wrapHorizontal ) {
center.x = (1 + (center.x % 1)) % 1;
this.centerSpringX.resetTo(center.x);
this.centerSpringX.update();
}
if ( this.wrapVertical ) {
center.y = (this.contentHeight + (center.y % this.contentHeight)) % this.contentHeight;
this.centerSpringY.resetTo(center.y);
this.centerSpringY.update();
}
this.fitBounds(this.homeBounds, immediately);
},
panBy: function(delta, immediately) {
var center = new $.Point(
this.centerSpringX.target.value,
this.centerSpringY.target.value
);
this.panTo( center.plus( delta ), immediately );
},
panTo: function(center, immediately) {
if (immediately) {
this.centerSpringX.resetTo(center.x);
this.centerSpringY.resetTo(center.y);
} else {
this.centerSpringX.springTo(center.x);
this.centerSpringY.springTo(center.y);
}
},
zoomBy: function(factor, refPoint, immediately) {
this.zoomTo(this.zoomSpring.target.value * factor, refPoint, immediately);
},
zoomTo: function(zoom, refPoint, immediately) {
if (immediately) {
this.zoomSpring.resetTo(zoom);
} else {
this.zoomSpring.springTo(zoom);
}
this.zoomPoint = refPoint instanceof $.Point ? refPoint : null;
},
resize: function(newContainerSize, maintain) {
var oldBounds = this.getBounds(),
newBounds = oldBounds,
widthDeltaFactor = newContainerSize.x / this.containerSize.x;
this.containerSize = new $.Point(newContainerSize.x, newContainerSize.y);
if (maintain) {
newBounds.width = oldBounds.width * widthDeltaFactor;
newBounds.height = newBounds.width / this.getAspectRatio();
}
this.fitBounds(newBounds, true);
},
update: function() {
var oldCenterX = this.centerSpringX.current.value,
oldCenterY = this.centerSpringY.current.value,
oldZoom = this.zoomSpring.current.value,
oldZoomPixel,
newZoomPixel,
deltaZoomPixels,
deltaZoomPoints;
if (this.zoomPoint) {
oldZoomPixel = this.pixelFromPoint(this.zoomPoint, true);
}
this.zoomSpring.update();
if (this.zoomPoint && this.zoomSpring.current.value != oldZoom) {
newZoomPixel = this.pixelFromPoint( this.zoomPoint, true );
deltaZoomPixels = newZoomPixel.minus( oldZoomPixel);
deltaZoomPoints = this.deltaPointsFromPixels( deltaZoomPixels, true );
this.centerSpringX.shiftBy( deltaZoomPoints.x );
this.centerSpringY.shiftBy( deltaZoomPoints.y );
} else {
this.zoomPoint = null;
}
this.centerSpringX.update();
this.centerSpringY.update();
return this.centerSpringX.current.value != oldCenterX ||
this.centerSpringY.current.value != oldCenterY ||
this.zoomSpring.current.value != oldZoom;
},
deltaPixelsFromPoints: function(deltaPoints, current) {
return deltaPoints.times(
this.containerSize.x * this.getZoom( current )
);
},
deltaPointsFromPixels: function(deltaPixels, current) {
return deltaPixels.divide(
this.containerSize.x * this.getZoom( current )
);
},
pixelFromPoint: function(point, current) {
var bounds = this.getBounds( current );
return point.minus(
bounds.getTopLeft()
).times(
this.containerSize.x / bounds.width
);
},
pointFromPixel: function(pixel, current) {
var bounds = this.getBounds( current );
return pixel.divide(
this.containerSize.x / bounds.width
).plus(
bounds.getTopLeft()
);
}
};
}( OpenSeadragon ));