diff --git a/src/tiledimage.js b/src/tiledimage.js index cfe4a0b3..cf55f40c 100644 --- a/src/tiledimage.js +++ b/src/tiledimage.js @@ -39,6 +39,7 @@ * or {@link OpenSeadragon.Viewer#addTiledImage} instead. * @class TiledImage * @memberof OpenSeadragon + * @extends OpenSeadragon.EventSource * @classdesc Handles rendering of tiles for an {@link OpenSeadragon.Viewer}. * A new instance is created for each TileSource opened. * @param {Object} options - Configuration for this TiledImage. @@ -68,6 +69,8 @@ $.TiledImage = function( options ) { $.console.assert( options.imageLoader, "[TiledImage] options.imageLoader is required" ); $.console.assert( options.source, "[TiledImage] options.source is required" ); + $.EventSource.call( this ); + this._tileCache = options.tileCache; delete options.tileCache; @@ -128,7 +131,7 @@ $.TiledImage = function( options ) { }, options ); }; -$.TiledImage.prototype = /** @lends OpenSeadragon.TiledImage.prototype */{ +$.extend($.TiledImage.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.TiledImage.prototype */{ /** * @returns {Boolean} Whether the TiledImage is scheduled for an update at the * soonest possible opportunity. @@ -175,8 +178,30 @@ $.TiledImage.prototype = /** @lends OpenSeadragon.TiledImage.prototype */{ */ getContentSize: function() { return new $.Point(this.source.dimensions.x, this.source.dimensions.y); + }, + + /** + * @fires OpenSeadragon.TiledImage.event:bounds-changed + */ + setPosition: function(position) { + this._worldX = position.x; + this._worldY = position.y; + this.updateAgain = true; + this._raiseBoundsChanged(); + }, + + _raiseBoundsChanged: function() { + /** + * Raised when the TiledImage's bounds are changed. + * @event bounds-changed + * @memberOf OpenSeadragon.TiledImage + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the TiledImage which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('bounds-changed'); } -}; +}); /** * @private @@ -794,8 +819,7 @@ function drawTiles( tiledImage, lastDrawn ){ viewer, viewport, position, - tileSource, - collectionTileSource; + tileSource; // We need a callback to give image manipulation a chance to happen var drawingHandler = function(args) { diff --git a/src/viewer.js b/src/viewer.js index 727cbf9d..8a801cc0 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -384,10 +384,6 @@ $.Viewer = function( options ) { }); this.world.addHandler('add-item', function(event) { - if (_this.viewport) { - _this.viewport.setHomeBounds(_this.world.getHomeBounds(), _this.world.getContentFactor()); - } - // For backwards compatibility, we maintain the source property _this.source = _this.world.getItemAt(0).source; @@ -399,10 +395,6 @@ $.Viewer = function( options ) { }); this.world.addHandler('remove-item', function(event) { - if (_this.viewport) { - _this.viewport.setHomeBounds(_this.world.getHomeBounds(), _this.world.getContentFactor()); - } - // For backwards compatibility, we maintain the source property if (_this.world.getItemCount()) { _this.source = _this.world.getItemAt(0).source; @@ -413,6 +405,12 @@ $.Viewer = function( options ) { THIS[ _this.hash ].forceRedraw = true; }); + this.world.addHandler('home-bounds-changed', function(event) { + if (_this.viewport) { + _this.viewport.setHomeBounds(_this.world.getHomeBounds(), _this.world.getContentFactor()); + } + }); + this.world.addHandler('item-index-changed', function(event) { // For backwards compatibility, we maintain the source property _this.source = _this.world.getItemAt(0).source; @@ -1301,6 +1299,15 @@ $.extend( $.Viewer.prototype, $.EventSource.prototype, $.ControlDock.prototype, index: options.index }); + if (_this.collectionMode) { + _this.world.layout({ + rows: _this.collectionRows, + layout: _this.collectionLayout, + tileSize: _this.collectionTileSize, + tileMargin: _this.collectionTileMargin + }); + } + if (_this.world.getItemCount() === 1 && !_this.preserveViewport) { _this.viewport.goHome(true); } diff --git a/src/world.js b/src/world.js index 3e4d3924..94045a49 100644 --- a/src/world.js +++ b/src/world.js @@ -61,6 +61,8 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W * @fires OpenSeadragon.World.event:add-item */ addItem: function( item, options ) { + var _this = this; + $.console.assert(item, "[World.addItem] item is required"); $.console.assert(item instanceof $.TiledImage, "[World.addItem] only TiledImages supported at this time"); @@ -75,6 +77,11 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W this._figureSizes(); this._needsUpdate = true; + // TODO: remove handler when removing item from world + item.addHandler('bounds-changed', function(event) { + _this._figureSizes(); + }); + /** * Raised when an item is added to the World. * @event add-item @@ -242,39 +249,79 @@ $.extend( $.World.prototype, $.EventSource.prototype, /** @lends OpenSeadragon.W return this._contentFactor; }, + layout: function(config) { + var layout = config.layout || $.DEFAULT_SETTINGS.collectionLayout; + var rows = config.rows || $.DEFAULT_SETTINGS.collectionRows; + var wrap = Math.ceil(this._items.length / rows); + var x = 0; + var y = 0; + for (var i = 0; i < this._items.length; i++) { + if (i && (i % wrap) === 0) { + if (layout === 'horizontal') { + y += 1; + x = 0; + } else { + x += 1; + y = 0; + } + } + + this._items[i].setPosition(new $.Point(x, y)); + + if (layout === 'horizontal') { + x += 1; + } else { + y += 1; + } + } + }, + // private _figureSizes: function() { + var oldHomeBounds = this._homeBounds ? this._homeBounds.clone() : null; + if ( !this._items.length ) { this._homeBounds = new $.Rect(0, 0, 1, 1); this._contentSize = new $.Point(1, 1); - return; + } else { + var bounds = this._items[0].getWorldBounds(); + this._contentFactor = this._items[0].getContentSize().x / bounds.width; + var left = bounds.x; + var top = bounds.y; + var right = bounds.x + bounds.width; + var bottom = bounds.y + bounds.height; + var box; + for ( var i = 1; i < this._items.length; i++ ) { + box = this._items[i].getWorldBounds(); + this._contentFactor = Math.max(this._contentFactor, this._items[i].getContentSize().x / box.width); + left = Math.min( left, box.x ); + top = Math.min( top, box.y ); + right = Math.max( right, box.x + box.width ); + bottom = Math.max( bottom, box.y + box.height ); + } + + this._homeBounds = new $.Rect( left, top, right - left, bottom - top ); + this._contentSize = new $.Point(this._homeBounds.width * this._contentFactor, + this._homeBounds.height * this._contentFactor); } - var bounds = this._items[0].getWorldBounds(); - this._contentFactor = this._items[0].getContentSize().x / bounds.width; - var left = bounds.x; - var top = bounds.y; - var right = bounds.x + bounds.width; - var bottom = bounds.y + bounds.height; - var box; - for ( var i = 1; i < this._items.length; i++ ) { - box = this._items[i].getWorldBounds(); - this._contentFactor = Math.max(this._contentFactor, this._items[i].getContentSize().x / box.width); - left = Math.min( left, box.x ); - top = Math.min( top, box.y ); - right = Math.max( right, box.x + box.width ); - bottom = Math.max( bottom, box.y + box.height ); + if (!this._homeBounds.equals(oldHomeBounds)) { + /** + * Raised when the home bounds change. + * @event home-bounds-changed + * @memberOf OpenSeadragon.World + * @type {object} + * @property {OpenSeadragon.World} eventSource - A reference to the World which raised the event. + * @property {?Object} userData - Arbitrary subscriber-defined object. + */ + this.raiseEvent('home-bounds-changed'); } - - this._homeBounds = new $.Rect( left, top, right - left, bottom - top ); - this._contentSize = new $.Point(this._homeBounds.width * this._contentFactor, - this._homeBounds.height * this._contentFactor); }, // private _raiseRemoveItem: function(item) { /** - * Raised when a item is removed. + * Raised when an item is removed. * @event remove-item * @memberOf OpenSeadragon.World * @type {object} diff --git a/test/demo/collections/main.js b/test/demo/collections/main.js index 927b777f..7ca4d8b0 100644 --- a/test/demo/collections/main.js +++ b/test/demo/collections/main.js @@ -16,6 +16,9 @@ // debugMode: true, zoomPerScroll: 1.02, showNavigator: testNavigator, + collectionMode: true, + collectionRows: 3, + collectionLayout: 'vertical', // wrapHorizontal: true, // wrapVertical: true, id: "contentDiv", @@ -96,7 +99,7 @@ } // this.crossTest3(); - this.basicTest(); + this.collectionTest(); }, // ---------- @@ -189,6 +192,16 @@ }); }, + // ---------- + collectionTest: function() { + var tileSources = []; + for (var i = 0; i < 10; i++) { + tileSources.push('../../data/testpattern.dzi'); + } + + this.viewer.open(tileSources); + }, + // ---------- gridTest: function() { var self = this;