Enhanced Navigator Resizability (#280, #296)

New navigator options:

* @property {Boolean} [showNavigator=false]
*     Set to true to make the navigator minimap appear.
*
* @property {Boolean} [navigatorId=navigator-GENERATED DATE]
*     The ID of a div to hold the navigator minimap.
*     If an ID is specified, the navigatorPosition, navigatorSizeRatio,
navigatorMaintainSizeRatio, and navigatorTop|Left|Height|Width options
will be ignored.
*     If an ID is not specified, a div element will be generated and
placed on top of the main image.
*
* @property {String} [navigatorPosition='TOP_RIGHT']
*     Valid values are 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT',
'BOTTOM_RIGHT', or 'ABSOLUTE'.<br>
*     If 'ABSOLUTE' is specified, then navigatorTop|Left|Height|Width
determines the size and position of the navigator minimap in the viewer,
and navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.<br>
*     For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT',
the navigatorSizeRatio or navigatorHeight|Width values determine the
size of the navigator minimap.
*
* @property {Number} [navigatorSizeRatio=0.2]
*     Ratio of navigator size to viewer size. Ignored if
navigatorHeight|Width are specified.
*
* @property {Boolean} [navigatorMaintainSizeRatio=false]
*     If true, the navigator minimap is resized (using
navigatorSizeRatio) when the viewer size changes.
*
* @property {Number|String} [navigatorTop=null]
*     Specifies the location of the navigator minimap (see
navigatorPosition).
*
* @property {Number|String} [navigatorLeft=null]
*     Specifies the location of the navigator minimap (see
navigatorPosition).
*
* @property {Number|String} [navigatorHeight=null]
*     Specifies the size of the navigator minimap (see
navigatorPosition).
*     If specified, navigatorSizeRatio and navigatorMaintainSizeRatio
are ignored.
*
* @property {Number|String} [navigatorWidth=null]
*     Specifies the size of the navigator minimap (see
navigatorPosition).
*     If specified, navigatorSizeRatio and navigatorMaintainSizeRatio
are ignored.

Fixes #280 and #296
This commit is contained in:
Mark Salsbery 2013-12-13 09:23:56 -08:00
parent 86be255c6b
commit 0d29c98df2
5 changed files with 144 additions and 84 deletions

View File

@ -46,13 +46,15 @@
* @property {Number} TOP_RIGHT
* @property {Number} BOTTOM_LEFT
* @property {Number} BOTTOM_RIGHT
* @property {Number} ABSOLUTE
*/
$.ControlAnchor = {
NONE: 0,
TOP_LEFT: 1,
TOP_RIGHT: 2,
BOTTOM_RIGHT: 3,
BOTTOM_LEFT: 4
BOTTOM_LEFT: 4,
ABSOLUTE: 5
};
/**
@ -110,13 +112,15 @@ $.Control = function ( element, options, container ) {
* @member {Element} wrapper
* @memberof OpenSeadragon.Control#
*/
this.wrapper = $.makeNeutralElement( "span" );
this.wrapper.style.display = "inline-block";
this.wrapper.appendChild( this.element );
if ( this.anchor != $.ControlAnchor.ABSOLUTE ) {
this.wrapper = $.makeNeutralElement( "span" );
this.wrapper.style.display = "inline-block";
this.wrapper.appendChild( this.element );
if ( this.anchor == $.ControlAnchor.NONE ) {
// IE6 fix
this.wrapper.style.width = this.wrapper.style.height = "100%";
if ( this.anchor == $.ControlAnchor.NONE ) {
// IE6 fix
this.wrapper.style.width = this.wrapper.style.height = "100%";
}
}
if (options.attachToViewer ) {
@ -126,11 +130,13 @@ $.Control = function ( element, options, container ) {
this.wrapper,
this.container.firstChild
);
} else if ( this.anchor == $.ControlAnchor.ABSOLUTE ) {
this.container.appendChild( this.element );
} else {
this.container.appendChild( this.wrapper );
}
} else {
parent.appendChild( this.wrapper );
parent.appendChild( this.anchor == $.ControlAnchor.ABSOLUTE ? this.element : this.wrapper );
}
};
@ -141,8 +147,10 @@ $.Control.prototype = /** @lends OpenSeadragon.Control.prototype */{
* @function
*/
destroy: function() {
this.wrapper.removeChild( this.element );
this.container.removeChild( this.wrapper );
if ( this.anchor != $.ControlAnchor.ABSOLUTE ) {
this.wrapper.removeChild( this.element );
}
this.container.removeChild( this.anchor == $.ControlAnchor.ABSOLUTE ? this.element : this.wrapper );
},
/**
@ -151,7 +159,8 @@ $.Control.prototype = /** @lends OpenSeadragon.Control.prototype */{
* @return {Boolean} true if currenly visible, false otherwise.
*/
isVisible: function() {
return this.wrapper.style.display != "none";
var controlElement = this.anchor == $.ControlAnchor.ABSOLUTE ? this.element : this.wrapper;
return controlElement.style.display != "none";
},
/**
@ -160,9 +169,15 @@ $.Control.prototype = /** @lends OpenSeadragon.Control.prototype */{
* @param {Boolean} visible - true to make visible, false to hide.
*/
setVisible: function( visible ) {
this.wrapper.style.display = visible ?
"inline-block" :
"none";
if ( this.anchor == $.ControlAnchor.ABSOLUTE ) {
this.element.style.display = visible ?
"block" :
"none";
} else {
this.wrapper.style.display = visible ?
"inline-block" :
"none";
}
},
/**
@ -171,7 +186,7 @@ $.Control.prototype = /** @lends OpenSeadragon.Control.prototype */{
* @param {Number} opactiy - a value between 1 and 0 inclusively.
*/
setOpacity: function( opacity ) {
if ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) {
if ( this.anchor == $.ControlAnchor.ABSOLUTE || ( this.element[ $.SIGNAL ] && $.Browser.vendor == $.BROWSERS.IE ) ) {
$.setElementOpacity( this.element, opacity, true );
} else {
$.setElementOpacity( this.wrapper, opacity, true );

View File

@ -126,6 +126,12 @@
element.style.paddingLeft = "0px";
element.style.paddingTop = "0px";
break;
case $.ControlAnchor.ABSOLUTE:
div = this.container;
element.style.position = "absolute";
element.style.margin = "0px";
element.style.padding = "0px";
break;
default:
case $.ControlAnchor.NONE:
div = this.container;

View File

@ -50,7 +50,7 @@
$.Navigator = function( options ){
var viewer = options.viewer,
viewerSize = $.getElementSize( viewer.element),
viewerSize,
unneededElement;
//We may need to create a new element and id if they did not
@ -73,6 +73,12 @@ $.Navigator = function( options ){
options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT;
} else if( 'TOP_LEFT' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT;
} else if( 'ABSOLUTE' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.ABSOLUTE;
options.controlOptions.top = options.top;
options.controlOptions.left = options.left;
options.controlOptions.height = options.height;
options.controlOptions.width = options.width;
}
}
@ -104,7 +110,6 @@ $.Navigator = function( options ){
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
this.viewerSizeInPoints = viewer.viewport.deltaPointsFromPixels(viewerSize);
this.borderWidth = 2;
//At some browser magnification levels the display regions lines up correctly, but at some there appears to
//be a one pixel gap.
@ -147,20 +152,16 @@ $.Navigator = function( options ){
style.cssFloat = 'left'; //Firefox
style.styleFloat = 'left'; //IE
style.zIndex = 999999999;
style.cursor = 'default';
style.cursor = 'pointer';
}( this.displayRegion.style, this.borderWidth ));
this.element.innerTracker = new $.MouseTracker({
element: this.element,
dragHandler: $.delegate( this, onCanvasDrag ),
clickHandler: $.delegate( this, onCanvasClick ),
releaseHandler: $.delegate( this, onCanvasRelease ),
scrollHandler: function(){
//dont scroll the page up and down if the user is scrolling
//in the navigator
return false;
}
element: this.element,
dragHandler: $.delegate( this, onCanvasDrag ),
clickHandler: $.delegate( this, onCanvasClick ),
releaseHandler: $.delegate( this, onCanvasRelease ),
scrollHandler: $.delegate( this, onCanvasScroll )
}).setTracking( true );
/*this.displayRegion.outerTracker = new $.MouseTracker({
@ -178,12 +179,20 @@ $.Navigator = function( options ){
options.controlOptions
);
if( options.width && options.height ){
this.element.style.width = options.width + 'px';
this.element.style.height = options.height + 'px';
if ( options.controlOptions.anchor === $.ControlAnchor.ABSOLUTE ) {
this.element.style.top = typeof ( options.top ) == "number" ? ( options.top + 'px' ) : options.top;
this.element.style.left = typeof ( options.left ) == "number" ? (options.left + 'px' ) : options.left;
}
if ( options.width && options.height ) {
this.element.style.height = typeof ( options.height ) == "number" ? ( options.height + 'px' ) : options.height;
this.element.style.width = typeof ( options.width ) == "number" ? ( options.width + 'px' ) : options.width;
} else {
this.element.style.width = ( viewerSize.x * options.sizeRatio ) + 'px';
viewerSize = $.getElementSize( viewer.element );
this.element.style.height = ( viewerSize.y * options.sizeRatio ) + 'px';
this.element.style.width = ( viewerSize.x * options.sizeRatio ) + 'px';
if ( options.maintainSizeRatio ) {
this.oldViewerSize = viewerSize;
}
}
$.Viewer.apply( this, [ options ] );
@ -203,10 +212,20 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
*/
update: function( viewport ){
var bounds,
var viewerSize,
bounds,
topleft,
bottomright;
if ( this.maintainSizeRatio ) {
viewerSize = $.getElementSize( this.viewer.element );
if ( !viewerSize.equals ( this.oldViewerSize ) ) {
this.element.style.height = ( viewerSize.y * this.sizeRatio ) + 'px';
this.element.style.width = ( viewerSize.x * this.sizeRatio ) + 'px';
this.oldViewerSize = viewerSize;
}
}
if( viewport && this.viewport ){
bounds = viewport.getBounds( true );
topleft = this.viewport.pixelFromPoint( bounds.getTopLeft());
@ -256,21 +275,7 @@ function onCanvasClick( event ) {
dimensions;
if (! this.drag) {
if ( this.viewer.viewport ) {
viewerPosition = this.viewport.deltaPointsFromPixels( event.position );
dimensions = this.viewer.viewport.getBounds().getSize();
newBounds = new $.Rect(
viewerPosition.x - dimensions.x/2,
viewerPosition.y - dimensions.y/2,
dimensions.x,
dimensions.y
);
if (this.viewer.source.aspectRatio > this.viewer.viewport.getAspectRatio()) {
newBounds.y = newBounds.y - ((this.viewerSizeInPoints.y - (1/this.viewer.source.aspectRatio)) /2 );
}
else {
newBounds.x = newBounds.x - ((this.viewerSizeInPoints.x -1) /2 );
}
this.viewer.viewport.fitBounds(newBounds);
this.viewer.viewport.panTo( this.viewport.pointFromPixel( event.position ) );
this.viewer.viewport.applyConstraints();
}
}
@ -320,16 +325,30 @@ function onCanvasRelease( event ) {
* @function
*/
function onCanvasScroll( event ) {
var factor;
if ( this.viewer.viewport ) {
factor = Math.pow( this.zoomPerScroll, event.scroll );
this.viewer.viewport.zoomBy(
factor,
this.viewport.getCenter()
);
this.viewer.viewport.applyConstraints();
}
//cancels event
/**
* Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.).
*
* @event navigator-scroll
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
* @property {OpenSeadragon.MouseTracker} tracker - A reference to the MouseTracker which originated this event.
* @property {OpenSeadragon.Point} position - The position of the event relative to the tracked element.
* @property {Number} scroll - The scroll delta for the event.
* @property {Boolean} shift - True if the shift key was pressed during this event.
* @property {Object} originalEvent - The original DOM event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'navigator-scroll', {
tracker: event.eventSource,
position: event.position,
scroll: event.scroll,
shift: event.shift,
originalEvent: event.originalEvent
});
//dont scroll the page up and down if the user is scrolling
//in the navigator
return false;
}

View File

@ -271,20 +271,34 @@
* Set to true to make the navigator minimap appear.
*
* @property {Boolean} [navigatorId=navigator-GENERATED DATE]
* Set the ID of a div to hold the navigator minimap. If one is not specified,
* one will be generated and placed on top of the main image
* The ID of a div to hold the navigator minimap.
* If an ID is specified, the navigatorPosition, navigatorSizeRatio, navigatorMaintainSizeRatio, and navigatorTop|Left|Height|Width options will be ignored.
* If an ID is not specified, a div element will be generated and placed on top of the main image.
*
* @property {Number} [navigatorHeight=null]
* TODO: Implement this. Currently not used.
*
* @property {Number} [navigatorWidth=null]
* TODO: Implement this. Currently not used.
*
* @property {Number} [navigatorPosition=null]
* TODO: Implement this. Currently not used.
* @property {String} [navigatorPosition='TOP_RIGHT']
* Valid values are 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', 'BOTTOM_RIGHT', or 'ABSOLUTE'.<br>
* If 'ABSOLUTE' is specified, then navigatorTop|Left|Height|Width determines the size and position of the navigator minimap in the viewer, and navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.<br>
* For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT', the navigatorSizeRatio or navigatorHeight|Width values determine the size of the navigator minimap.
*
* @property {Number} [navigatorSizeRatio=0.2]
* Ratio of navigator size to viewer size.
* Ratio of navigator size to viewer size. Ignored if navigatorHeight|Width are specified.
*
* @property {Boolean} [navigatorMaintainSizeRatio=false]
* If true, the navigator minimap is resized (using navigatorSizeRatio) when the viewer size changes.
*
* @property {Number|String} [navigatorTop=null]
* Specifies the location of the navigator minimap (see navigatorPosition).
*
* @property {Number|String} [navigatorLeft=null]
* Specifies the location of the navigator minimap (see navigatorPosition).
*
* @property {Number|String} [navigatorHeight=null]
* Specifies the size of the navigator minimap (see navigatorPosition).
* If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.
*
* @property {Number|String} [navigatorWidth=null]
* Specifies the size of the navigator minimap (see navigatorPosition).
* If specified, navigatorSizeRatio and navigatorMaintainSizeRatio are ignored.
*
* @property {Number} [controlsFadeDelay=2000]
* The number of milliseconds to wait once the user has stopped interacting
@ -713,12 +727,15 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY
//VIEWPORT NAVIGATOR SETTINGS
showNavigator: false,
navigatorId: null,
navigatorHeight: null,
navigatorWidth: null,
navigatorPosition: null,
navigatorSizeRatio: 0.2,
showNavigator: false,
navigatorId: null,
navigatorPosition: null,
navigatorSizeRatio: 0.2,
navigatorMaintainSizeRatio: false,
navigatorTop: null,
navigatorLeft: null,
navigatorHeight: null,
navigatorWidth: null,
// INITIAL ROTATION
degrees: 0,

View File

@ -1469,16 +1469,19 @@ function openTileSource( viewer, source ) {
_this.navigator.open( source );
} else {
_this.navigator = new $.Navigator({
id: _this.navigatorId,
position: _this.navigatorPosition,
sizeRatio: _this.navigatorSizeRatio,
height: _this.navigatorHeight,
width: _this.navigatorWidth,
tileSources: source,
tileHost: _this.tileHost,
prefixUrl: _this.prefixUrl,
overlays: _this.overlays,
viewer: _this
id: _this.navigatorId,
position: _this.navigatorPosition,
sizeRatio: _this.navigatorSizeRatio,
maintainSizeRatio: _this.navigatorMaintainSizeRatio,
top: _this.navigatorTop,
left: _this.navigatorLeft,
width: _this.navigatorWidth,
height: _this.navigatorHeight,
tileSources: source,
tileHost: _this.tileHost,
prefixUrl: _this.prefixUrl,
overlays: _this.overlays,
viewer: _this
});
}
}