Move all overlay code from drawer to viewer

This commit is contained in:
Antoine Vandecreme 2014-01-30 15:38:37 -05:00
parent 7210181b4f
commit 365dad9317
3 changed files with 275 additions and 297 deletions

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
maxImageCacheCount: $.DEFAULT_SETTINGS.maxImageCacheCount, maxImageCacheCount: $.DEFAULT_SETTINGS.maxImageCacheCount,
@ -148,199 +147,11 @@ $.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();
}; };
$.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{ $.Drawer.prototype = /** @lends OpenSeadragon.Drawer.prototype */{
/**
* 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.
* @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.
* @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.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;
},
/**
* 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.Drawer} Chainable.
* @fires OpenSeadragon.Viewer.event:update-overlay
*/
updateOverlay: function( element, location, placement ) {
var i;
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;
},
/**
* Removes and overlay identified by the reference element or element id
* and schedules and 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.Drawer} Chainable.
* @fires OpenSeadragon.Viewer.event:remove-overlay
*/
removeOverlay: function( element ) {
var i;
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;
},
/**
* Removes all currently configured Overlays from this Drawer and schedules
* and update.
* @method
* @return {OpenSeadragon.Drawer} Chainable.
* @fires OpenSeadragon.Viewer.event:clear-overlay
*/
clearOverlays: function() {
while ( this.overlays.length > 0 ) {
this.overlays.pop().destroy();
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;
},
/** /**
* 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.
@ -467,61 +278,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
@ -695,7 +451,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 ) {
@ -1142,23 +897,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
@ -1196,28 +934,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,

View File

@ -174,7 +174,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,
@ -208,10 +208,16 @@
drawerCenter = new $.Point( drawerCenter = new $.Point(
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 +231,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

@ -126,7 +126,7 @@ $.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: [],
//private state properties //private state properties
@ -570,9 +570,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;
@ -1299,6 +1297,178 @@ $.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.
* @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( new $.Overlay({
element: element,
location: options.location,
placement: options.placement,
onDraw: options.onDraw
}) );
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
@ -1417,7 +1587,7 @@ function openTileSource( viewer, source ) {
//minZoomLevel: this.minZoomLevel, //minZoomLevel: this.minZoomLevel,
//maxZoomLevel: this.maxZoomLevel //maxZoomLevel: this.maxZoomLevel
}); });
}else{ } else {
if( source ){ if( source ){
_this.source = source; _this.source = source;
} }
@ -1515,6 +1685,16 @@ function openTileSource( viewer, source ) {
VIEWERS[ _this.hash ] = _this; VIEWERS[ _this.hash ] = _this;
_this.currentOverlays = [];
var i;
for ( 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 ] );
}
/** /**
* Raised when the viewer has opened and loaded one or more TileSources. * Raised when the viewer has opened and loaded one or more TileSources.
* *
@ -1530,8 +1710,82 @@ function openTileSource( viewer, source ) {
return _this; return _this;
} }
function getOverlayObject( viewer, overlay ) {
if ( !$.isPlainObject( overlay ) ) {
return 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 = viewer.viewport.imageToViewportRectangle( rect );
}
if( overlay.placement ){
return new $.Overlay({
element: element,
location: viewer.viewport.pointFromPixel( rect ),
placement: $.OverlayPlacement[ overlay.placement.toUpperCase() ],
onDraw: overlay.onDraw
});
} else {
return new $.Overlay({
element: element,
location: rect,
onDraw: overlay.onDraw
});
}
}
/**
* @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;
}
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
@ -1905,6 +2159,7 @@ function updateOnce( viewer ) {
if ( animated ) { if ( animated ) {
viewer.drawer.update(); viewer.drawer.update();
drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.canvas );
if( viewer.navigator ){ if( viewer.navigator ){
viewer.navigator.update( viewer.viewport ); viewer.navigator.update( viewer.viewport );
} }
@ -1920,6 +2175,7 @@ function updateOnce( viewer ) {
viewer.raiseEvent( "animation" ); viewer.raiseEvent( "animation" );
} else if ( THIS[ viewer.hash ].forceRedraw || viewer.drawer.needsUpdate() ) { } else if ( THIS[ viewer.hash ].forceRedraw || viewer.drawer.needsUpdate() ) {
viewer.drawer.update(); viewer.drawer.update();
drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.canvas );
if( viewer.navigator ){ if( viewer.navigator ){
viewer.navigator.update( viewer.viewport ); viewer.navigator.update( viewer.viewport );
} }