/* * OpenSeadragon - HTMLDrawer * * Copyright (C) 2009 CodePlex Foundation * Copyright (C) 2010-2024 OpenSeadragon contributors * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of CodePlex Foundation nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ (function( $ ){ /** * @class HTMLDrawer * @memberof OpenSeadragon * @classdesc HTML-based implementation of DrawerBase for an {@link OpenSeadragon.Viewer}. * @param {Object} options - Options for this Drawer. * @param {OpenSeadragon.Viewer} options.viewer - The Viewer that owns this Drawer. * @param {OpenSeadragon.Viewport} options.viewport - Reference to Viewer viewport. * @param {Element} options.element - Parent element. * @param {Number} [options.debugGridColor] - See debugGridColor in {@link OpenSeadragon.Options} for details. */ class HTMLDrawer extends $.DrawerBase{ constructor(options){ super(options); // Reject listening for the tile-drawing event, which this drawer does not fire this.viewer.rejectEventHandler("tile-drawing", "The HTMLDrawer does not raise the tile-drawing event"); // Since the tile-drawn event is fired by this drawer, make sure handlers can be added for it this.viewer.allowEventHandler("tile-drawn"); } /** * @returns {Boolean} always true */ static isSupported(){ return true; } getType(){ return 'html'; } /** * @returns {Boolean} Whether this drawer requires enforcing minimum tile overlap to avoid showing seams. */ minimumOverlapRequired() { return true; } /** * create the HTML element (e.g. canvas, div) that the image will be drawn into * @returns {Element} the div to draw into */ _createDrawingElement(){ let canvas = $.makeNeutralElement("div"); return canvas; } /** * Draws the TiledImages */ draw(tiledImages) { var _this = this; this._prepareNewFrame(); // prepare to draw a new frame tiledImages.forEach(function(tiledImage){ if (tiledImage.opacity !== 0 || tiledImage._preload) { _this._drawTiles(tiledImage); } }); } /** * @returns {Boolean} False - rotation is not supported. */ canRotate() { return false; } /** * Destroy the drawer (unload current loaded tiles) */ destroy() { this.canvas.innerHTML = ""; } /** * Turns image smoothing on or off for this viewer. Note: Ignored by HTML Drawer * * @function * @param {Boolean} [imageSmoothingEnabled] - Whether or not the image is * drawn smoothly on the canvas; see imageSmoothingEnabled in * {@link OpenSeadragon.Options} for more explanation. */ setImageSmoothingEnabled(){ // noop - HTML Drawer does not deal with this property } /** * Clears the Drawer so it's ready to draw another frame. * @private * */ _prepareNewFrame() { this.canvas.innerHTML = ""; } /** * Draws a TiledImage. * @private * */ _drawTiles( tiledImage ) { var lastDrawn = tiledImage.getTilesToDraw().map(info => info.tile); if (tiledImage.opacity === 0 || (lastDrawn.length === 0 && !tiledImage.placeholderFillStyle)) { return; } // Iterate over the tiles to draw, and draw them for (var i = lastDrawn.length - 1; i >= 0; i--) { var tile = lastDrawn[ i ]; this._drawTile( tile ); if( this.viewer ){ /** * Raised when a tile is drawn to the canvas. Only valid for * context2d and html drawers. * * @event tile-drawn * @memberof OpenSeadragon.Viewer * @type {object} * @property {OpenSeadragon.Viewer} eventSource - A reference to the Viewer which raised the event. * @property {OpenSeadragon.TiledImage} tiledImage - Which TiledImage is being drawn. * @property {OpenSeadragon.Tile} tile * @property {?Object} userData - Arbitrary subscriber-defined object. */ this.viewer.raiseEvent( 'tile-drawn', { tiledImage: tiledImage, tile: tile }); } } } /** * Draws the given tile. * @private * @param {OpenSeadragon.Tile} tile - The tile to draw. * @param {Function} drawingHandler - Method for firing the drawing event if using canvas. * drawingHandler({context, tile, rendered}) */ _drawTile( tile ) { $.console.assert(tile, '[Drawer._drawTile] tile is required'); let container = this.canvas; if (!tile.cacheImageRecord) { $.console.warn( '[Drawer._drawTileToHTML] attempting to draw tile %s when it\'s not cached', tile.toString()); return; } if ( !tile.loaded ) { $.console.warn( "Attempting to draw tile %s when it's not yet loaded.", tile.toString() ); return; } //EXPERIMENTAL - trying to figure out how to scale the container // content during animation of the container size. if ( !tile.element ) { var image = tile.getImage(); if (!image) { return; } tile.element = $.makeNeutralElement( "div" ); tile.imgElement = image.cloneNode(); tile.imgElement.style.msInterpolationMode = "nearest-neighbor"; tile.imgElement.style.width = "100%"; tile.imgElement.style.height = "100%"; tile.style = tile.element.style; tile.style.position = "absolute"; } if ( tile.element.parentNode !== container ) { container.appendChild( tile.element ); } if ( tile.imgElement.parentNode !== tile.element ) { tile.element.appendChild( tile.imgElement ); } tile.style.top = tile.position.y + "px"; tile.style.left = tile.position.x + "px"; tile.style.height = tile.size.y + "px"; tile.style.width = tile.size.x + "px"; if (tile.flipped) { tile.style.transform = "scaleX(-1)"; } $.setElementOpacity( tile.element, tile.opacity ); } } $.HTMLDrawer = HTMLDrawer; }( OpenSeadragon ));