From 0dd97dbc567c35a857d82c9696f23dcb317c3ae9 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 14 Nov 2014 16:51:02 -0800 Subject: [PATCH 1/8] First version of sequence mode --- src/viewer.js | 21 ++++++++++++++++----- test/demo/collections/main.js | 24 ++++++++++++++---------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 2b2ea1f1..52583764 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -207,6 +207,7 @@ $.Viewer = function( options ) { "onfullscreenchange": null }; + this._firstOpen = true; this._updateRequestId = null; this.currentOverlays = []; @@ -374,7 +375,6 @@ $.Viewer = function( options ) { } this.bindStandardControls(); - this.bindSequenceControls(); THIS[ this.hash ].prevContainerSize = _getSafeElemSize( this.container ); @@ -505,12 +505,21 @@ $.Viewer = function( options ) { }); } + // Sequence mode + if (this.sequenceMode) { + THIS[ this.hash ].sequenced = true; + this.initialPage = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); + THIS[ this.hash ].sequence = this.initialPage; + this.bindSequenceControls(); + } + // Open initial tilesources if ( this.tileSources ) { - this.open( this.tileSources ); - - if ( this.tileSources.length > 1 ) { + if (this.sequenceMode) { + this.open(this.tileSources[this.initialPage]); this._updateSequenceButtons( this.initialPage ); + } else { + this.open( this.tileSources ); } } @@ -589,10 +598,12 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, var checkCompletion = function() { if (successes + failures === expected) { if (successes) { - if (!_this.preserveViewport) { + if (_this._firstOpen || !_this.preserveViewport) { _this.viewport.goHome( true ); } + _this._firstOpen = false; + var source = tileSources[0]; if (source.tileSource) { source = source.tileSource; diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index 426015b2..f026453e 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -6,7 +6,7 @@ init: function() { var self = this; - var testInitialOpen = false; + var testInitialOpen = true; var testOverlays = false; var testMargins = false; var testNavigator = false; @@ -16,9 +16,12 @@ // debugMode: true, zoomPerScroll: 1.02, showNavigator: testNavigator, - collectionMode: true, - collectionRows: 3, - collectionLayout: 'vertical', + sequenceMode: true, + navPrevNextWrap: false, + preserveViewport: false, + // collectionMode: true, + // collectionRows: 3, + // collectionLayout: 'vertical', // collectionTileSize: 10, // collectionTileMargin: 10, // wrapHorizontal: true, @@ -29,12 +32,13 @@ if (testInitialOpen) { config.tileSources = [ + // { + // tileSource: "../../data/tall.dzi", + // x: 1.5, + // y: 0, + // width: 1 + // }, { - tileSource: "../../data/tall.dzi", - x: 1.5, - y: 0, - width: 1 - }, { tileSource: '../../data/wide.dzi', opacity: 1, x: 0, @@ -101,7 +105,7 @@ } // this.crossTest3(); - this.collectionTest(); + // this.collectionTest(); }, // ---------- From 1279c6766cd0404b5362af6fad864c96a2f00be5 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Fri, 14 Nov 2014 17:19:04 -0800 Subject: [PATCH 2/8] More sequence mode work --- src/viewer.js | 35 +++++++++++++++++++---------------- test/demo/collections/main.js | 12 ++++++------ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/viewer.js b/src/viewer.js index 52583764..fa0afea7 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -200,13 +200,11 @@ $.Viewer = function( options ) { // how much we should be continuously zooming by "zoomFactor": null, "lastZoomTime": null, - // did we decide this viewer has a sequence of tile sources - "sequenced": false, - "sequence": 0, "fullPage": false, "onfullscreenchange": null }; + this._sequenceIndex = 0; this._firstOpen = true; this._updateRequestId = null; this.currentOverlays = []; @@ -507,17 +505,18 @@ $.Viewer = function( options ) { // Sequence mode if (this.sequenceMode) { - THIS[ this.hash ].sequenced = true; - this.initialPage = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); - THIS[ this.hash ].sequence = this.initialPage; + if (this.tileSources && this.tileSources.length) { + this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); + } + this.bindSequenceControls(); } // Open initial tilesources - if ( this.tileSources ) { + if ( this.tileSources && this.tileSources.length) { if (this.sequenceMode) { - this.open(this.tileSources[this.initialPage]); - this._updateSequenceButtons( this.initialPage ); + this.open(this.tileSources[this._sequenceIndex]); + this._updateSequenceButtons( this._sequenceIndex ); } else { this.open( this.tileSources ); } @@ -1422,7 +1421,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, navImages = this.navImages, useGroup = true ; - if( this.showSequenceControl && THIS[ this.hash ].sequenced ){ + if( this.showSequenceControl ){ if( this.previousButton || this.nextButton ){ //if we are binding to custom buttons then layout and @@ -1462,6 +1461,10 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, this.previousButton.disable(); } + if (!this.tileSources || !this.tileSources.length) { + this.nextButton.disable(); + } + if( useGroup ){ this.paging = new $.ButtonGroup({ buttons: [ @@ -1659,7 +1662,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * @return {Number} */ currentPage: function() { - return THIS[ this.hash ].sequence; + return this._sequenceIndex; }, /** @@ -1668,7 +1671,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, * @fires OpenSeadragon.Viewer.event:page */ goToPage: function( page ){ - if( page >= 0 && page < this.tileSources.length ){ + if( this.tileSources && page >= 0 && page < this.tileSources.length ){ /** * Raised when the page is changed on a viewer configured with multiple image sources (see {@link OpenSeadragon.Viewer#goToPage}). * @@ -1681,7 +1684,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, */ this.raiseEvent( 'page', { page: page } ); - THIS[ this.hash ].sequence = page; + this._sequenceIndex = page; this._updateSequenceButtons( page ); @@ -1871,7 +1874,7 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, _updateSequenceButtons: function( page ) { if ( this.nextButton ) { - if( ( this.tileSources.length - 1 ) === page ) { + if(!this.tileSources || this.tileSources.length - 1 === page) { //Disable next button if ( !this.navPrevNextWrap ) { this.nextButton.disable(); @@ -2856,7 +2859,7 @@ function onRotateRight() { function onPrevious(){ - var previous = THIS[ this.hash ].sequence - 1; + var previous = this._sequenceIndex - 1; if(this.navPrevNextWrap && previous < 0){ previous += this.tileSources.length; } @@ -2865,7 +2868,7 @@ function onPrevious(){ function onNext(){ - var next = THIS[ this.hash ].sequence + 1; + var next = this._sequenceIndex + 1; if(this.navPrevNextWrap && next >= this.tileSources.length){ next = 0; } diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index f026453e..cb34e807 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -32,12 +32,12 @@ if (testInitialOpen) { config.tileSources = [ - // { - // tileSource: "../../data/tall.dzi", - // x: 1.5, - // y: 0, - // width: 1 - // }, + { + tileSource: "../../data/tall.dzi", + x: 1.5, + y: 0, + width: 1 + }, { tileSource: '../../data/wide.dzi', opacity: 1, From f018059b600b686804a1cb4c2f41e68f4a446e5b Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 17 Nov 2014 11:50:20 -0800 Subject: [PATCH 3/8] Docs for sequence mode --- changelog.txt | 1 + src/openseadragon.js | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/changelog.txt b/changelog.txt index 8b7a991c..4b4eb7d2 100644 --- a/changelog.txt +++ b/changelog.txt @@ -4,6 +4,7 @@ OPENSEADRAGON CHANGELOG 2.0.0: (in progress) * True multi-image mode (#450) + * BREAKING CHANGE: Passing an array for the tileSources option is no longer enough to trigger sequence mode; you have to set the sequenceMode option to true as well * BREAKING CHANGE: Navigator no longer sends an open event when its viewer opens * BREAKING CHANGE: Viewer.drawers and Viewer.drawersContainer no longer exist * BREAKING CHANGE: A Viewer's Drawer and Viewport are now made once per Viewer and reused for every image that Viewer opens (rather than being recreated for every open); this means if you change Viewer options between opens, the behavior is different now. diff --git a/src/openseadragon.js b/src/openseadragon.js index 70aeca84..5a40c560 100644 --- a/src/openseadragon.js +++ b/src/openseadragon.js @@ -446,8 +446,8 @@ * this setting when set to false. * * @property {Boolean} [showSequenceControl=true] - * If the viewer has been configured with a sequence of tile sources, then - * provide buttons for navigating forward and backward through the images. + * If sequenceMode is true, then provide buttons for navigating forward and + * backward through the images. * * @property {OpenSeadragon.ControlAnchor} [sequenceControlAnchor=TOP_LEFT] * Placement of the default sequence controls. @@ -505,18 +505,21 @@ * To only change the button images, consider using * {@link OpenSeadragon.Options.navImages} * + * @property {Boolean} [sequenceMode=false] + * Set to true to have the viewer treat your tilesources as a sequence of images to + * be opened one at a time rather than all at once. + * * @property {Number} [initialPage=0] - * If the viewer has been configured with a sequence of tile sources, display this page initially. + * If sequenceMode is true, display this page initially. * * @property {Boolean} [preserveViewport=false] - * If the viewer has been configured with a sequence of tile sources, then - * normally navigating to through each image resets the viewport to 'home' - * position. If preserveViewport is set to true, then the viewport position - * is preserved when navigating between images in the sequence. + * If sequenceMode is true, then normally navigating to through each image resets the + * viewport to 'home' position. If preserveViewport is set to true, then the viewport + * position is preserved when navigating between images in the sequence. * * @property {Boolean} [showReferenceStrip=false] - * If the viewer has been configured with a sequence of tile sources, then - * display a scrolling strip of image thumbnails for navigating through the images. + * If sequenceMode is true, then display a scrolling strip of image thumbnails for + * navigating through the images. * * @property {String} [referenceStripScroll='horizontal'] * From 336482cd1c2bb18bfadc36aec1dc8a0351b82ed3 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 17 Nov 2014 12:57:49 -0800 Subject: [PATCH 4/8] Viewer.open now honors sequence mode --- src/viewer.js | 11 +++++++++++ test/demo/collections/main.js | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/viewer.js b/src/viewer.js index fa0afea7..32c7acb5 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -581,6 +581,17 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, return; } + if (this.sequenceMode && $.isArray(tileSources)) { + this.tileSources = tileSources; + this._sequenceIndex = 0; + if (tileSources.length) { + this.open(tileSources[0]); + } + + this._updateSequenceButtons( this._sequenceIndex ); + return; + } + if (!$.isArray(tileSources)) { tileSources = [tileSources]; } diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index cb34e807..915583fd 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -104,7 +104,7 @@ }); } - // this.crossTest3(); + // this.crossTest2(); // this.collectionTest(); }, From 4bd4dd561864fe49938998bbbbb2974d99d42b90 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 17 Nov 2014 13:17:24 -0800 Subject: [PATCH 5/8] Reference strip testing --- test/demo/collections/main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index 915583fd..fe4efe1a 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -17,6 +17,8 @@ zoomPerScroll: 1.02, showNavigator: testNavigator, sequenceMode: true, + showReferenceStrip: true, + // referenceStripScroll: 'vertical', navPrevNextWrap: false, preserveViewport: false, // collectionMode: true, From 0e31b67ca5b427480a37673b9c694428f25f9e6d Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 17 Nov 2014 14:03:14 -0800 Subject: [PATCH 6/8] ReferenceStrip fixes --- src/referencestrip.js | 11 +++++-- src/viewer.js | 58 +++++++++++++++++------------------ test/demo/collections/main.js | 7 +++-- 3 files changed, 42 insertions(+), 34 deletions(-) diff --git a/src/referencestrip.js b/src/referencestrip.js index f68744b2..0c0fdf61 100644 --- a/src/referencestrip.js +++ b/src/referencestrip.js @@ -289,6 +289,13 @@ $.extend( $.ReferenceStrip.prototype, $.EventSource.prototype, $.Viewer.prototyp return true; } return false; + }, + + // Overrides Viewer.destroy + destroy: function() { + if (this.element) { + this.element.parentNode.removeChild(this.element); + } } } ); @@ -467,7 +474,7 @@ function loadPanels( strip, viewerSize, scroll ) { */ function onStripEnter( event ) { var element = event.eventSource.element; - + //$.setElementOpacity(element, 0.8); //element.style.border = '1px solid #555'; @@ -495,7 +502,7 @@ function onStripEnter( event ) { */ function onStripExit( event ) { var element = event.eventSource.element; - + if ( 'horizontal' == this.scroll ) { //element.style.paddingTop = "10px"; diff --git a/src/viewer.js b/src/viewer.js index 32c7acb5..e5269a8b 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -487,39 +487,14 @@ $.Viewer = function( options ) { }); } - //Instantiate a referencestrip if configured - if ( this.showReferenceStrip ){ - this.referenceStrip = new $.ReferenceStrip({ - id: this.referenceStripElement, - position: this.referenceStripPosition, - sizeRatio: this.referenceStripSizeRatio, - scroll: this.referenceStripScroll, - height: this.referenceStripHeight, - width: this.referenceStripWidth, - tileSources: this.tileSources, - tileHost: this.tileHost, - prefixUrl: this.prefixUrl, - viewer: this - }); - } - // Sequence mode if (this.sequenceMode) { - if (this.tileSources && this.tileSources.length) { - this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); - } - this.bindSequenceControls(); } // Open initial tilesources if ( this.tileSources && this.tileSources.length) { - if (this.sequenceMode) { - this.open(this.tileSources[this._sequenceIndex]); - this._updateSequenceButtons( this._sequenceIndex ); - } else { - this.open( this.tileSources ); - } + this.open( this.tileSources ); } // Add custom controls @@ -582,10 +557,30 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, } if (this.sequenceMode && $.isArray(tileSources)) { + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + this.tileSources = tileSources; - this._sequenceIndex = 0; - if (tileSources.length) { - this.open(tileSources[0]); + this._sequenceIndex = Math.max(0, Math.min(this.tileSources.length - 1, this.initialPage)); + if (this.tileSources.length) { + this.open(this.tileSources[this._sequenceIndex]); + + if ( this.showReferenceStrip ){ + this.referenceStrip = new $.ReferenceStrip({ + id: this.referenceStripElement, + position: this.referenceStripPosition, + sizeRatio: this.referenceStripSizeRatio, + scroll: this.referenceStripScroll, + height: this.referenceStripHeight, + width: this.referenceStripWidth, + tileSources: this.tileSources, + tileHost: this.tileHost, + prefixUrl: this.prefixUrl, + viewer: this + }); + } } this._updateSequenceButtons( this._sequenceIndex ); @@ -772,6 +767,11 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, //this.unbindSequenceControls() //this.unbindStandardControls() + if (this.referenceStrip) { + this.referenceStrip.destroy(); + this.referenceStrip = null; + } + if ( this._updateRequestId !== null ) { $.cancelAnimationFrame( this._updateRequestId ); this._updateRequestId = null; diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index fe4efe1a..d1f9c652 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -6,7 +6,7 @@ init: function() { var self = this; - var testInitialOpen = true; + var testInitialOpen = false; var testOverlays = false; var testMargins = false; var testNavigator = false; @@ -106,8 +106,9 @@ }); } - // this.crossTest2(); - // this.collectionTest(); + if (!testInitialOpen) { + this.collectionTest(); + } }, // ---------- From b149b39b061c1da02515e366525e0bdb00904567 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 17 Nov 2014 14:06:10 -0800 Subject: [PATCH 7/8] Reinstating sequence control tests --- test/controls.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/controls.js b/test/controls.js index f0f008fe..640b2402 100644 --- a/test/controls.js +++ b/test/controls.js @@ -278,10 +278,6 @@ asyncTest('SequenceControlOnPrevNextWrapOff', function () { - expect(0); - start(); - return; // Temporarily disabling - var openHandler = function () { viewer.removeHandler('open', openHandler); ok(viewer.showSequenceControl, 'showSequenceControl should be on'); @@ -333,6 +329,7 @@ ], springStiffness: 100, // Faster animation = faster tests showSequenceControl: true, + sequenceMode: true, navPrevNextWrap: false }); viewer.addHandler('open', openHandler); @@ -340,10 +337,6 @@ asyncTest('SequenceControlOnPrevNextWrapOn', function () { - expect(0); - start(); - return; // Temporarily disabling - var openHandler = function () { viewer.removeHandler('open', openHandler); ok(viewer.showSequenceControl, 'showSequenceControl should be on'); @@ -388,6 +381,7 @@ ], springStiffness: 100, // Faster animation = faster tests showSequenceControl: true, + sequenceMode: true, navPrevNextWrap: true }); viewer.addHandler('open', openHandler); From 643332902dbd296dbc089c124397ce68c1ac06a6 Mon Sep 17 00:00:00 2001 From: Ian Gilman Date: Mon, 17 Nov 2014 16:24:40 -0800 Subject: [PATCH 8/8] Unit tests for World --- changelog.txt | 1 + src/point.js | 2 +- src/rectangle.js | 8 +- src/world.js | 3 +- test/test.html | 1 + test/world.js | 226 +++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 235 insertions(+), 6 deletions(-) create mode 100644 test/world.js diff --git a/changelog.txt b/changelog.txt index 4b4eb7d2..547646c4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -36,6 +36,7 @@ OPENSEADRAGON CHANGELOG * New Viewport method for managing homeBounds as well as constraints: setHomeBounds * Viewport.open supports positioning config properties * Margins option to push the home region in from the edges of the Viewer (#505) +* Rect and Point toString() functions are now consistent: rounding values to nearest hundredth 1.2.0: (in progress) diff --git a/src/point.js b/src/point.js index 0004426b..1ceef296 100644 --- a/src/point.js +++ b/src/point.js @@ -196,7 +196,7 @@ $.Point.prototype = /** @lends OpenSeadragon.Point.prototype */{ * @returns {String} A string representation of this point. */ toString: function() { - return "(" + Math.round(this.x) + "," + Math.round(this.y) + ")"; + return "(" + (Math.round(this.x * 100) / 100) + "," + (Math.round(this.y * 100) / 100) + ")"; } }; diff --git a/src/rectangle.js b/src/rectangle.js index 217b5126..6c8c9243 100644 --- a/src/rectangle.js +++ b/src/rectangle.js @@ -264,10 +264,10 @@ $.Rect.prototype = /** @lends OpenSeadragon.Rect.prototype */{ */ toString: function() { return "[" + - Math.round(this.x*100) + "," + - Math.round(this.y*100) + "," + - Math.round(this.width*100) + "x" + - Math.round(this.height*100) + + (Math.round(this.x*100) / 100) + "," + + (Math.round(this.y*100) / 100) + "," + + (Math.round(this.width*100) / 100) + "x" + + (Math.round(this.height*100) / 100) + "]"; } }; diff --git a/src/world.js b/src/world.js index 9dc47b45..2c7a3f7f 100644 --- a/src/world.js +++ b/src/world.js @@ -324,6 +324,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W if ( !this._items.length ) { this._homeBounds = new $.Rect(0, 0, 1, 1); this._contentSize = new $.Point(1, 1); + this._contentFactor = 1; } else { var bounds = this._items[0].getBounds(); this._contentFactor = this._items[0].getContentSize().x / bounds.width; @@ -349,7 +350,7 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W if (this._contentFactor !== oldContentFactor || !this._homeBounds.equals(oldHomeBounds) || !this._contentSize.equals(oldContentSize)) { /** - * Raised when the home bounds, content size, or content factor change. + * Raised when the home bounds or content factor change. * @event metrics-change * @memberOf OpenSeadragon.World * @type {object} diff --git a/test/test.html b/test/test.html index 88a04135..54b5de05 100644 --- a/test/test.html +++ b/test/test.html @@ -31,6 +31,7 @@ + diff --git a/test/world.js b/test/world.js new file mode 100644 index 00000000..634165d8 --- /dev/null +++ b/test/world.js @@ -0,0 +1,226 @@ +/* global module, asyncTest, $, ok, equal, notEqual, start, test, Util, testLog */ + +(function() { + var viewer; + + module('World', { + setup: function () { + var example = $('
').appendTo("#qunit-fixture"); + + testLog.reset(); + + viewer = OpenSeadragon({ + id: 'example', + prefixUrl: '/build/openseadragon/images/', + springStiffness: 100 // Faster animation = faster tests + }); + }, + teardown: function () { + if (viewer && viewer.close) { + viewer.close(); + } + + viewer = null; + } + }); + + // ---------- + var checkBounds = function(expected, message) { + var bounds = viewer.world.getHomeBounds(); + ok(bounds.equals(expected), message + ' ' + bounds.toString()); + }; + + // ---------- + asyncTest('adding a tiled image', function() { + ok(viewer.world, 'World exists'); + + viewer.world.addHandler('add-item', function(event) { + ok(event, 'add-item handler received event data'); + equal(event.eventSource, viewer.world, 'sender of add-item event was world'); + ok(event.item, 'add-item event includes item'); + equal(viewer.world.getItemCount(), 1, 'there is now 1 item'); + equal(event.item, viewer.world.getItemAt(0), 'item is accessible via getItemAt'); + equal(viewer.world.getIndexOfItem(event.item), 0, 'item index is 0'); + start(); + }); + + equal(viewer.world.getItemCount(), 0, 'no items to start with'); + + viewer.open('/test/data/testpattern.dzi'); + }); + + // ---------- + asyncTest('metrics', function() { + viewer.addHandler('open', function(event) { + checkBounds(new OpenSeadragon.Rect(0, 0, 4, 4), 'bounds after open'); + + var expectedContentFactor = viewer.world.getItemAt(1).getContentSize().x / 2; + equal(viewer.world.getContentFactor(), expectedContentFactor, 'content factor has changed'); + + viewer.world.addHandler('metrics-change', function metricsChangeHandler(event) { + viewer.world.removeHandler('metrics-change', metricsChangeHandler); + ok(event, 'metrics-change handler received event data'); + equal(event.eventSource, viewer.world, 'sender of metrics-change event was world'); + checkBounds(new OpenSeadragon.Rect(0, 0, 7, 12), 'bounds after position'); + viewer.world.getItemAt(0).setWidth(20); + checkBounds(new OpenSeadragon.Rect(0, 0, 20, 20), 'bounds after size'); + + start(); + }); + + viewer.world.getItemAt(1).setPosition(new OpenSeadragon.Point(5, 10)); + }); + + checkBounds(new OpenSeadragon.Rect(0, 0, 1, 1), 'default bounds'); + equal(viewer.world.getContentFactor(), 1, 'default content factor'); + + viewer.open([ + { + tileSource: '/test/data/testpattern.dzi', + width: 4 + }, { + tileSource: '/test/data/testpattern.dzi', + width: 2 + } + ]); + }); + + // ---------- + asyncTest('remove/reorder tiled images', function() { + var handlerCount = 0; + + viewer.addHandler('open', function(event) { + equal(viewer.world.getItemCount(), 3, 'there are now 3 items'); + var item0 = viewer.world.getItemAt(0); + var item1 = viewer.world.getItemAt(1); + + viewer.world.addHandler('item-index-change', function(event) { + handlerCount++; + ok(event, 'item-index-change handler received event data'); + equal(event.eventSource, viewer.world, 'sender of item-index-change event was world'); + equal(event.item, item0, 'item-index-change event includes correct item'); + equal(event.newIndex, 1, 'item-index-change event includes correct newIndex'); + equal(event.previousIndex, 0, 'item-index-change event includes correct previousIndex'); + equal(viewer.world.getItemAt(0), item1, 'item1 is now at index 0'); + equal(viewer.world.getItemAt(1), item0, 'item0 is now at index 1'); + }); + + viewer.world.setItemIndex(item0, 1); + + viewer.world.addHandler('remove-item', function removeHandler(event) { + viewer.world.removeHandler('remove-item', removeHandler); + handlerCount++; + ok(event, 'remove-item handler received event data'); + equal(event.eventSource, viewer.world, 'sender of remove-item event was world'); + equal(event.item, item1, 'remove-item event includes correct item'); + equal(viewer.world.getItemCount(), 2, 'after removal, only two items remain'); + equal(viewer.world.getItemAt(0), item0, 'item0 is now at index 0'); + }); + + viewer.world.removeItem(item1); + + var removeCount = 0; + viewer.world.addHandler('remove-item', function() { + removeCount++; + if (removeCount === 2) { + handlerCount++; + equal(viewer.world.getItemCount(), 0, 'after removeAll, no items remain'); + } + }); + + viewer.world.removeAll(); + + equal(handlerCount, 3, 'correct number of handlers called'); + start(); + }); + + equal(viewer.world.getItemCount(), 0, 'no items to start with'); + + viewer.open([ + '/test/data/testpattern.dzi', + '/test/data/testpattern.dzi', + '/test/data/testpattern.dzi' + ]); + }); + + // ---------- + asyncTest('update', function() { + var handlerCount = 0; + + viewer.addHandler('open', function(event) { + equal(viewer.world.needsUpdate(), true, 'needs update after open'); + + viewer.addHandler('update-level', function updateHandler() { + viewer.removeHandler('update-level', updateHandler); + handlerCount++; + }); + + viewer.world.update(); + + equal(handlerCount, 1, 'correct number of handlers called'); + start(); + }); + + equal(viewer.world.needsUpdate(), false, 'needs no update at first'); + + viewer.open('/test/data/testpattern.dzi'); + }); + + // ---------- + asyncTest('resetItems', function() { + viewer.addHandler('tile-drawn', function updateHandler() { + viewer.removeHandler('tile-drawn', updateHandler); + ok(viewer.tileCache.numTilesLoaded() > 0, 'we have tiles after tile-drawn'); + viewer.world.resetItems(); + equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles after reset'); + start(); + }); + + equal(viewer.tileCache.numTilesLoaded(), 0, 'no tiles at start'); + + viewer.open('/test/data/testpattern.dzi'); + }); + + // ---------- + asyncTest('arrange', function() { + viewer.addHandler('open', function(event) { + checkBounds(new OpenSeadragon.Rect(0, 0, 1, 1), 'all stacked'); + + viewer.world.arrange({ + layout: 'horizontal', + rows: 1, + tileSize: 1, + tileMargin: 0.5 + }); + + checkBounds(new OpenSeadragon.Rect(0, 0, 4, 1), 'one horizontal row'); + + viewer.world.arrange({ + layout: 'horizontal', + rows: 2, + tileSize: 1, + tileMargin: 0.5 + }); + + checkBounds(new OpenSeadragon.Rect(0, 0, 2.5, 2.5), 'grid'); + + viewer.world.arrange({ + layout: 'vertical', + rows: 1, + tileSize: 1, + tileMargin: 0.5 + }); + + checkBounds(new OpenSeadragon.Rect(0, 0, 1, 4), 'one vertical column'); + + start(); + }); + + viewer.open([ + '/test/data/testpattern.dzi', + '/test/data/testpattern.dzi', + '/test/data/testpattern.dzi' + ]); + }); + +})();