UNPKG

photoswipe-deep-zoom-plugin

Version:

A plugin that adds tile-based zoom support to PhotoSwipe. Supports Deepzoom and Zoomify tile formats.

264 lines (220 loc) 7.08 kB
import Tiler from './tiler.js'; import DeepZoomUI from './ui.js'; import { slideIsTiled } from './util.js'; const WHEEL_DEBOUNCE_DELAY = 85; // ms const defaultOptions = { fadeInDuration: 150, tileWidth: 256, tileOverlap: 0, incrementalZoomButtons: true, maxTilePixelRatio: 2, forceWillChange: true, cacheLimit: 200, maxDecodingCount: 15, minBatchRequestCount: 6 }; class PhotoSwipeDeepZoom { constructor(lightbox, options) { lightbox.on('init', () => { this.handlePhotoSwipeOpen(lightbox.pswp, options); }); } handlePhotoSwipeOpen(pswp, options) { this.pswp = pswp; this.options = { ...defaultOptions, ...options }; this.ui = new DeepZoomUI(pswp, this.options); pswp.on('itemData', (e) => { this.parseItemData(e.itemData) }); pswp.on('zoomLevelsUpdate', (e) => { if (e.slideData.tileUrl) { // Custom limit for the max zoom if (e.slideData.maxZoomWidth) { const maxWidth = e.slideData.maxZoomWidth; if (maxWidth) { const newMaxZoomLevel = maxWidth / e.zoomLevels.elementSize.x; e.zoomLevels.max = Math.max( e.zoomLevels.initial, newMaxZoomLevel ); } } // For incremental zoom buttons e.zoomLevels.secondary = e.zoomLevels.max; } }); pswp.on('slideInit', (e) => { if (slideIsTiled(e.slide)) { this._handleTiledSlideInit(e.slide); } }); pswp.on('slideActivate', (e) => { if (slideIsTiled(e.slide)) { this.createTiler(e.slide); } }); pswp.on('slideDeactivate', (e) => { if (slideIsTiled(e.slide)) { this.destroyTiler(e.slide); } }); pswp.on('slideDestroy', (e) => { if (slideIsTiled(e.slide)) { this.destroyTiler(e.slide); } }); pswp.on('appendHeavyContent', (e) => { if (slideIsTiled(e.slide)) { this._appendHeavyContent(e.slide); } }); pswp.on('zoomPanUpdate', (e) => { if (slideIsTiled(e.slide)) { this._handleZoomPanChange(e.slide); } }); pswp.on('imageSizeChange', (e) => { if (slideIsTiled(e.slide)) { this.updateTilerSize(e.slide); } }); pswp.on('change', () => { if (slideIsTiled(pswp.currSlide)) { this.updateTilerSize(pswp.currSlide); } }); pswp.on('loadComplete', (e) => { if (slideIsTiled(e.slide) && e.slide.tiler) { e.slide.tiler.updatePrimaryImageVisibility(); } }); // Block tile loading until wheel acion is finished // (to prevent unnessesary tile reuqests) this._wheelTimeout = undefined; pswp.on('wheel', (e) => { if (slideIsTiled(pswp.currSlide)) { if (pswp.currSlide.tiler) { pswp.currSlide.tiler.blockLoading = true; } if (this._wheelTimeout) { clearTimeout(this._wheelTimeout); } this._wheelTimeout = setTimeout(() => { pswp.currSlide.tiler.blockLoading = false; pswp.currSlide.tiler.updateSize(); this._wheelTimeout = undefined; }, WHEEL_DEBOUNCE_DELAY); } }); } createTiler(slide) { if (!slide.tiler) { slide.tiler = new Tiler(slide, this.options); } } destroyTiler(slide) { if (slide.tiler) { slide.tiler.destroy(); slide.tiler = undefined; if (slide.image) { slide.image.style.display = 'block'; } } } _handleTiledSlideInit(slide) { if (!slide.primaryImageWidth) { slide.primaryImageWidth = slide.width; slide.primaryImageHeight = slide.height; slide.width = slide.data.maxWidth; slide.height = slide.data.maxHeight; } } _appendHeavyContent(slide) { this.createTiler(slide); this.updateTilerSize(slide); } _handleZoomPanChange(slide) { if (slide.isActive && slide.tiler) { this.updateTilerSize(slide); } } updateTilerSize(slide) { const scaleMultiplier = slide.currentResolution || slide.zoomLevels.initial; if (slide.tiler && slide.isActive) { const slideImage = slide.content.element; if (slide.placeholder) { this._setImgStyles(slide.placeholder.element, 5); } const width = Math.round(slide.width * scaleMultiplier); const height = Math.round(slide.height * scaleMultiplier); if (slideImage) { this._setImgStyles(slideImage, 7); if (width >= slide.primaryImageWidth) { if (slideImage.srcset) { // adjust sizes attribute so it's based on primary image size, // and not based on full (tiled) size const prevSizes = parseInt(slideImage.sizes, 10); if (prevSizes >= slide.primaryImageWidth) { slideImage.sizes = slide.primaryImageWidth + 'px'; slideImage.dataset.largestUsedSize = width; } } // scale image instead of changing width/height slideImage.style.width = slide.primaryImageWidth + 'px'; slideImage.style.height = slide.primaryImageHeight + 'px'; const scale = width / slide.primaryImageWidth; slideImage.style.transform = 'scale3d('+scale+','+scale+',1)'; slideImage.style.transformOrigin = '0 0'; } else { slideImage.style.transform = 'none'; } } slide.tiler.setSize(width, height); } else { if (slide.image) { slide.image.style.transform = 'none'; } } } parseItemData(itemData) { const element = itemData.element; if (!element) { return; } const linkEl = element.tagName === 'A' ? element : element.querySelector('a'); if (!linkEl) { return; } if (linkEl.dataset.pswpTileUrl) { itemData.tileUrl = linkEl.dataset.pswpTileUrl; } if (linkEl.dataset.pswpTileType) { itemData.tileType = linkEl.dataset.pswpTileType; } if (linkEl.dataset.pswpTileSize) { itemData.tileSize = parseInt(linkEl.dataset.pswpTileSize, 10); } if (linkEl.dataset.pswpMaxWidth) { itemData.maxWidth = parseInt(linkEl.dataset.pswpMaxWidth, 10); } if (linkEl.dataset.pswpMaxZoomWidth) { itemData.maxZoomWidth = parseInt(linkEl.dataset.pswpMaxZoomWidth, 10); } if (linkEl.dataset.pswpMaxHeight) { itemData.maxHeight = parseInt(linkEl.dataset.pswpMaxHeight, 10); } itemData.tileOverlap = parseInt(linkEl.dataset.pswpTileOverlap, 10) || 0; } _setImgStyles(el, zIndex) { if (el && el.tagName === 'IMG') { el.style.zIndex = zIndex; if (this.options.forceWillChange) { el.style.willChange = 'transform'; } } } } export default PhotoSwipeDeepZoom;