From 7210181b4f5d716b6fafba750c359e148f243f06 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Wed, 29 Jan 2014 16:31:13 -0500 Subject: [PATCH 01/13] Remove not working code --- src/viewer.js | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 2139678e..11a96691 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -74,8 +74,7 @@ $.Viewer = function( options ) { xmlPath: args.length > 1 ? args[ 1 ] : undefined, prefixUrl: args.length > 2 ? args[ 2 ] : undefined, controls: args.length > 3 ? args[ 3 ] : undefined, - overlays: args.length > 4 ? args[ 4 ] : undefined, - overlayControls: args.length > 5 ? args[ 5 ] : undefined + overlays: args.length > 4 ? args[ 4 ] : undefined }; } @@ -129,7 +128,6 @@ $.Viewer = function( options ) { //TODO: not sure how to best describe these overlays: [], - overlayControls:[], //private state properties previousBody: [], @@ -1386,9 +1384,7 @@ function _getSafeElemSize (oElement) { * @private */ function openTileSource( viewer, source ) { - var _this = viewer, - overlay, - i; + var _this = viewer; if ( _this.source ) { _this.close( ); @@ -1517,38 +1513,6 @@ function openTileSource( viewer, source ) { THIS[ _this.hash ].forceRedraw = true; _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; /** From 365dad931742d5c512145145bb0e76b61198cf47 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Thu, 30 Jan 2014 15:38:37 -0500 Subject: [PATCH 02/13] Move all overlay code from drawer to viewer --- src/drawer.js | 286 +------------------------------------------------ src/overlay.js | 20 ++-- src/viewer.js | 266 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 275 insertions(+), 297 deletions(-) diff --git a/src/drawer.js b/src/drawer.js index a53d0d3b..27f0cdd7 100644 --- a/src/drawer.js +++ b/src/drawer.js @@ -87,8 +87,7 @@ $.Drawer = function( options ) { //internal state / configurable settings - overlays: [], // An unordered list of Overlays added. - collectionOverlays: {}, + collectionOverlays: {}, // For collection mode. Here an overlay is actually a viewer. //configurable settings maxImageCacheCount: $.DEFAULT_SETTINGS.maxImageCacheCount, @@ -148,199 +147,11 @@ $.Drawer = function( options ) { this.container.style.textAlign = "left"; 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(); }; $.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 * 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 * @inner @@ -695,7 +451,6 @@ function updateViewport( drawer ) { //TODO drawTiles( drawer, drawer.lastDrawn ); - drawOverlays( drawer.viewport, drawer.overlays, drawer.container ); //TODO if ( best ) { @@ -1142,23 +897,6 @@ function resetCoverage( 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 * @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 ){ var i, tile, diff --git a/src/overlay.js b/src/overlay.js index 29445389..c87c84e1 100644 --- a/src/overlay.js +++ b/src/overlay.js @@ -174,7 +174,7 @@ element.parentNode.removeChild( element ); //this should allow us to preserve overlays when required between //pages - if( element.prevElementParent ){ + if ( element.prevElementParent ) { style.display = 'none'; //element.prevElementParent.insertBefore( // element, @@ -208,10 +208,16 @@ drawerCenter = new $.Point( viewport.viewer.drawer.canvas.width / 2, viewport.viewer.drawer.canvas.height / 2 - ), - degrees = viewport.degrees, - position, - size, + ), + degrees = viewport.degrees, + position = viewport.pixelFromPoint( + this.bounds.getTopLeft(), + true + ), + size = viewport.deltaPixelsFromPoints( + this.bounds.getSize(), + true + ), overlayCenter; if ( element.parentNode != container ) { @@ -225,8 +231,8 @@ this.size = $.getElementSize( element ); } - position = this.position; - size = this.size; + this.position = position; + this.size = size; this.adjust( position, size ); diff --git a/src/viewer.js b/src/viewer.js index 11a96691..f9eb1242 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -126,7 +126,7 @@ $.Viewer = function( options ) { */ canvas: null, - //TODO: not sure how to best describe these + // Overlays list. An overlay allows to add html on top of the viewer. overlays: [], //private state properties @@ -570,9 +570,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, this.navigator.close(); } - if ( this.drawer ) { - this.drawer.clearOverlays(); - } + this.clearOverlays(); this.source = null; this.drawer = null; @@ -1299,6 +1297,178 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, 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. * @function OpenSeadragon.Viewer.prototype._updateSequenceButtons @@ -1417,7 +1587,7 @@ function openTileSource( viewer, source ) { //minZoomLevel: this.minZoomLevel, //maxZoomLevel: this.maxZoomLevel }); - }else{ + } else { if( source ){ _this.source = source; } @@ -1515,6 +1685,16 @@ function openTileSource( viewer, source ) { 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. * @@ -1530,8 +1710,82 @@ function openTileSource( viewer, source ) { 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 @@ -1905,6 +2159,7 @@ function updateOnce( viewer ) { if ( animated ) { viewer.drawer.update(); + drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.canvas ); if( viewer.navigator ){ viewer.navigator.update( viewer.viewport ); } @@ -1920,6 +2175,7 @@ function updateOnce( viewer ) { viewer.raiseEvent( "animation" ); } else if ( THIS[ viewer.hash ].forceRedraw || viewer.drawer.needsUpdate() ) { viewer.drawer.update(); + drawOverlays( viewer.viewport, viewer.currentOverlays, viewer.canvas ); if( viewer.navigator ){ viewer.navigator.update( viewer.viewport ); } From c4428db8a5301e56c45ad2984fb5a376193c748f Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Fri, 31 Jan 2014 11:49:44 -0500 Subject: [PATCH 03/13] Fix crash when closing the viewer when no overlay has been added. --- src/viewer.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/viewer.js b/src/viewer.js index f9eb1242..085eb73f 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -127,7 +127,10 @@ $.Viewer = function( options ) { canvas: null, // Overlays list. An overlay allows to add html on top of the viewer. - overlays: [], + // Configured overlays via viewer's options + overlays: [], + // Currently opened overlays + currentOverlays: [], //private state properties previousBody: [], From e26727488fd3487f3d0f32562dcb6276d30dd5e5 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Tue, 4 Feb 2014 16:59:45 -0500 Subject: [PATCH 04/13] Fix doc in point.js --- src/point.js | 56 ++++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/point.js b/src/point.js index b3cd928a..38aad1f1 100644 --- a/src/point.js +++ b/src/point.js @@ -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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the + * @param {OpenSeadragon.Point} point The point to substract vector components. + * @returns {OpenSeadragon.Point} A new point representing the substraction of the * vector components */ 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the - * vector components + * @param {Number} factor The factor to multiply vector components. + * @returns {OpenSeadragon.Point} A new point representing the multiplication + * of the vector components by the factor */ times: function( factor ) { 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the - * vector components + * @param {Number} factor The factor to divide vector components. + * @returns {OpenSeadragon.Point} A new point representing the division of the + * vector components by the factor */ divide: function( factor ) { 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the + * @returns {OpenSeadragon.Point} A new point representing the opposite of the * vector components */ 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the - * vector components + * @param {OpenSeadragon.Point} point The point to compute the distance with. + * @returns {Number} The distance between the 2 points */ distanceTo: function( point ) { 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the - * vector components + * @param {function} func The function to apply to each coordinate. + * @returns {OpenSeadragon.Point} A new point with the coordinates computed + * by the specified function */ apply: function( func ) { 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the - * vector components + * @param {OpenSeadragon.Point} point The point to compare this point with. + * @returns {Boolean} true if they are equal, false otherwise. */ equals: function( point ) { 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 - * @param {OpenSeadragon.Point} point The point to add vector components. - * @returns {OpenSeadragon.Point} A new point representing the sum of the - * vector components + * @returns {String} A string representation of this point. */ toString: function() { return "(" + Math.round(this.x) + "," + Math.round(this.y) + ")"; From ed5eae9a7374d01ca3e1f5ff633647552c04e782 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Tue, 4 Feb 2014 17:02:11 -0500 Subject: [PATCH 05/13] Fix imageToViewerElementCoordinates method and corresponding unit tests. --- src/viewport.js | 8 ++++---- test/units.js | 54 +++++++++++++++++++++++++++++-------------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/viewport.js b/src/viewport.js index 65230f4a..9049e3d6 100644 --- a/src/viewport.js +++ b/src/viewport.js @@ -920,12 +920,12 @@ $.Viewport.prototype = /** @lends OpenSeadragon.Viewport.prototype */{ /** * Convert pixel coordinates relative to the image to * viewer element coordinates. - * @param {OpenSeadragon.Point} point + * @param {OpenSeadragon.Point} pixel * @returns {OpenSeadragon.Point} */ - imageToViewerElementCoordinates: function( point ) { - var pixel = this.pixelFromPoint( point, true ); - return this.imageToViewportCoordinates( pixel ); + imageToViewerElementCoordinates: function( pixel ) { + var point = this.imageToViewportCoordinates( pixel ); + return this.pixelFromPoint( point, true ); }, /** diff --git a/test/units.js b/test/units.js index 348835b3..1ce10a09 100644 --- a/test/units.js +++ b/test/units.js @@ -26,12 +26,34 @@ function pointEqual(a, b, message) { - ok(a.x === b.x && a.y === b.y, message); + Util.assessNumericValue(a.x, b.x, 0.00000001, message); + Util.assessNumericValue(a.y, b.y, 0.00000001, message); } // ---------- asyncTest('Coordinates conversions', function() { + function checkPoint(context) { + var viewport = viewer.viewport; + + var point = new OpenSeadragon.Point(15, 12); + var result = viewport.viewerElementToImageCoordinates( + viewport.imageToViewerElementCoordinates(point)); + pointEqual(result, point, 'viewerElement and image ' + context); + + var result = viewport.windowToImageCoordinates( + viewport.imageToWindowCoordinates(point)); + pointEqual(result, point, 'window and image ' + context); + + var result = viewport.viewerElementToViewportCoordinates( + viewport.viewportToViewerElementCoordinates(point)); + pointEqual(result, point, 'viewerElement and viewport ' + context); + + var result = viewport.windowToViewportCoordinates( + viewport.viewportToWindowCoordinates(point)); + pointEqual(result, point, 'window and viewport ' + context); + } + viewer.addHandler("open", function () { var viewport = viewer.viewport; @@ -52,24 +74,13 @@ var pixel = viewport.viewerElementToImageCoordinates(viewerTopRight); pointEqual(pixel, imageTopRight, 'Viewer top right has viewport coordinates imageWidth,0.'); - var point = new OpenSeadragon.Point(15, 12); - var result = viewport.viewerElementToImageCoordinates( - viewport.imageToViewerElementCoordinates(point)); - pointEqual(result, point, 'viewerElement and image'); - - var result = viewport.windowToImageCoordinates( - viewport.imageToWindowCoordinates(point)); - pointEqual(result, point, 'window and image'); - - var result = viewport.viewerElementToViewportCoordinates( - viewport.viewportToViewerElementCoordinates(point)); - pointEqual(result, point, 'viewerElement and viewport'); - - var result = viewport.windowToViewportCoordinates( - viewport.viewportToWindowCoordinates(point)); - pointEqual(result, point, 'window and viewport'); - - start(); + checkPoint('after opening'); + viewer.addHandler('animation-finish', function animationHandler() { + viewer.removeHandler('animation-finish', animationHandler); + checkPoint('after zoom and pan'); + start(); + }); + viewer.viewport.zoomTo(0.8).panTo(new OpenSeadragon.Point(0.1, 0.2)); }); viewer.open('/test/data/testpattern.dzi'); }); @@ -104,14 +115,13 @@ checkZoom(); var zoomHandler = function() { - viewer.removeHandler('animationfinish', zoomHandler); + viewer.removeHandler('animation-finish', zoomHandler); checkZoom(); start(); }; - viewer.addHandler('animationfinish', zoomHandler); + viewer.addHandler('animation-finish', zoomHandler); viewport.zoomTo(2); - start(); }); viewer.open('/test/data/testpattern.dzi'); From db98e4c34ee19ba83876e98a44c37f9c10773948 Mon Sep 17 00:00:00 2001 From: Antoine Vandecreme Date: Tue, 4 Feb 2014 17:09:12 -0500 Subject: [PATCH 06/13] Add overlays unit tests --- test/overlays.js | 266 +++++++++++++++++++++++++++++++++++++++++++++++ test/test.css | 2 +- test/test.html | 3 +- 3 files changed, 269 insertions(+), 2 deletions(-) create mode 100644 test/overlays.js diff --git a/test/overlays.js b/test/overlays.js new file mode 100644 index 00000000..4f4c0c1f --- /dev/null +++ b/test/overlays.js @@ -0,0 +1,266 @@ +/* global QUnit, module, Util, $, console, test, asyncTest, start, ok, equal */ + +( function() { + var debug = false, + viewer; + + module( "Overlays", { + setup: function() { + var example = $( '
' ).appendTo( "#qunit-fixture" ); + + testLog.reset(); + }, + teardown: function() { + resetTestVariables(); + } + } ); + + var resetTestVariables = function() { + if ( viewer ) { + viewer.close(); + } + }; + + function waitForViewer( handler, count ) { + if ( typeof count !== "number" ) { + count = 0; + } + var ready = viewer.isOpen() && + viewer.drawer !== null && + !viewer.drawer.needsUpdate() && + Util.equalsWithVariance( viewer.viewport.getBounds( true ).x, + viewer.viewport.getBounds().x, 0.000 ) && + Util.equalsWithVariance( viewer.viewport.getBounds( true ).y, + viewer.viewport.getBounds().y, 0.000 ) && + Util.equalsWithVariance( viewer.viewport.getBounds( true ).width, + viewer.viewport.getBounds().width, 0.000 ); + + if ( ready ) { + handler(); + } else if ( count < 50 ) { + count++; + setTimeout( function() { + waitForViewer( handler, count ); + }, 100 ); + } else { + console.log( "waitForViewer:" + viewer.isOpen( ) + ":" + viewer.drawer + + ":" + viewer.drawer.needsUpdate() ); + handler(); + } + } + + asyncTest( 'Overlays via viewer options', function() { + + viewer = OpenSeadragon( { + id: 'example-overlays', + prefixUrl: '/build/openseadragon/images/', + tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ], + springStiffness: 100, // Faster animation = faster tests + overlays: [ { + x: 0.1, + y: 0.4, + width: 0.09, + height: 0.09, + id: "overlay" + } ] + } ); + viewer.addHandler( 'open', openHandler ); + + function openHandler() { + viewer.removeHandler( 'open', openHandler ); + + equal( viewer.overlays.length, 1, "Global overlay not added." ); + equal( viewer.currentOverlays.length, 1, "Global overlay not opened." ); + + viewer.addHandler( 'open', openPageHandler ); + viewer.goToPage( 1 ); + } + + function openPageHandler() { + viewer.removeHandler( 'open', openPageHandler ); + + equal( viewer.overlays.length, 1, "Global overlay removed after page switch." ); + equal( viewer.currentOverlays.length, 1, "Global overlay not re-opened after page switch." ); + + viewer.addHandler( 'close', closeHandler ); + viewer.close(); + } + + function closeHandler() { + viewer.removeHandler( 'close', closeHandler ); + + equal( viewer.overlays.length, 1, "Global overlay removed on close." ); + equal( viewer.currentOverlays.length, 0, "Global overlay not removed on close." ); + + start(); + } + } ); + + asyncTest( 'Overlays via addOverlay ', function() { + + viewer = OpenSeadragon( { + id: 'example-overlays', + prefixUrl: '/build/openseadragon/images/', + tileSources: [ { + Image: { + xmlns: "http://schemas.microsoft.com/deepzoom/2008", + Url: "/test/data/testpattern_files/", + Format: "jpg", + Overlap: "1", + TileSize: "254", + Size: { + Width: 1000, + Height: 1000 + } + }, + overlays: [ { + x: 0.1, + y: 0.4, + width: 0.09, + height: 0.09, + id: "overlay" + } ] + }, { + Image: { + xmlns: "http://schemas.microsoft.com/deepzoom/2008", + Url: "/test/data/testpattern_files/", + Format: "jpg", + Overlap: "1", + TileSize: "254", + Size: { + Width: 1000, + Height: 1000 + } + } + } ], + springStiffness: 100 // Faster animation = faster tests + } ); + viewer.addHandler( 'open', openHandler ); + + function openHandler() { + viewer.removeHandler( 'open', openHandler ); + + equal( viewer.overlays.length, 0, "No global overlay should be added." ); + equal( viewer.currentOverlays.length, 1, "Tile overlay not opened." ); + + viewer.addHandler( 'open', openPageHandler ); + viewer.goToPage( 1 ); + } + + function openPageHandler() { + viewer.removeHandler( 'open', openPageHandler ); + + equal( viewer.overlays.length, 0, "Global overlay added after page switch." ); + equal( viewer.currentOverlays.length, 0, "Tile overlay re-opened after page switch." ); + + viewer.addHandler( 'close', closeHandler ); + viewer.close(); + } + + function closeHandler() { + viewer.removeHandler( 'close', closeHandler ); + + equal( viewer.overlays.length, 0, "Global overlay added on close." ); + equal( viewer.currentOverlays.length, 0, "Tile overlay not removed on close." ); + + start(); + } + } ); + + asyncTest( 'Overlays via addOverlay method', function() { + + viewer = OpenSeadragon( { + id: 'example-overlays', + prefixUrl: '/build/openseadragon/images/', + tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ], + springStiffness: 100 // Faster animation = faster tests + } ); + viewer.addHandler( 'open', openHandler ); + + function openHandler() { + viewer.removeHandler( 'open', openHandler ); + + equal( viewer.overlays.length, 0, "Global overlay added." ); + equal( viewer.currentOverlays.length, 0, "Overlay opened." ); + + var rect = new OpenSeadragon.Rect( 0.1, 0.1, 0.1, 0.1 ); + var overlay = $( "
" ).get( 0 ); + viewer.addOverlay( overlay, rect ); + equal( viewer.overlays.length, 0, "Manual overlay added as global overlay." ); + equal( viewer.currentOverlays.length, 1, "Manual overlay not opened." ); + + viewer.addHandler( 'open', openPageHandler ); + viewer.goToPage( 1 ); + } + + function openPageHandler() { + viewer.removeHandler( 'open', openPageHandler ); + + equal( viewer.overlays.length, 0, "Global overlay added after page switch." ); + equal( viewer.currentOverlays.length, 0, "Manual overlay not removed after page switch." ); + + viewer.addHandler( 'close', closeHandler ); + viewer.close(); + } + + function closeHandler() { + viewer.removeHandler( 'close', closeHandler ); + + equal( viewer.overlays.length, 0, "Global overlay added on close." ); + equal( viewer.currentOverlays.length, 0, "Overlay not removed on close." ); + + start(); + } + + } ); + + asyncTest( 'Overlays size in pixels', function() { + + viewer = OpenSeadragon( { + id: 'example-overlays', + prefixUrl: '/build/openseadragon/images/', + tileSources: [ '/test/data/testpattern.dzi', '/test/data/testpattern.dzi' ], + springStiffness: 100, // Faster animation = faster tests + overlays: [ { + px: 13, + py: 120, + width: 124, + height: 132, + id: "overlay" + } ] + } ); + + function checkOverlayPosition( contextMessage ) { + var viewport = viewer.viewport; + + var expPosition = viewport.imageToViewerElementCoordinates( + new OpenSeadragon.Point( 13, 120 ) ).apply( Math.floor ); + var actPosition = $( "#overlay" ).position(); + equal( actPosition.left, expPosition.x, "X position mismatch " + contextMessage ); + equal( actPosition.top, expPosition.y, "Y position mismatch " + contextMessage ); + + var zoom = viewport.viewportToImageZoom( viewport.getZoom( true ) ); + var expectedWidth = Math.ceil( 124 * zoom ); + var expectedHeight = Math.ceil( 132 * zoom ); + equal( $( "#overlay" ).width(), expectedWidth, "Width mismatch " + contextMessage ); + equal( $( "#overlay" ).height( ), expectedHeight, "Height mismatch " + contextMessage ); + } + + waitForViewer( function() { + checkOverlayPosition( "after opening using image coordinates" ); + + viewer.viewport.zoomBy( 1.1 ).panBy( new OpenSeadragon.Point( 0.1, 0.2 ) ); + waitForViewer( function() { + checkOverlayPosition( "after zoom and pan using image coordinates" ); + + viewer.viewport.goHome(); + waitForViewer( function() { + checkOverlayPosition( "after goHome using image coordinates" ); + start(); + } ); + } ); + + } ); + } ); + +} )(); diff --git a/test/test.css b/test/test.css index 88dca730..9ff8c406 100644 --- a/test/test.css +++ b/test/test.css @@ -18,7 +18,7 @@ width: 300px; } -#unitsexample { +#unitsexample, #example-overlays { height: 500px; width: 500px; } diff --git a/test/test.html b/test/test.html index 0f46fa30..3bef367b 100644 --- a/test/test.html +++ b/test/test.html @@ -14,7 +14,7 @@ - +