Merge branch 'master' into layers

Conflicts:
	src/drawer.js
	src/viewer.js
	test/test.html
This commit is contained in:
Antoine Vandecreme 2014-03-19 16:24:48 -04:00
commit ba10c392a1
115 changed files with 1775 additions and 616 deletions

View File

@ -1,7 +1,26 @@
OPENSEADRAGON CHANGELOG OPENSEADRAGON CHANGELOG
======================= =======================
1.0.0: (in progress) 1.0.1: (in progress)
* DEPRECATION: overlay functions have been moved from Drawer to Viewer (#331)
* Improved overlay functions (#331)
* Fixed: Nav button highlight states aren't quite aligned on Firefox (#303)
* Added ControlAnchor options for default controls (#304)
* Enabled basic cross-domain tile loading without tainting canvas (works in Chrome and Firefox) (#308)
* Added a ControlAnchor.ABSOLUTE enumeration. Enables absolute positioning of control elements in the viewer (#310)
* Added a 'navigator-scroll' event to Navigator. Fired when mousewheel/pinch events occur in the navigator (#310)
* Added a navigatorMaintainSizeRatio option. If set to true, the navigator minimap resizes when the viewer element is resized (#310)
* Added 'ABSOLUTE' as a navigatorPosition option, along with corresponding navigatorTop, navigatorLeft options. Allows the navigator minimap to be placed anywhere in the viewer (#310)
* Enhanced the navigatorTop, navigatorLeft, navigatorHeight, and navigatorWidth options to allow a number for pixel units or a string for other element units (%, em, etc.) (#310)
* Additional enhancements for IIIF support (#315)
* Fixed: Setting degrees in Viewer constructor has no effect (#336)
* Added pre-draw event for tiles to allow applications to alter the image (#348)
* Added optional Rotate Left/Right buttons to standard controls (#341)
1.0.0:
NOTE: This version has a number of breaking changes to the API, mostly in event handling. See below.
* BREAKING CHANGE: All EventSource and MouseTracker event handler method signatures changed to 'handlerMethod(event)' where event == { eventSource, userData, ... } (#251) (Also fixes #23, #224, #239) * BREAKING CHANGE: All EventSource and MouseTracker event handler method signatures changed to 'handlerMethod(event)' where event == { eventSource, userData, ... } (#251) (Also fixes #23, #224, #239)
* The new eventSource property in the event object replaces the old eventSource parameter that was passed to handler methods. * The new eventSource property in the event object replaces the old eventSource parameter that was passed to handler methods.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
images/rotateleft_hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/rotateleft_rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

BIN
images/rotateright_rest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -129,11 +129,9 @@ $.Button = function( options ) {
this.imgGroup = $.makeTransparentImage( this.srcGroup ); this.imgGroup = $.makeTransparentImage( this.srcGroup );
this.imgHover = $.makeTransparentImage( this.srcHover ); this.imgHover = $.makeTransparentImage( this.srcHover );
this.imgDown = $.makeTransparentImage( this.srcDown ); this.imgDown = $.makeTransparentImage( this.srcDown );
this.imgDiv = $.makeNeutralElement( "div" );
this.element.appendChild( this.imgRest ); this.imgDiv.style.position = "relative";
this.element.appendChild( this.imgGroup );
this.element.appendChild( this.imgHover );
this.element.appendChild( this.imgDown );
this.imgGroup.style.position = this.imgGroup.style.position =
this.imgHover.style.position = this.imgHover.style.position =
@ -160,6 +158,12 @@ $.Button = function( options ) {
this.imgDown.style.top = this.imgDown.style.top =
""; "";
} }
this.imgDiv.appendChild( this.imgRest );
this.imgDiv.appendChild( this.imgGroup );
this.imgDiv.appendChild( this.imgHover );
this.imgDiv.appendChild( this.imgDown );
this.element.appendChild( this.imgDiv );
} }

View File

@ -46,13 +46,15 @@
* @property {Number} TOP_RIGHT * @property {Number} TOP_RIGHT
* @property {Number} BOTTOM_LEFT * @property {Number} BOTTOM_LEFT
* @property {Number} BOTTOM_RIGHT * @property {Number} BOTTOM_RIGHT
* @property {Number} ABSOLUTE
*/ */
$.ControlAnchor = { $.ControlAnchor = {
NONE: 0, NONE: 0,
TOP_LEFT: 1, TOP_LEFT: 1,
TOP_RIGHT: 2, TOP_RIGHT: 2,
BOTTOM_RIGHT: 3, BOTTOM_RIGHT: 3,
BOTTOM_LEFT: 4 BOTTOM_LEFT: 4,
ABSOLUTE: 5
}; };
/** /**
@ -110,14 +112,30 @@ $.Control = function ( element, options, container ) {
* @member {Element} wrapper * @member {Element} wrapper
* @memberof OpenSeadragon.Control# * @memberof OpenSeadragon.Control#
*/ */
this.wrapper = $.makeNeutralElement( "span" ); if ( this.anchor == $.ControlAnchor.ABSOLUTE ) {
this.wrapper.style.display = "inline-block"; this.wrapper = $.makeNeutralElement( "div" );
this.wrapper.appendChild( this.element ); this.wrapper.style.position = "absolute";
this.wrapper.style.top = typeof ( options.top ) == "number" ? ( options.top + 'px' ) : options.top;
this.wrapper.style.left = typeof ( options.left ) == "number" ? (options.left + 'px' ) : options.left;
this.wrapper.style.height = typeof ( options.height ) == "number" ? ( options.height + 'px' ) : options.height;
this.wrapper.style.width = typeof ( options.width ) == "number" ? ( options.width + 'px' ) : options.width;
this.wrapper.style.margin = "0px";
this.wrapper.style.padding = "0px";
if ( this.anchor == $.ControlAnchor.NONE ) { this.element.style.position = "relative";
// IE6 fix this.element.style.top = "0px";
this.wrapper.style.width = this.wrapper.style.height = "100%"; this.element.style.left = "0px";
this.element.style.height = "100%";
this.element.style.width = "100%";
} else {
this.wrapper = $.makeNeutralElement( "span" );
this.wrapper.style.display = "inline-block";
if ( this.anchor == $.ControlAnchor.NONE ) {
// IE6 fix
this.wrapper.style.width = this.wrapper.style.height = "100%";
}
} }
this.wrapper.appendChild( this.element );
if (options.attachToViewer ) { if (options.attachToViewer ) {
if ( this.anchor == $.ControlAnchor.TOP_RIGHT || if ( this.anchor == $.ControlAnchor.TOP_RIGHT ||
@ -161,7 +179,7 @@ $.Control.prototype = /** @lends OpenSeadragon.Control.prototype */{
*/ */
setVisible: function( visible ) { setVisible: function( visible ) {
this.wrapper.style.display = visible ? this.wrapper.style.display = visible ?
"inline-block" : ( this.anchor == $.ControlAnchor.ABSOLUTE ? 'block' : 'inline-block' ) :
"none"; "none";
}, },

View File

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

View File

@ -87,8 +87,7 @@ $.Drawer = function( options ) {
//internal state / configurable settings //internal state / configurable settings
overlays: [], // An unordered list of Overlays added. collectionOverlays: {}, // For collection mode. Here an overlay is actually a viewer.
collectionOverlays: {},
//configurable settings //configurable settings
opacity: $.DEFAULT_SETTINGS.opacity, opacity: $.DEFAULT_SETTINGS.opacity,
@ -150,18 +149,6 @@ $.Drawer = function( options ) {
this.container.style.textAlign = "left"; this.container.style.textAlign = "left";
this.container.appendChild( this.canvas ); this.container.appendChild( this.canvas );
//create the correct type of overlay by convention if the overlays
//are not already OpenSeadragon.Overlays
for( i = 0; i < this.overlays.length; i++ ){
if( $.isPlainObject( this.overlays[ i ] ) ){
this.overlays[ i ] = addOverlayFromConfiguration( this, this.overlays[ i ]);
} else if ( $.isFunction( this.overlays[ i ] ) ){
//TODO
}
}
//this.profiler = new $.Profiler(); //this.profiler = new $.Profiler();
}; };
@ -183,53 +170,11 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
* needs to be drawn. It it the responsibility of the callback to do any drawing/positioning. * needs to be drawn. It it the responsibility of the callback to do any drawing/positioning.
* It is passed position, size and element. * It is passed position, size and element.
* @fires OpenSeadragon.Viewer.event:add-overlay * @fires OpenSeadragon.Viewer.event:add-overlay
* @deprecated - use {@link OpenSeadragon.Viewer#addOverlay} instead.
*/ */
addOverlay: function( element, location, placement, onDraw ) { addOverlay: function( element, location, placement, onDraw ) {
var options; $.console.error("drawer.addOverlay is deprecated. Use viewer.addOverlay instead.");
if( $.isPlainObject( element ) ){ this.viewer.addOverlay( element, location, placement, onDraw );
options = element;
} else {
options = {
element: element,
location: location,
placement: placement,
onDraw: onDraw
};
}
element = $.getElement(options.element);
if ( getOverlayIndex( this.overlays, element ) >= 0 ) {
// they're trying to add a duplicate overlay
return;
}
this.overlays.push( new $.Overlay({
element: element,
location: options.location,
placement: options.placement,
onDraw: options.onDraw
}) );
this.updateAgain = true;
if( this.viewer ){
/**
* Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Drawer#addOverlay}).
*
* @event add-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {Element} element - The overlay element.
* @property {OpenSeadragon.Point|OpenSeadragon.Rect} location
* @property {OpenSeadragon.OverlayPlacement} placement
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'add-overlay', {
element: element,
location: options.location,
placement: options.placement
});
}
return this; return this;
}, },
@ -244,36 +189,11 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
* to. * to.
* @return {OpenSeadragon.Drawer} Chainable. * @return {OpenSeadragon.Drawer} Chainable.
* @fires OpenSeadragon.Viewer.event:update-overlay * @fires OpenSeadragon.Viewer.event:update-overlay
* @deprecated - use {@link OpenSeadragon.Viewer#updateOverlay} instead.
*/ */
updateOverlay: function( element, location, placement ) { updateOverlay: function( element, location, placement ) {
var i; $.console.error("drawer.updateOverlay is deprecated. Use viewer.updateOverlay instead.");
this.viewer.updateOverlay( element, location, placement );
element = $.getElement( element );
i = getOverlayIndex( this.overlays, element );
if ( i >= 0 ) {
this.overlays[ i ].update( location, placement );
this.updateAgain = true;
}
if( this.viewer ){
/**
* Raised when an overlay's location or placement changes (see {@link OpenSeadragon.Drawer#updateOverlay}).
*
* @event update-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {Element} element
* @property {OpenSeadragon.Point|OpenSeadragon.Rect} location
* @property {OpenSeadragon.OverlayPlacement} placement
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'update-overlay', {
element: element,
location: location,
placement: placement
});
}
return this; return this;
}, },
@ -285,33 +205,11 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
* element id which represent the ovelay content to be removed. * element id which represent the ovelay content to be removed.
* @return {OpenSeadragon.Drawer} Chainable. * @return {OpenSeadragon.Drawer} Chainable.
* @fires OpenSeadragon.Viewer.event:remove-overlay * @fires OpenSeadragon.Viewer.event:remove-overlay
* @deprecated - use {@link OpenSeadragon.Viewer#removeOverlay} instead.
*/ */
removeOverlay: function( element ) { removeOverlay: function( element ) {
var i; $.console.error("drawer.removeOverlay is deprecated. Use viewer.removeOverlay instead.");
this.viewer.updateOverlay( element );
element = $.getElement( element );
i = getOverlayIndex( this.overlays, element );
if ( i >= 0 ) {
this.overlays[ i ].destroy();
this.overlays.splice( i, 1 );
this.updateAgain = true;
}
if( this.viewer ){
/**
* Raised when an overlay is removed from the viewer (see {@link OpenSeadragon.Drawer#removeOverlay}).
*
* @event remove-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {Element} element - The overlay element.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'remove-overlay', {
element: element
});
}
return this; return this;
}, },
@ -321,24 +219,11 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
* @method * @method
* @return {OpenSeadragon.Drawer} Chainable. * @return {OpenSeadragon.Drawer} Chainable.
* @fires OpenSeadragon.Viewer.event:clear-overlay * @fires OpenSeadragon.Viewer.event:clear-overlay
* @deprecated - use {@link OpenSeadragon.Viewer#clearOverlays} instead.
*/ */
clearOverlays: function() { clearOverlays: function() {
while ( this.overlays.length > 0 ) { $.console.error("drawer.clearOverlays is deprecated. Use viewer.clearOverlays instead.");
this.overlays.pop().destroy(); this.viewer.clearOverlays();
this.updateAgain = true;
}
if( this.viewer ){
/**
* Raised when all overlays are removed from the viewer (see {@link OpenSeadragon.Drawer#clearOverlays}).
*
* @event clear-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.viewer.raiseEvent( 'clear-overlay', {} );
}
return this; return this;
}, },
@ -362,7 +247,6 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
getOpacity: function() { getOpacity: function() {
return this.opacity; return this.opacity;
}, },
/** /**
* Returns whether the Drawer is scheduled for an update at the * Returns whether the Drawer is scheduled for an update at the
* soonest possible opportunity. * soonest possible opportunity.
@ -441,6 +325,7 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
this.downloading++; this.downloading++;
image = new Image(); image = new Image();
image.crossOrigin = 'Anonymous';
complete = function( imagesrc, resultingImage ){ complete = function( imagesrc, resultingImage ){
_this.downloading--; _this.downloading--;
@ -488,61 +373,6 @@ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
} }
}; };
/**
* @private
* @inner
*/
function addOverlayFromConfiguration( drawer, overlay ){
var element = null,
rect = ( overlay.height && overlay.width ) ? new $.Rect(
overlay.x || overlay.px,
overlay.y || overlay.py,
overlay.width,
overlay.height
) : new $.Point(
overlay.x || overlay.px,
overlay.y || overlay.py
),
id = overlay.id ?
overlay.id :
"openseadragon-overlay-"+Math.floor(Math.random()*10000000);
element = $.getElement(overlay.id);
if( !element ){
element = document.createElement("a");
element.href = "#/overlay/"+id;
}
element.id = id;
$.addClass( element, overlay.className ?
overlay.className :
"openseadragon-overlay"
);
if(overlay.px !== undefined){
//if they specified 'px' so it's in pixel coordinates so
//we need to translate to viewport coordinates
rect = drawer.viewport.imageToViewportRectangle( rect );
}
if( overlay.placement ){
return new $.Overlay({
element: element,
location: drawer.viewport.pointFromPixel(rect),
placement: $.OverlayPlacement[overlay.placement.toUpperCase()],
onDraw: overlay.onDraw
});
}else{
return new $.Overlay({
element: element,
location: rect,
onDraw: overlay.onDraw
});
}
}
/** /**
* @private * @private
* @inner * @inner
@ -716,7 +546,6 @@ function updateViewport( drawer ) {
//TODO //TODO
drawTiles( drawer, drawer.lastDrawn ); drawTiles( drawer, drawer.lastDrawn );
drawOverlays( drawer.viewport, drawer.overlays, drawer.container );
//TODO //TODO
if ( best ) { if ( best ) {
@ -1163,23 +992,6 @@ function resetCoverage( coverage, level ) {
coverage[ level ] = {}; coverage[ level ] = {};
} }
/**
* @private
* @inner
* Determines the 'z-index' of the given overlay. Overlays are ordered in
* a z-index based on the order they are added to the Drawer.
*/
function getOverlayIndex( overlays, element ) {
var i;
for ( i = overlays.length - 1; i >= 0; i-- ) {
if ( overlays[ i ].element == element ) {
return i;
}
}
return -1;
}
/** /**
* @private * @private
* @inner * @inner
@ -1217,28 +1029,6 @@ function finishLoadingImage( image, callback, successful, jobid ){
} }
function drawOverlays( viewport, overlays, container ){
var i,
length = overlays.length;
for ( i = 0; i < length; i++ ) {
drawOverlay( viewport, overlays[ i ], container );
}
}
function drawOverlay( viewport, overlay, container ){
overlay.position = viewport.pixelFromPoint(
overlay.bounds.getTopLeft(),
true
);
overlay.size = viewport.deltaPixelsFromPoints(
overlay.bounds.getSize(),
true
);
overlay.drawHTML( container, viewport );
}
function drawTiles( drawer, lastDrawn ){ function drawTiles( drawer, lastDrawn ){
var i, var i,
tile, tile,
@ -1249,6 +1039,25 @@ function drawTiles( drawer, lastDrawn ){
tileSource, tileSource,
collectionTileSource; collectionTileSource;
// We need a callback to give image manipulation a chance to happen
var drawingHandler = function(args) {
if (drawer.viewer) {
/**
* This event is fired just before the tile is drawn giving the application a chance to alter the image.
*
* NOTE: This event is only fired when the drawer is using a <canvas>.
*
* @event tile-drawing
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {OpenSeadragon.Tile} tile
* @property {?Object} userData - 'context', 'tile' and 'rendered'.
*/
drawer.viewer.raiseEvent('tile-drawing', args);
}
};
for ( i = lastDrawn.length - 1; i >= 0; i-- ) { for ( i = lastDrawn.length - 1; i >= 0; i-- ) {
tile = lastDrawn[ i ]; tile = lastDrawn[ i ];
@ -1299,7 +1108,7 @@ function drawTiles( drawer, lastDrawn ){
')'; ')';
} }
drawer.addOverlay( drawer.viewer.addOverlay(
viewer.element, viewer.element,
tile.bounds tile.bounds
); );
@ -1320,10 +1129,10 @@ function drawTiles( drawer, lastDrawn ){
// specifically, don't save,rotate,restore every time we draw a tile // specifically, don't save,rotate,restore every time we draw a tile
if( drawer.viewport.degrees !== 0 ) { if( drawer.viewport.degrees !== 0 ) {
offsetForRotation( tile, drawer.canvas, drawer.context, drawer.viewport.degrees ); offsetForRotation( tile, drawer.canvas, drawer.context, drawer.viewport.degrees );
tile.drawCanvas( drawer.context ); tile.drawCanvas( drawer.context, drawingHandler );
restoreRotationChanges( tile, drawer.canvas, drawer.context ); restoreRotationChanges( tile, drawer.canvas, drawer.context );
} else { } else {
tile.drawCanvas( drawer.context ); tile.drawCanvas( drawer.context, drawingHandler );
} }
} else { } else {
tile.drawHTML( drawer.canvas ); tile.drawHTML( drawer.canvas );

View File

@ -45,20 +45,49 @@
*/ */
$.IIIF1_1TileSource = function( options ){ $.IIIF1_1TileSource = function( options ){
$.extend( true, this, options ); $.extend( true, this, options );
if( !(this.height && this.width && this['@id'] ) ){
throw new Error('IIIF required parameters not provided.'); if ( !( this.height && this.width && this['@id'] ) ){
throw new Error( 'IIIF required parameters not provided.' );
} }
if ( !(this.tile_width && this.tile_height) ) { if ( ( this.profile &&
// use the short dimension if there aren't tile sizes provided. this.profile == "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" ) ){
options.tileSize = Math.min(this.height, this.width); // what if not reporting a profile?
} else { throw new Error( 'IIIF Image API 1.1 compliance level 1 or greater is required.' );
}
if ( this.tile_width ) {
options.tileSize = this.tile_width; options.tileSize = this.tile_width;
} else if ( this.tile_height ) {
options.tileSize = this.tile_height;
} else {
// use the largest of tileOptions that is smaller than the short
// dimension
var shortDim = Math.min( this.height, this.width ),
tileOptions = [256,512,1024],
smallerTiles = [];
for ( var c = 0; c < tileOptions.length; c++ ) {
if ( tileOptions[c] <= shortDim ) {
smallerTiles.push( tileOptions[c] );
}
}
if ( smallerTiles.length > 0 ) {
options.tileSize = Math.max.apply( null, smallerTiles );
} else {
// If we're smaller than 256, just use the short side.
options.tileSize = shortDim;
}
this.tile_width = options.tileSize; // So that 'full' gets used for
this.tile_height = options.tileSize; // the region below
} }
if (! options.maxLevel ) { if ( !options.maxLevel ) {
var mf = -1; var mf = -1;
var scfs = this.scale_factors || this.scale_factor; var scfs = this.scale_factors || this.scale_factor;
if ( scfs instanceof Array ) { if ( scfs instanceof Array ) {
@ -67,7 +96,7 @@ $.IIIF1_1TileSource = function( options ){
if ( !isNaN( cf ) && cf > mf ) { mf = cf; } if ( !isNaN( cf ) && cf > mf ) { mf = cf; }
} }
} }
if ( mf < 0 ) { options.maxLevel = Number(Math.ceil(Math.log(Math.max(this.width, this.height), 2))); } if ( mf < 0 ) { options.maxLevel = Number( Math.ceil( Math.log( Math.max( this.width, this.height ), 2 ) ) ); }
else { options.maxLevel = mf; } else { options.maxLevel = mf; }
} }
@ -82,33 +111,29 @@ $.extend( $.IIIF1_1TileSource.prototype, $.TileSource.prototype, /** @lends Open
* @param {Object|Array} data * @param {Object|Array} data
* @param {String} optional - url * @param {String} optional - url
*/ */
supports: function( data, url ){ supports: function( data, url ) {
return data.profile && ( return ( data['@context'] &&
"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0" == data.profile || data['@context'] == "http://library.stanford.edu/iiif/image-api/1.1/context.json" );
"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1" == data.profile ||
"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2" == data.profile ||
"http://library.stanford.edu/iiif/image-api/1.1/compliance.html" == data.profile
);
}, },
/** /**
* *
* @function * @function
* @param {Object} data - the raw configuration * @param {Object} data - the raw configuration
* @example <caption>IIIF 1.1 Info Looks like this (XML syntax is no more)</caption>
* {
* "@context" : "http://library.stanford.edu/iiif/image-api/1.1/context.json",
* "@id" : "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C",
* "width" : 6000,
* "height" : 4000,
* "scale_factors" : [ 1, 2, 4 ],
* "tile_width" : 1024,
* "tile_height" : 1024,
* "formats" : [ "jpg", "png" ],
* "qualities" : [ "native", "grey" ],
* "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
* }
*/ */
// IIIF 1.1 Info Looks like this (XML syntax is no more):
// {
// "@context" : "http://library.stanford.edu/iiif/image-api/1.1/context.json",
// "@id" : "http://iiif.example.com/prefix/1E34750D-38DB-4825-A38A-B60A345E591C",
// "width" : 6000,
// "height" : 4000,
// "scale_factors" : [ 1, 2, 4 ],
// "tile_width" : 1024,
// "tile_height" : 1024,
// "formats" : [ "jpg", "png" ],
// "qualities" : [ "native", "grey" ]
// "profile" : "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0"
// }
configure: function( data ){ configure: function( data ){
return data; return data;
}, },
@ -124,6 +149,7 @@ $.extend( $.IIIF1_1TileSource.prototype, $.TileSource.prototype, /** @lends Open
getTileUrl: function( level, x, y ){ getTileUrl: function( level, x, y ){
//# constants //# constants
var IIIF_ROTATION = '0', var IIIF_ROTATION = '0',
IIIF_QUALITY = 'native.jpg', IIIF_QUALITY = 'native.jpg',
@ -131,32 +157,34 @@ $.extend( $.IIIF1_1TileSource.prototype, $.TileSource.prototype, /** @lends Open
scale = Math.pow( 0.5, this.maxLevel - level ), scale = Math.pow( 0.5, this.maxLevel - level ),
//# image dimensions at this level //# image dimensions at this level
level_width = Math.ceil( this.width * scale ), levelWidth = Math.ceil( this.width * scale ),
level_height = Math.ceil( this.height * scale ), levelHeight = Math.ceil( this.height * scale ),
//## iiif region //## iiif region
iiif_tile_size_width = Math.ceil( this.tileSize / scale ), iiifTileSizeWidth = Math.ceil( this.tileSize / scale ),
iiif_tile_size_height = Math.ceil( this.tileSize / scale ), iiifTileSizeHeight = Math.ceil( this.tileSize / scale ),
iiif_region, iiifRegion,
iiif_tile_x, iiifTileX,
iiif_tile_y, iiifTileY,
iiif_tile_w, iiifTileW,
iiif_tile_h, iiifTileH,
iiif_size, iiifSize,
uri; uri;
if ( level_width < this.tile_width && level_height < this.tile_height ){ if ( levelWidth < this.tile_width && levelHeight < this.tile_height ){
iiif_size = level_width + "," + level_height; iiifSize = levelWidth + ",";
iiif_region = 'full'; iiifRegion = 'full';
} else { } else {
iiif_tile_x = x * iiif_tile_size_width; iiifTileX = x * iiifTileSizeWidth;
iiif_tile_y = y * iiif_tile_size_height; iiifTileY = y * iiifTileSizeHeight;
iiif_tile_w = Math.min( iiif_tile_size_width, this.width - iiif_tile_x ); iiifTileW = Math.min( iiifTileSizeWidth, this.width - iiifTileX );
iiif_tile_h = Math.min( iiif_tile_size_height, this.height - iiif_tile_y ); iiifTileH = Math.min( iiifTileSizeHeight, this.height - iiifTileY );
iiif_size = Math.ceil(iiif_tile_w * scale) + "," + Math.ceil(iiif_tile_h * scale);
iiif_region = [ iiif_tile_x, iiif_tile_y, iiif_tile_w, iiif_tile_h ].join(','); iiifSize = Math.ceil( iiifTileW * scale ) + ",";
iiifRegion = [ iiifTileX, iiifTileY, iiifTileW, iiifTileH ].join( ',' );
} }
uri = [ this['@id'], iiif_region, iiif_size, IIIF_ROTATION, IIIF_QUALITY ].join('/'); uri = [ this['@id'], iiifRegion, iiifSize, IIIF_ROTATION, IIIF_QUALITY ].join( '/' );
return uri; return uri;
} }
}); });

View File

@ -114,7 +114,7 @@ $.extend( $.IIIFTileSource.prototype, $.TileSource.prototype, /** @lends OpenSea
* @param {Object|XMLDocument} data - the raw configuration * @param {Object|XMLDocument} data - the raw configuration
* @param {String} url - the url the data was retreived from if any. * @param {String} url - the url the data was retreived from if any.
* @return {Object} options - A dictionary of keyword arguments sufficient * @return {Object} options - A dictionary of keyword arguments sufficient
* to configure this tile source via it's constructor. * to configure this tile source via its constructor.
*/ */
configure: function( data, url ){ configure: function( data, url ){
var service, var service,

View File

@ -50,7 +50,8 @@
$.Navigator = function( options ){ $.Navigator = function( options ){
var viewer = options.viewer, var viewer = options.viewer,
viewerSize = $.getElementSize( viewer.element), viewerSize,
navigatorSize,
unneededElement; unneededElement;
//We may need to create a new element and id if they did not //We may need to create a new element and id if they did not
@ -73,6 +74,12 @@ $.Navigator = function( options ){
options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT; options.controlOptions.anchor = $.ControlAnchor.TOP_RIGHT;
} else if( 'TOP_LEFT' == options.position ){ } else if( 'TOP_LEFT' == options.position ){
options.controlOptions.anchor = $.ControlAnchor.TOP_LEFT; 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;
} }
} }
@ -99,12 +106,12 @@ $.Navigator = function( options ){
showSequenceControl: false, showSequenceControl: false,
immediateRender: true, immediateRender: true,
blendTime: 0, blendTime: 0,
animationTime: 0 animationTime: 0,
autoResize: options.autoResize
}); });
options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio; options.minPixelRatio = this.minPixelRatio = viewer.minPixelRatio;
this.viewerSizeInPoints = viewer.viewport.deltaPointsFromPixels(viewerSize);
this.borderWidth = 2; this.borderWidth = 2;
//At some browser magnification levels the display regions lines up correctly, but at some there appears to //At some browser magnification levels the display regions lines up correctly, but at some there appears to
//be a one pixel gap. //be a one pixel gap.
@ -112,14 +119,16 @@ $.Navigator = function( options ){
this.totalBorderWidths = new $.Point(this.borderWidth*2, this.borderWidth*2).minus(this.fudge); this.totalBorderWidths = new $.Point(this.borderWidth*2, this.borderWidth*2).minus(this.fudge);
(function( style, borderWidth ){ if ( options.controlOptions.anchor != $.ControlAnchor.NONE ) {
style.margin = '0px'; (function( style, borderWidth ){
style.border = borderWidth + 'px solid #555'; style.margin = '0px';
style.padding = '0px'; style.border = borderWidth + 'px solid #555';
style.background = '#000'; style.padding = '0px';
style.opacity = 0.8; style.background = '#000';
style.overflow = 'hidden'; style.opacity = 0.8;
}( this.element.style, this.borderWidth)); style.overflow = 'hidden';
}( this.element.style, this.borderWidth));
}
this.displayRegion = $.makeNeutralElement( "div" ); this.displayRegion = $.makeNeutralElement( "div" );
this.displayRegion.id = this.element.id + '-displayregion'; this.displayRegion.id = this.element.id + '-displayregion';
@ -152,15 +161,11 @@ $.Navigator = function( options ){
this.element.innerTracker = new $.MouseTracker({ this.element.innerTracker = new $.MouseTracker({
element: this.element, element: this.element,
dragHandler: $.delegate( this, onCanvasDrag ), dragHandler: $.delegate( this, onCanvasDrag ),
clickHandler: $.delegate( this, onCanvasClick ), clickHandler: $.delegate( this, onCanvasClick ),
releaseHandler: $.delegate( this, onCanvasRelease ), releaseHandler: $.delegate( this, onCanvasRelease ),
scrollHandler: function(){ scrollHandler: $.delegate( this, onCanvasScroll )
//dont scroll the page up and down if the user is scrolling
//in the navigator
return false;
}
}).setTracking( true ); }).setTracking( true );
/*this.displayRegion.outerTracker = new $.MouseTracker({ /*this.displayRegion.outerTracker = new $.MouseTracker({
@ -178,14 +183,22 @@ $.Navigator = function( options ){
options.controlOptions options.controlOptions
); );
if( options.width && options.height ){ if ( options.controlOptions.anchor != $.ControlAnchor.ABSOLUTE && options.controlOptions.anchor != $.ControlAnchor.NONE ) {
this.element.style.width = options.width + 'px'; if ( options.width && options.height ) {
this.element.style.height = options.height + 'px'; this.element.style.height = typeof ( options.height ) == "number" ? ( options.height + 'px' ) : options.height;
} else { this.element.style.width = typeof ( options.width ) == "number" ? ( options.width + 'px' ) : options.width;
this.element.style.width = ( viewerSize.x * options.sizeRatio ) + 'px'; } else {
this.element.style.height = ( viewerSize.y * 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';
this.oldViewerSize = viewerSize;
}
navigatorSize = $.getElementSize( this.element );
this.elementArea = navigatorSize.x * navigatorSize.y;
} }
this.oldContainerSize = new $.Point( 0, 0 );
$.Viewer.apply( this, [ options ] ); $.Viewer.apply( this, [ options ] );
this.element.getElementsByTagName('form')[0].appendChild( this.displayRegion ); this.element.getElementsByTagName('form')[0].appendChild( this.displayRegion );
@ -199,18 +212,71 @@ $.Navigator = function( options ){
$.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /** @lends OpenSeadragon.Navigator.prototype */{
/** /**
* Used to notify the navigator when its size has changed.
* Especially useful when {@link OpenSeadragon.Options}.navigatorAutoResize is set to false and the navigator is resizable.
* @function * @function
*/ */
update: function( viewport ){ updateSize: function () {
if ( this.viewport ) {
var containerSize = new $.Point(
(this.container.clientWidth === 0 ? 1 : this.container.clientWidth),
(this.container.clientHeight === 0 ? 1 : this.container.clientHeight)
);
if ( !containerSize.equals( this.oldContainerSize ) ) {
var oldBounds = this.viewport.getBounds();
var oldCenter = this.viewport.getCenter();
this.viewport.resize( containerSize, true );
var imageHeight = 1 / this.source.aspectRatio;
var newWidth = oldBounds.width <= 1 ? oldBounds.width : 1;
var newHeight = oldBounds.height <= imageHeight ?
oldBounds.height : imageHeight;
var newBounds = new $.Rect(
oldCenter.x - ( newWidth / 2.0 ),
oldCenter.y - ( newHeight / 2.0 ),
newWidth,
newHeight
);
this.viewport.fitBounds( newBounds, true );
this.oldContainerSize = containerSize;
this.drawer.update();
}
}
},
var bounds, /**
* Used to update the navigator minimap's viewport rectangle when a change in the viewer's viewport occurs.
* @function
* @param {OpenSeadragon.Viewport} The viewport this navigator is tracking.
*/
update: function( viewport ) {
var viewerSize,
newWidth,
newHeight,
bounds,
topleft, topleft,
bottomright; bottomright;
if( viewport && this.viewport ){ viewerSize = $.getElementSize( this.viewer.element );
if ( !viewerSize.equals( this.oldViewerSize ) ) {
this.oldViewerSize = viewerSize;
if ( this.maintainSizeRatio ) {
newWidth = viewerSize.x * this.sizeRatio;
newHeight = viewerSize.y * this.sizeRatio;
}
else {
newWidth = Math.sqrt(this.elementArea * (viewerSize.x / viewerSize.y));
newHeight = this.elementArea / newWidth;
}
this.element.style.width = newWidth + 'px';
this.element.style.height = newHeight + 'px';
this.updateSize();
}
if( viewport && this.viewport ) {
bounds = viewport.getBounds( true ); bounds = viewport.getBounds( true );
topleft = this.viewport.pixelFromPoint( bounds.getTopLeft()); topleft = this.viewport.pixelFromPoint( bounds.getTopLeft(), false );
bottomright = this.viewport.pixelFromPoint( bounds.getBottomRight()).minus(this.totalBorderWidths); bottomright = this.viewport.pixelFromPoint( bounds.getBottomRight(), false ).minus( this.totalBorderWidths );
//update style for navigator-box //update style for navigator-box
(function(style) { (function(style) {
@ -229,7 +295,8 @@ $.extend( $.Navigator.prototype, $.EventSource.prototype, $.Viewer.prototype, /*
}, },
open: function( source ){ open: function( source ) {
this.updateSize();
var containerSize = this.viewer.viewport.containerSize.times( this.sizeRatio ); var containerSize = this.viewer.viewport.containerSize.times( this.sizeRatio );
if( source.tileSize > containerSize.x || if( source.tileSize > containerSize.x ||
source.tileSize > containerSize.y ){ source.tileSize > containerSize.y ){
@ -256,21 +323,7 @@ function onCanvasClick( event ) {
dimensions; dimensions;
if (! this.drag) { if (! this.drag) {
if ( this.viewer.viewport ) { if ( this.viewer.viewport ) {
viewerPosition = this.viewport.deltaPointsFromPixels( event.position ); this.viewer.viewport.panTo( this.viewport.pointFromPixel( 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.applyConstraints(); this.viewer.viewport.applyConstraints();
} }
} }
@ -320,16 +373,30 @@ function onCanvasRelease( event ) {
* @function * @function
*/ */
function onCanvasScroll( event ) { function onCanvasScroll( event ) {
var factor; /**
if ( this.viewer.viewport ) { * Raised when a scroll event occurs on the {@link OpenSeadragon.Viewer#navigator} element (mouse wheel, touch pinch, etc.).
factor = Math.pow( this.zoomPerScroll, event.scroll ); *
this.viewer.viewport.zoomBy( * @event navigator-scroll
factor, * @memberof OpenSeadragon.Viewer
this.viewport.getCenter() * @type {object}
); * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised this event.
this.viewer.viewport.applyConstraints(); * @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.
//cancels event * @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; return false;
} }

View File

@ -102,11 +102,11 @@
*/ */
/** /**
* The root namespace for OpenSeadragon. All utility methods
* and classes are defined on or below this namespace.
*
* @namespace OpenSeadragon * @namespace OpenSeadragon
* *
* @classdesc The root namespace for OpenSeadragon. All utility methods
* and classes are defined on or below this namespace.
*
*/ */
@ -136,6 +136,28 @@
* is an Array of objects, it is used to create a * is an Array of objects, it is used to create a
* {@link OpenSeadragon.LegacyTileSource}. * {@link OpenSeadragon.LegacyTileSource}.
* *
* @property {Array} overlays Array of objects defining permanent overlays of
* the viewer. The overlays added via this option and later removed with
* {@link OpenSeadragon.Viewer#removeOverlay} will be added back when a new
* image is opened.
* To add overlays which can be definitively removed, one must use
* {@link OpenSeadragon.Viewer#addOverlay}
* If displaying a sequence of images, the overlays can be associated
* with a specific page by passing the overlays array to the page's
* tile source configuration.
* Expected properties:
* * x, y, (or px, py for pixel coordinates) to define the location.
* * width, height in point if using x,y or in pixels if using px,py. If width
* and height are specified, the overlay size is adjusted when zooming,
* otherwise the size stays the size of the content (or the size defined by CSS).
* * className to associate a class to the overlay
* * id to set the overlay element. If an element with this id already exists,
* it is reused, otherwise it is created. If not specified, a new element is
* created.
* * placement a string to define the relative position to the viewport.
* Only used if no width and height are specified. Default: 'TOP_LEFT'.
* See {@link OpenSeadragon.OverlayPlacement} for possible values.
*
* @property {String} [xmlPath=null] * @property {String} [xmlPath=null]
* <strong>DEPRECATED</strong>. A relative path to load a DZI file from the server. * <strong>DEPRECATED</strong>. A relative path to load a DZI file from the server.
* Prefer the newer Options.tileSources. * Prefer the newer Options.tileSources.
@ -270,24 +292,45 @@
* @property {Boolean} [showNavigationControl=true] * @property {Boolean} [showNavigationControl=true]
* Set to false to prevent the appearance of the default navigation controls. * Set to false to prevent the appearance of the default navigation controls.
* *
* @property {OpenSeadragon.ControlAnchor} [navigationControlAnchor=TOP_LEFT]
* Placement of the default navigation controls.
*
* @property {Boolean} [showNavigator=false] * @property {Boolean} [showNavigator=false]
* Set to true to make the navigator minimap appear. * Set to true to make the navigator minimap appear.
* *
* @property {Boolean} [navigatorId=navigator-GENERATED DATE] * @property {Boolean} [navigatorId=navigator-GENERATED DATE]
* Set the ID of a div to hold the navigator minimap. If one is not specified, * The ID of a div to hold the navigator minimap.
* one will be generated and placed on top of the main image * 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] * @property {String} [navigatorPosition='TOP_RIGHT']
* TODO: Implement this. Currently not used. * 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>
* @property {Number} [navigatorWidth=null] * For 'TOP_LEFT', 'TOP_RIGHT', 'BOTTOM_LEFT', and 'BOTTOM_RIGHT', the navigatorSizeRatio or navigatorHeight|Width values determine the size of the navigator minimap.
* TODO: Implement this. Currently not used.
*
* @property {Number} [navigatorPosition=null]
* TODO: Implement this. Currently not used.
* *
* @property {Number} [navigatorSizeRatio=0.2] * @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 {Boolean} [navigatorAutoResize=true]
* Set to false to prevent polling for navigator size changes. Useful for providing custom resize behavior.
* Setting to false can also improve performance when the navigator is configured to a fixed size.
* *
* @property {Number} [controlsFadeDelay=2000] * @property {Number} [controlsFadeDelay=2000]
* The number of milliseconds to wait once the user has stopped interacting * The number of milliseconds to wait once the user has stopped interacting
@ -321,10 +364,18 @@
* image and if the 'next' button will wrap to the first image when viewing * image and if the 'next' button will wrap to the first image when viewing
* the last image. * the last image.
* *
* @property {Boolean} [showRotationControl=false]
* If true then the rotate left/right controls will be displayed as part of the
* standard controls. This is also subject to the browser support for rotate
* (e.g. viewer.drawer.canRotate()).
*
* @property {Boolean} [showSequenceControl=true] * @property {Boolean} [showSequenceControl=true]
* If the viewer has been configured with a sequence of tile sources, then * If the viewer has been configured with a sequence of tile sources, then
* provide buttons for navigating forward and backward through the images. * provide buttons for navigating forward and backward through the images.
* *
* @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT]
* Placement of the default sequence controls.
*
* @property {Number} [initialPage=0] * @property {Number} [initialPage=0]
* If the viewer has been configured with a sequence of tile sources, display this page initially. * If the viewer has been configured with a sequence of tile sources, display this page initially.
* *
@ -703,20 +754,26 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
autoResize: true, autoResize: true,
//DEFAULT CONTROL SETTINGS //DEFAULT CONTROL SETTINGS
showSequenceControl: true, //SEQUENCE showSequenceControl: true, //SEQUENCE
preserveViewport: false, //SEQUENCE sequenceControlAnchor: null, //SEQUENCE
showNavigationControl: true, //ZOOM/HOME/FULL/SEQUENCE preserveViewport: false, //SEQUENCE
controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE showNavigationControl: true, //ZOOM/HOME/FULL/SEQUENCE
controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE navigationControlAnchor: null, //ZOOM/HOME/FULL
mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY controlsFadeDelay: 2000, //ZOOM/HOME/FULL/SEQUENCE
controlsFadeLength: 1500, //ZOOM/HOME/FULL/SEQUENCE
mouseNavEnabled: true, //GENERAL MOUSE INTERACTIVITY
//VIEWPORT NAVIGATOR SETTINGS //VIEWPORT NAVIGATOR SETTINGS
showNavigator: false, showNavigator: false,
navigatorId: null, navigatorId: null,
navigatorHeight: null, navigatorPosition: null,
navigatorWidth: null, navigatorSizeRatio: 0.2,
navigatorPosition: null, navigatorMaintainSizeRatio: false,
navigatorSizeRatio: 0.2, navigatorTop: null,
navigatorLeft: null,
navigatorHeight: null,
navigatorWidth: null,
navigatorAutoResize: true,
// INITIAL ROTATION // INITIAL ROTATION
degrees: 0, degrees: 0,
@ -775,6 +832,18 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
HOVER: 'fullpage_hover.png', HOVER: 'fullpage_hover.png',
DOWN: 'fullpage_pressed.png' DOWN: 'fullpage_pressed.png'
}, },
rotateleft: {
REST: 'rotateleft_rest.png',
GROUP: 'rotateleft_grouphover.png',
HOVER: 'rotateleft_hover.png',
DOWN: 'rotateleft_pressed.png'
},
rotateright: {
REST: 'rotateright_rest.png',
GROUP: 'rotateright_grouphover.png',
HOVER: 'rotateright_hover.png',
DOWN: 'rotateright_pressed.png'
},
previous: { previous: {
REST: 'previous_rest.png', REST: 'previous_rest.png',
GROUP: 'previous_grouphover.png', GROUP: 'previous_grouphover.png',
@ -789,6 +858,7 @@ window.OpenSeadragon = window.OpenSeadragon || function( options ){
} }
}, },
navPrevNextWrap: false, navPrevNextWrap: false,
showRotationControl: false,
//DEVELOPER SETTINGS //DEVELOPER SETTINGS
debugMode: false, debugMode: false,

View File

@ -35,7 +35,8 @@
(function( $ ){ (function( $ ){
/** /**
* An enumeration of positions that an overlay may be assigned relative to the viewport. * An enumeration of positions that an overlay may be assigned relative to
* the viewport.
* @member OverlayPlacement * @member OverlayPlacement
* @memberof OpenSeadragon * @memberof OpenSeadragon
* @static * @static
@ -69,8 +70,14 @@
* @memberof OpenSeadragon * @memberof OpenSeadragon
* @param {Object} options * @param {Object} options
* @param {Element} options.element * @param {Element} options.element
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location * @param {OpenSeadragon.Point|OpenSeadragon.Rect} options.location - The
* @param {OpenSeadragon.OverlayPlacement} options.placement - Only used if location is an {@link OpenSeadragon.Point}. * location of the overlay on the image. If a {@link OpenSeadragon.Point}
* is specified, the overlay will keep a constant size independently of the
* zoom. If a {@link OpenSeadragon.Rect} is specified, the overlay size will
* be adjusted when the zoom changes.
* @param {OpenSeadragon.OverlayPlacement} [options.placement=OpenSeadragon.OverlayPlacement.TOP_LEFT]
* Relative position to the viewport.
* Only used if location is a {@link OpenSeadragon.Point}.
* @param {OpenSeadragon.Overlay.OnDrawCallback} options.onDraw * @param {OpenSeadragon.Overlay.OnDrawCallback} options.onDraw
*/ */
$.Overlay = function( element, location, placement ) { $.Overlay = function( element, location, placement ) {
@ -86,9 +93,9 @@
*/ */
var options; var options;
if( $.isPlainObject( element ) ){ if ( $.isPlainObject( element ) ) {
options = element; options = element;
} else{ } else {
options = { options = {
element: element, element: element,
location: location, location: location,
@ -174,7 +181,7 @@
element.parentNode.removeChild( element ); element.parentNode.removeChild( element );
//this should allow us to preserve overlays when required between //this should allow us to preserve overlays when required between
//pages //pages
if( element.prevElementParent ){ if ( element.prevElementParent ) {
style.display = 'none'; style.display = 'none';
//element.prevElementParent.insertBefore( //element.prevElementParent.insertBefore(
// element, // element,
@ -209,9 +216,15 @@
viewport.viewer.drawer.canvas.width / 2, viewport.viewer.drawer.canvas.width / 2,
viewport.viewer.drawer.canvas.height / 2 viewport.viewer.drawer.canvas.height / 2
), ),
degrees = viewport.degrees, degrees = viewport.degrees,
position, position = viewport.pixelFromPoint(
size, this.bounds.getTopLeft(),
true
),
size = viewport.deltaPixelsFromPoints(
this.bounds.getSize(),
true
),
overlayCenter; overlayCenter;
if ( element.parentNode != container ) { if ( element.parentNode != container ) {
@ -225,8 +238,8 @@
this.size = $.getElementSize( element ); this.size = $.getElementSize( element );
} }
position = this.position; this.position = position;
size = this.size; this.size = size;
this.adjust( position, size ); this.adjust( position, size );

View File

@ -76,10 +76,10 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Substract another Point to this point and return a new Point.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @param {OpenSeadragon.Point} point The point to substract vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the * @returns {OpenSeadragon.Point} A new point representing the substraction of the
* vector components * vector components
*/ */
minus: function( point ) { minus: function( point ) {
@ -90,11 +90,11 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Multiply this point by a factor and return a new Point.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @param {Number} factor The factor to multiply vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the * @returns {OpenSeadragon.Point} A new point representing the multiplication
* vector components * of the vector components by the factor
*/ */
times: function( factor ) { times: function( factor ) {
return new $.Point( return new $.Point(
@ -104,11 +104,11 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Divide this point by a factor and return a new Point.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @param {Number} factor The factor to divide vector components.
* @returns {OpenSeadragon.Point} A new point representing the sum of the * @returns {OpenSeadragon.Point} A new point representing the division of the
* vector components * vector components by the factor
*/ */
divide: function( factor ) { divide: function( factor ) {
return new $.Point( return new $.Point(
@ -118,10 +118,9 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Compute the opposite of this point and return a new Point.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @returns {OpenSeadragon.Point} A new point representing the opposite of the
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components * vector components
*/ */
negate: function() { negate: function() {
@ -129,11 +128,10 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Compute the distance between this point and another point.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @param {OpenSeadragon.Point} point The point to compute the distance with.
* @returns {OpenSeadragon.Point} A new point representing the sum of the * @returns {Number} The distance between the 2 points
* vector components
*/ */
distanceTo: function( point ) { distanceTo: function( point ) {
return Math.sqrt( return Math.sqrt(
@ -143,22 +141,21 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Apply a function to each coordinate of this point and return a new point.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @param {function} func The function to apply to each coordinate.
* @returns {OpenSeadragon.Point} A new point representing the sum of the * @returns {OpenSeadragon.Point} A new point with the coordinates computed
* vector components * by the specified function
*/ */
apply: function( func ) { apply: function( func ) {
return new $.Point( func( this.x ), func( this.y ) ); return new $.Point( func( this.x ), func( this.y ) );
}, },
/** /**
* Add another Point to this point and return a new Point. * Check if this point is equal to another one.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @param {OpenSeadragon.Point} point The point to compare this point with.
* @returns {OpenSeadragon.Point} A new point representing the sum of the * @returns {Boolean} true if they are equal, false otherwise.
* vector components
*/ */
equals: function( point ) { equals: function( point ) {
return ( return (
@ -186,11 +183,10 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{
}, },
/** /**
* Add another Point to this point and return a new Point. * Convert this point to a string in the format (x,y) where x and y are
* rounded to the nearest integer.
* @function * @function
* @param {OpenSeadragon.Point} point The point to add vector components. * @returns {String} A string representation of this point.
* @returns {OpenSeadragon.Point} A new point representing the sum of the
* vector components
*/ */
toString: function() { toString: function() {
return "(" + Math.round(this.x) + "," + Math.round(this.y) + ")"; return "(" + Math.round(this.x) + "," + Math.round(this.y) + ")";

View File

@ -55,7 +55,9 @@ var I18N = {
ZoomIn: "Zoom in", ZoomIn: "Zoom in",
ZoomOut: "Zoom out", ZoomOut: "Zoom out",
NextPage: "Next page", NextPage: "Next page",
PreviousPage: "Previous page" PreviousPage: "Previous page",
RotateLeft: "Rotate left",
RotateRight: "Rotate right"
} }
}; };

View File

@ -231,8 +231,10 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
* Renders the tile in a canvas-based context. * Renders the tile in a canvas-based context.
* @function * @function
* @param {Canvas} context * @param {Canvas} context
* @param {Function} method for firing the drawing event. drawingHandler({context, tile, rendered})
* where <code>rendered</code> is the context with the pre-drawn image.
*/ */
drawCanvas: function( context ) { drawCanvas: function( context, drawingHandler ) {
var position = this.position, var position = this.position,
size = this.size, size = this.size,
@ -280,6 +282,9 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
rendered = TILE_CACHE[ this.url ]; rendered = TILE_CACHE[ this.url ];
// This gives the application a chance to make image manipulation changes as we are rendering the image
drawingHandler({context: context, tile: this, rendered: rendered});
//rendered.save(); //rendered.save();
context.drawImage( context.drawImage(
rendered.canvas, rendered.canvas,
@ -298,7 +303,7 @@ $.Tile.prototype = /** @lends OpenSeadragon.Tile.prototype */{
}, },
/** /**
* Removes tile from it's contianer. * Removes tile from its container.
* @function * @function
*/ */
unload: function() { unload: function() {

View File

@ -55,7 +55,7 @@
* @param {Number|Object|Array|String} width * @param {Number|Object|Array|String} width
* If more than a single argument is supplied, the traditional use of * If more than a single argument is supplied, the traditional use of
* positional parameters is supplied and width is expected to be the width * positional parameters is supplied and width is expected to be the width
* source image at it's max resolution in pixels. If a single argument is supplied and * source image at its max resolution in pixels. If a single argument is supplied and
* it is an Object or Array, the construction is assumed to occur through * it is an Object or Array, the construction is assumed to occur through
* the extending classes implementation of 'configure'. Finally if only a * the extending classes implementation of 'configure'. Finally if only a
* single argument is supplied and it is a String, the extending class is * single argument is supplied and it is a String, the extending class is
@ -93,7 +93,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
} }
//Tile sources supply some events, namely 'ready' when they must be configured //Tile sources supply some events, namely 'ready' when they must be configured
//by asyncronously fetching their configuration data. //by asynchronously fetching their configuration data.
$.EventSource.call( this ); $.EventSource.call( this );
//we allow options to override anything we dont treat as //we allow options to override anything we dont treat as
@ -131,7 +131,7 @@ $.TileSource = function( width, height, tileSize, tileOverlap, minLevel, maxLeve
* @memberof OpenSeadragon.TileSource# * @memberof OpenSeadragon.TileSource#
*/ */
/** /**
* The overlap in pixels each tile shares with it's adjacent neighbors. * The overlap in pixels each tile shares with its adjacent neighbors.
* @member {Number} tileOverlap * @member {Number} tileOverlap
* @memberof OpenSeadragon.TileSource# * @memberof OpenSeadragon.TileSource#
*/ */
@ -366,7 +366,7 @@ $.TileSource.prototype = /** @lends OpenSeadragon.TileSource.prototype */{
callback: callback callback: callback
}); });
} else { } else {
// request info via xhr asyncronously. // request info via xhr asynchronously.
$.makeAjaxRequest( url, function( xhr ) { $.makeAjaxRequest( url, function( xhr ) {
var data = processResponse( xhr ); var data = processResponse( xhr );
callback( data ); callback( data );

View File

@ -74,8 +74,7 @@ $.Viewer = function( options ) {
xmlPath: args.length > 1 ? args[ 1 ] : undefined, xmlPath: args.length > 1 ? args[ 1 ] : undefined,
prefixUrl: args.length > 2 ? args[ 2 ] : undefined, prefixUrl: args.length > 2 ? args[ 2 ] : undefined,
controls: args.length > 3 ? args[ 3 ] : undefined, controls: args.length > 3 ? args[ 3 ] : undefined,
overlays: args.length > 4 ? args[ 4 ] : undefined, overlays: args.length > 4 ? args[ 4 ] : undefined
overlayControls: args.length > 5 ? args[ 5 ] : undefined
}; };
} }
@ -127,9 +126,8 @@ $.Viewer = function( options ) {
*/ */
canvas: null, canvas: null,
//TODO: not sure how to best describe these // Overlays list. An overlay allows to add html on top of the viewer.
overlays: [], overlays: [],
overlayControls:[],
//private state properties //private state properties
previousBody: [], previousBody: [],
@ -211,6 +209,7 @@ $.Viewer = function( options ) {
}; };
this._updateRequestId = null; this._updateRequestId = null;
this.currentOverlays = [];
//Inherit some behaviors and properties //Inherit some behaviors and properties
$.EventSource.call( this ); $.EventSource.call( this );
@ -517,9 +516,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
this.navigator.close(); this.navigator.close();
} }
if ( this.drawer ) { this.clearOverlays();
this.drawer.clearOverlays();
}
this.source = null; this.source = null;
this.drawer = null; this.drawer = null;
@ -856,6 +853,10 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
} }
if ( this.navigator && this.viewport ) {
this.navigator.update( this.viewport );
}
/** /**
* Raised when the viewer has changed to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}). * Raised when the viewer has changed to/from full-page mode (see {@link OpenSeadragon.Viewer#setFullPage}).
* *
@ -937,6 +938,9 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
_this.element.style.height = _this.fullPageStyleHeight; _this.element.style.height = _this.fullPageStyleHeight;
} }
} }
if ( _this.navigator && _this.viewport ) {
_this.navigator.update( _this.viewport );
}
/** /**
* Raised when the viewer has changed to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}). * Raised when the viewer has changed to/from full-screen mode (see {@link OpenSeadragon.Viewer#setFullScreen}).
* *
@ -1318,7 +1322,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
}else{ }else{
this.addControl( this.addControl(
this.pagingControl, this.pagingControl,
{anchor: $.ControlAnchor.TOP_LEFT} {anchor: this.sequenceControlAnchor || $.ControlAnchor.TOP_LEFT}
); );
} }
} }
@ -1342,6 +1346,8 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ), doSingleZoomOutHandler = $.delegate( this, doSingleZoomOut ),
onHomeHandler = $.delegate( this, onHome ), onHomeHandler = $.delegate( this, onHome ),
onFullScreenHandler = $.delegate( this, onFullScreen ), onFullScreenHandler = $.delegate( this, onFullScreen ),
onRotateLeftHandler = $.delegate( this, onRotateLeft ),
onRotateRightHandler = $.delegate( this, onRotateRight ),
onFocusHandler = $.delegate( this, onFocus ), onFocusHandler = $.delegate( this, onFocus ),
onBlurHandler = $.delegate( this, onBlur ), onBlurHandler = $.delegate( this, onBlur ),
navImages = this.navImages, navImages = this.navImages,
@ -1421,6 +1427,37 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
onBlur: onBlurHandler onBlur: onBlurHandler
})); }));
if (this.showRotationControl) {
buttons.push( this.rotateLeft = new $.Button({
element: this.rotateLeftButton ? $.getElement( this.rotateLeftButton ) : null,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.RotateLeft" ),
srcRest: resolveUrl( this.prefixUrl, navImages.rotateleft.REST ),
srcGroup: resolveUrl( this.prefixUrl, navImages.rotateleft.GROUP ),
srcHover: resolveUrl( this.prefixUrl, navImages.rotateleft.HOVER ),
srcDown: resolveUrl( this.prefixUrl, navImages.rotateleft.DOWN ),
onRelease: onRotateLeftHandler,
onFocus: onFocusHandler,
onBlur: onBlurHandler
}));
buttons.push( this.rotateRight = new $.Button({
element: this.rotateRightButton ? $.getElement( this.rotateRightButton ) : null,
clickTimeThreshold: this.clickTimeThreshold,
clickDistThreshold: this.clickDistThreshold,
tooltip: $.getString( "Tooltips.RotateRight" ),
srcRest: resolveUrl( this.prefixUrl, navImages.rotateright.REST ),
srcGroup: resolveUrl( this.prefixUrl, navImages.rotateright.GROUP ),
srcHover: resolveUrl( this.prefixUrl, navImages.rotateright.HOVER ),
srcDown: resolveUrl( this.prefixUrl, navImages.rotateright.DOWN ),
onRelease: onRotateRightHandler,
onFocus: onFocusHandler,
onBlur: onBlurHandler
}));
}
if( useGroup ){ if( useGroup ){
this.buttons = new $.ButtonGroup({ this.buttons = new $.ButtonGroup({
buttons: buttons, buttons: buttons,
@ -1439,7 +1476,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
}else{ }else{
this.addControl( this.addControl(
this.navControl, this.navControl,
{anchor: $.ControlAnchor.TOP_LEFT} {anchor: this.navigationControlAnchor || $.ControlAnchor.TOP_LEFT}
); );
} }
} }
@ -1490,6 +1527,173 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype,
return this; return this;
}, },
/**
* Adds an html element as an overlay to the current viewport. Useful for
* highlighting words or areas of interest on an image or other zoomable
* interface. The overlays added via this method are removed when the viewport
* is closed which include when changing page.
* @method
* @param {Element|String|Object} element - A reference to an element or an id for
* the element which will overlayed. Or an Object specifying the configuration for the overlay
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
* rectangle which will be overlayed.
* @param {OpenSeadragon.OverlayPlacement} placement - The position of the
* viewport which the location coordinates will be treated as relative
* to.
* @param {function} onDraw - If supplied the callback is called when the overlay
* needs to be drawn. It it the responsibility of the callback to do any drawing/positioning.
* It is passed position, size and element.
* @return {OpenSeadragon.Viewer} Chainable.
* @fires OpenSeadragon.Viewer.event:add-overlay
*/
addOverlay: function( element, location, placement, onDraw ) {
var options;
if( $.isPlainObject( element ) ){
options = element;
} else {
options = {
element: element,
location: location,
placement: placement,
onDraw: onDraw
};
}
element = $.getElement( options.element );
if ( getOverlayIndex( this.currentOverlays, element ) >= 0 ) {
// they're trying to add a duplicate overlay
return this;
}
this.currentOverlays.push( getOverlayObject( this, options ) );
THIS[ this.hash ].forceRedraw = true;
/**
* Raised when an overlay is added to the viewer (see {@link OpenSeadragon.Viewer#addOverlay}).
*
* @event add-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {Element} element - The overlay element.
* @property {OpenSeadragon.Point|OpenSeadragon.Rect} location
* @property {OpenSeadragon.OverlayPlacement} placement
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'add-overlay', {
element: element,
location: options.location,
placement: options.placement
});
return this;
},
/**
* Updates the overlay represented by the reference to the element or
* element id moving it to the new location, relative to the new placement.
* @method
* @param {OpenSeadragon.Point|OpenSeadragon.Rect} location - The point or
* rectangle which will be overlayed.
* @param {OpenSeadragon.OverlayPlacement} placement - The position of the
* viewport which the location coordinates will be treated as relative
* to.
* @return {OpenSeadragon.Viewer} Chainable.
* @fires OpenSeadragon.Viewer.event:update-overlay
*/
updateOverlay: function( element, location, placement ) {
var i;
element = $.getElement( element );
i = getOverlayIndex( this.currentOverlays, element );
if ( i >= 0 ) {
this.currentOverlays[ i ].update( location, placement );
THIS[ this.hash ].forceRedraw = true;
/**
* Raised when an overlay's location or placement changes
* (see {@link OpenSeadragon.Viewer#updateOverlay}).
*
* @event update-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the
* Viewer which raised the event.
* @property {Element} element
* @property {OpenSeadragon.Point|OpenSeadragon.Rect} location
* @property {OpenSeadragon.OverlayPlacement} placement
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'update-overlay', {
element: element,
location: location,
placement: placement
});
}
return this;
},
/**
* Removes an overlay identified by the reference element or element id
* and schedules an update.
* @method
* @param {Element|String} element - A reference to the element or an
* element id which represent the ovelay content to be removed.
* @return {OpenSeadragon.Viewer} Chainable.
* @fires OpenSeadragon.Viewer.event:remove-overlay
*/
removeOverlay: function( element ) {
var i;
element = $.getElement( element );
i = getOverlayIndex( this.currentOverlays, element );
if ( i >= 0 ) {
this.currentOverlays[ i ].destroy();
this.currentOverlays.splice( i, 1 );
THIS[ this.hash ].forceRedraw = true;
/**
* Raised when an overlay is removed from the viewer
* (see {@link OpenSeadragon.Viewer#removeOverlay}).
*
* @event remove-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the
* Viewer which raised the event.
* @property {Element} element - The overlay element.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'remove-overlay', {
element: element
});
}
return this;
},
/**
* Removes all currently configured Overlays from this Viewer and schedules
* an update.
* @method
* @return {OpenSeadragon.Viewer} Chainable.
* @fires OpenSeadragon.Viewer.event:clear-overlay
*/
clearOverlays: function() {
while ( this.currentOverlays.length > 0 ) {
this.currentOverlays.pop().destroy();
}
THIS[ this.hash ].forceRedraw = true;
/**
* Raised when all overlays are removed from the viewer (see {@link OpenSeadragon.Drawer#clearOverlays}).
*
* @event clear-overlay
* @memberof OpenSeadragon.Viewer
* @type {object}
* @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event.
* @property {?Object} userData - Arbitrary subscriber-defined object.
*/
this.raiseEvent( 'clear-overlay', {} );
return this;
},
/** /**
* Updates the sequence buttons. * Updates the sequence buttons.
* @function OpenSeadragon.Viewer.prototype._updateSequenceButtons * @function OpenSeadragon.Viewer.prototype._updateSequenceButtons
@ -1630,9 +1834,8 @@ function getTileSourceImplementation( viewer, tileSource, successCallback,
* @private * @private
*/ */
function openTileSource( viewer, source ) { function openTileSource( viewer, source ) {
var _this = viewer, var i,
overlay, _this = viewer;
i;
if ( _this.source ) { if ( _this.source ) {
_this.close( ); _this.close( );
@ -1660,12 +1863,13 @@ function openTileSource( viewer, source ) {
showNavigator: false, showNavigator: false,
minZoomImageRatio: 1, minZoomImageRatio: 1,
maxZoomPixelRatio: 1, maxZoomPixelRatio: 1,
viewer: _this //, viewer: _this,
degrees: _this.degrees //,
//TODO: figure out how to support these in a way that makes sense //TODO: figure out how to support these in a way that makes sense
//minZoomLevel: this.minZoomLevel, //minZoomLevel: this.minZoomLevel,
//maxZoomLevel: this.maxZoomLevel //maxZoomLevel: this.maxZoomLevel
}); });
}else{ } else {
if( source ){ if( source ){
_this.source = source; _this.source = source;
} }
@ -1682,7 +1886,8 @@ function openTileSource( viewer, source ) {
defaultZoomLevel: _this.defaultZoomLevel, defaultZoomLevel: _this.defaultZoomLevel,
minZoomLevel: _this.minZoomLevel, minZoomLevel: _this.minZoomLevel,
maxZoomLevel: _this.maxZoomLevel, maxZoomLevel: _this.maxZoomLevel,
viewer: _this viewer: _this,
degrees: _this.degrees
}); });
} }
@ -1697,7 +1902,6 @@ function openTileSource( viewer, source ) {
source: _this.source, source: _this.source,
viewport: _this.viewport, viewport: _this.viewport,
element: _this.canvas, element: _this.canvas,
overlays: [].concat( _this.overlays ).concat( _this.source.overlays ),
opacity: _this.opacity, opacity: _this.opacity,
maxImageCacheCount: _this.maxImageCacheCount, maxImageCacheCount: _this.maxImageCacheCount,
imageLoaderLimit: _this.imageLoaderLimit, imageLoaderLimit: _this.imageLoaderLimit,
@ -1714,6 +1918,21 @@ function openTileSource( viewer, source ) {
}); });
_this.drawers = [_this.drawer]; _this.drawers = [_this.drawer];
// Now that we have a drawer, see if it supports rotate. If not we need to remove the rotate buttons
if (!_this.drawer.canRotate()) {
// Disable/remove the rotate left/right buttons since they aren't supported
if (_this.rotateLeft) {
i = _this.buttons.buttons.indexOf(_this.rotateLeft);
_this.buttons.buttons.splice(i, 1);
_this.buttons.element.removeChild(_this.rotateLeft.element);
}
if (_this.rotateRight) {
i = _this.buttons.buttons.indexOf(_this.rotateRight);
_this.buttons.buttons.splice(i, 1);
_this.buttons.element.removeChild(_this.rotateRight.element);
}
}
//Instantiate a navigator if configured //Instantiate a navigator if configured
if ( _this.showNavigator && !_this.collectionMode ){ if ( _this.showNavigator && !_this.collectionMode ){
// Note: By passing the fully parsed source, the navigator doesn't // Note: By passing the fully parsed source, the navigator doesn't
@ -1722,16 +1941,19 @@ function openTileSource( viewer, source ) {
_this.navigator.open( source ); _this.navigator.open( source );
} else { } else {
_this.navigator = new $.Navigator({ _this.navigator = new $.Navigator({
id: _this.navigatorId, id: _this.navigatorId,
position: _this.navigatorPosition, position: _this.navigatorPosition,
sizeRatio: _this.navigatorSizeRatio, sizeRatio: _this.navigatorSizeRatio,
height: _this.navigatorHeight, maintainSizeRatio: _this.navigatorMaintainSizeRatio,
width: _this.navigatorWidth, top: _this.navigatorTop,
tileSources: source, left: _this.navigatorLeft,
tileHost: _this.tileHost, width: _this.navigatorWidth,
prefixUrl: _this.prefixUrl, height: _this.navigatorHeight,
overlays: _this.overlays, autoResize: _this.navigatorAutoResize,
viewer: _this tileSources: source,
tileHost: _this.tileHost,
prefixUrl: _this.prefixUrl,
viewer: _this
}); });
} }
} }
@ -1748,7 +1970,6 @@ function openTileSource( viewer, source ) {
tileSources: _this.tileSources, tileSources: _this.tileSources,
tileHost: _this.tileHost, tileHost: _this.tileHost,
prefixUrl: _this.prefixUrl, prefixUrl: _this.prefixUrl,
overlays: _this.overlays,
viewer: _this viewer: _this
}); });
} }
@ -1759,40 +1980,10 @@ function openTileSource( viewer, source ) {
THIS[ _this.hash ].forceRedraw = true; THIS[ _this.hash ].forceRedraw = true;
_this._updateRequestId = scheduleUpdate( _this, updateMulti ); _this._updateRequestId = scheduleUpdate( _this, updateMulti );
//Assuming you had programatically created a bunch of overlays
//and added them via configuration
for ( i = 0; i < _this.overlayControls.length; i++ ) {
overlay = _this.overlayControls[ i ];
if ( overlay.point ) {
_this.drawer.addOverlay(
overlay.id,
new $.Point(
overlay.point.X,
overlay.point.Y
),
$.OverlayPlacement.TOP_LEFT
);
} else {
_this.drawer.addOverlay(
overlay.id,
new $.Rect(
overlay.rect.Point.X,
overlay.rect.Point.Y,
overlay.rect.Width,
overlay.rect.Height
),
overlay.placement
);
}
}
VIEWERS[ _this.hash ] = _this; VIEWERS[ _this.hash ] = _this;
loadOverlays( _this );
/** /**
* Raised when the viewer has opened and loaded one or more TileSources. * Raised when the viewer has opened and loaded one or more TileSources.
* *
@ -1808,8 +1999,98 @@ function openTileSource( viewer, source ) {
return _this; return _this;
} }
function loadOverlays( _this ) {
_this.currentOverlays = [];
for ( var i = 0; i < _this.overlays.length; i++ ) {
_this.currentOverlays[ i ] = getOverlayObject( _this, _this.overlays[ i ] );
}
for ( var j = 0; j < _this.source.overlays.length; j++ ) {
_this.currentOverlays[ i + j ] =
getOverlayObject( _this, _this.source.overlays[ j ] );
}
}
function getOverlayObject( viewer, overlay ) {
if ( overlay instanceof $.Overlay ) {
return overlay;
}
var element = null;
if ( overlay.element ) {
element = $.getElement( overlay.element );
} else {
var id = overlay.id ?
overlay.id :
"openseadragon-overlay-" + Math.floor( Math.random() * 10000000 );
element = $.getElement( overlay.id );
if ( !element ) {
element = document.createElement( "a" );
element.href = "#/overlay/" + id;
}
element.id = id;
$.addClass( element, overlay.className ?
overlay.className :
"openseadragon-overlay"
);
}
var location = overlay.location;
if ( !location ) {
var rect = ( overlay.height && overlay.width ) ? new $.Rect(
overlay.x || overlay.px,
overlay.y || overlay.py,
overlay.width,
overlay.height
) : new $.Point(
overlay.x || overlay.px,
overlay.y || overlay.py
);
if( overlay.px !== undefined ) {
//if they specified 'px' so it's in pixel coordinates so
//we need to translate to viewport coordinates
rect = viewer.viewport.imageToViewportRectangle( rect );
}
location = overlay.placement ? viewer.viewport.pointFromPixel( rect ) :
rect;
}
var placement = overlay.placement;
if ( placement && ( $.type( placement ) === "string" ) ) {
placement = $.OverlayPlacement[ overlay.placement.toUpperCase() ];
}
return new $.Overlay({
element: element,
location: location,
placement: placement,
onDraw: overlay.onDraw
});
}
/**
* @private
* @inner
* Determines the index of the given overlay in the given overlays array.
*/
function getOverlayIndex( overlays, element ) {
var i;
for ( i = overlays.length - 1; i >= 0; i-- ) {
if ( overlays[ i ].element === element ) {
return i;
}
}
return -1;
}
function drawOverlays( viewport, overlays, container ) {
var i,
length = overlays.length;
for ( i = 0; i < length; i++ ) {
overlays[ i ].drawHTML( container, viewport );
}
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// Schedulers provide the general engine for animation // Schedulers provide the general engine for animation
@ -2183,6 +2464,7 @@ function updateOnce( viewer ) {
if ( animated ) { if ( animated ) {
updateDrawers( viewer ); updateDrawers( viewer );
drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.canvas );
if( viewer.navigator ){ if( viewer.navigator ){
viewer.navigator.update( viewer.viewport ); viewer.navigator.update( viewer.viewport );
} }
@ -2198,6 +2480,7 @@ function updateOnce( viewer ) {
viewer.raiseEvent( "animation" ); viewer.raiseEvent( "animation" );
} else if ( THIS[ viewer.hash ].forceRedraw || drawersNeedUpdate( viewer ) ) { } else if ( THIS[ viewer.hash ].forceRedraw || drawersNeedUpdate( viewer ) ) {
updateDrawers( viewer ); updateDrawers( viewer );
drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.canvas );
if( viewer.navigator ){ if( viewer.navigator ){
viewer.navigator.update( viewer.viewport ); viewer.navigator.update( viewer.viewport );
} }
@ -2371,6 +2654,38 @@ function onFullScreen() {
} }
} }
/**
* Note: The current rotation feature is limited to 90 degree turns.
*/
function onRotateLeft() {
if ( this.viewport ) {
var currRotation = this.viewport.getRotation();
if (currRotation === 0) {
currRotation = 270;
}
else {
currRotation -= 90;
}
this.viewport.setRotation(currRotation);
}
}
/**
* Note: The current rotation feature is limited to 90 degree turns.
*/
function onRotateRight() {
if ( this.viewport ) {
var currRotation = this.viewport.getRotation();
if (currRotation === 270) {
currRotation = 0;
}
else {
currRotation += 90;
}
this.viewport.setRotation(currRotation);
}
}
function onPrevious(){ function onPrevious(){
var previous = THIS[ this.hash ].sequence - 1; var previous = THIS[ this.hash ].sequence - 1;

View File

@ -920,12 +920,12 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{
/** /**
* Convert pixel coordinates relative to the image to * Convert pixel coordinates relative to the image to
* viewer element coordinates. * viewer element coordinates.
* @param {OpenSeadragon.Point} point * @param {OpenSeadragon.Point} pixel
* @returns {OpenSeadragon.Point} * @returns {OpenSeadragon.Point}
*/ */
imageToViewerElementCoordinates: function( point ) { imageToViewerElementCoordinates: function( pixel ) {
var pixel = this.pixelFromPoint( point, true ); var point = this.imageToViewportCoordinates( pixel );
return this.imageToViewportCoordinates( pixel ); return this.pixelFromPoint( point, true );
}, },
/** /**

View File

@ -0,0 +1,18 @@
{
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1",
"height": 870,
"width": 1048,
"qualities": [
"native",
"color",
"grey",
"bitonal"
],
"formats": [
"jpg",
"png",
"gif"
],
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
"@id": "http://localhost:8000/test/data/iiif_1_1_no_tiles_1048"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

After

Width:  |  Height:  |  Size: 710 B

View File

@ -0,0 +1,18 @@
{
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1",
"height": 212,
"width": 255,
"qualities": [
"native",
"color",
"grey",
"bitonal"
],
"formats": [
"jpg",
"png",
"gif"
],
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
"@id": "http://localhost:8000/test/data/iiif_1_1_no_tiles_255"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 691 B

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 689 B

View File

@ -0,0 +1,18 @@
{
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1",
"height": 319,
"width": 384,
"qualities": [
"native",
"color",
"grey",
"bitonal"
],
"formats": [
"jpg",
"png",
"gif"
],
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
"@id": "http://localhost:8000/test/data/iiif_1_1_no_tiles_384"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 758 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1012 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -1,7 +1,7 @@
{ {
"profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", "profile": "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2",
"height": 850, "height": 637,
"width": 1024, "width": 768,
"qualities": [ "qualities": [
"native", "native",
"color", "color",
@ -14,6 +14,5 @@
"gif" "gif"
], ],
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
"@id": "http://localhost:8000/test/data/iiif_no_tiles" "@id": "http://localhost:8000/test/data/iiif_1_1_no_tiles_768"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 690 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -24,5 +24,5 @@
"gif" "gif"
], ],
"@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json", "@context": "http://library.stanford.edu/iiif/image-api/1.1/context.json",
"@id": "http://localhost:8000/test/data/iiif_1_1_files" "@id": "http://localhost:8000/test/data/iiif_1_1_tiled"
} }

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 23 KiB

View File

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 9.9 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 717 B

View File

Before

Width:  |  Height:  |  Size: 716 B

After

Width:  |  Height:  |  Size: 716 B

View File

Before

Width:  |  Height:  |  Size: 717 B

After

Width:  |  Height:  |  Size: 717 B

View File

Before

Width:  |  Height:  |  Size: 712 B

After

Width:  |  Height:  |  Size: 712 B

View File

Before

Width:  |  Height:  |  Size: 633 B

After

Width:  |  Height:  |  Size: 633 B

View File

Before

Width:  |  Height:  |  Size: 810 B

After

Width:  |  Height:  |  Size: 810 B

View File

Before

Width:  |  Height:  |  Size: 663 B

After

Width:  |  Height:  |  Size: 663 B

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

Before

Width:  |  Height:  |  Size: 675 B

After

Width:  |  Height:  |  Size: 675 B

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

View File

Before

Width:  |  Height:  |  Size: 683 B

After

Width:  |  Height:  |  Size: 683 B

Some files were not shown because too many files have changed in this diff Show More