photoswipe-deep-zoom-plugin
Version:
A plugin that adds tile-based zoom support to PhotoSwipe. Supports Deepzoom and Zoomify tile formats.
250 lines (220 loc) • 7.41 kB
JavaScript
import { slideIsTiled } from "./util.js";
class DeepZoomUI {
constructor(pswp, options) {
this.pswp = pswp;
this.options = options;
pswp.on('uiRegister', () => {
if (options.incrementalZoomButtons) {
this.addButtons();
}
});
pswp.on('imageClickAction', (e) => {
if (slideIsTiled(pswp.currSlide)) {
e.preventDefault();
this.incrementalZoomIn(e.point);
}
});
pswp.on('doubleTapAction', (e) => {
if (slideIsTiled(pswp.currSlide)) {
e.preventDefault();
this.incrementalZoomIn(e.point);
}
});
pswp.on('keydown', (e) => {
const origEvent = e.originalEvent;
let action;
if (origEvent.keyCode === 187) { // = (+)
action = 'ZoomIn';
} else if (origEvent.keyCode === 189) { // -
action = 'ZoomOut';
}
if (action && !origEvent.metaKey && !origEvent.altKey && !origEvent.ctrlKey) {
e.preventDefault();
origEvent.preventDefault();
this['incremental' + action](false);
}
});
this.adjustPreloaderBehavior();
}
addButtons() {
this.pswp.ui.registerElement({
name: 'incrementalZoomIn',
title: 'Zoom In',
order: 10,
isButton: true,
html: {
isCustomSVG: true,
inner: '<path d="M17.426 19.926a6 6 0 1 1 1.5-1.5L23 22.5 21.5 24l-4.074-4.074z" id="pswp__icn-incremental-zoom-in"/>'
+ '<path fill="currentColor" d="M11 16v-2h6v2z"/>'
+ '<path fill="currentColor" d="M13 12h2v6h-2z"/>',
outlineID: 'pswp__icn-incremental-zoom-in'
},
onClick: (e, zoomInBtnElement) => {
this.incrementalZoomIn(false);
this.updateZoomInButtonState(zoomInBtnElement);
},
onInit: (zoomInBtnElement) => {
pswp.on('zoomPanUpdate', () => {
this.updateZoomInButtonState(zoomInBtnElement);
});
}
});
this.pswp.ui.registerElement({
name: 'incrementalZoomOut',
title: 'Zoom Out',
order: 9,
isButton: true,
html: {
isCustomSVG: true,
inner: '<path d="M17.426 19.926a6 6 0 1 1 1.5-1.5L23 22.5 21.5 24l-4.074-4.074z" id="pswp__icn-incremental-zoom-out"/>'
+ '<path fill="currentColor" d="M11 16v-2h6v2z"/>',
outlineID: 'pswp__icn-incremental-zoom-out'
},
onClick: (e, zoomInBtnElement) => {
this.incrementalZoomOut(false);
this.updateZoomOutButtonState(zoomInBtnElement);
},
onInit: (zoomInBtnElement) => {
pswp.on('zoomPanUpdate', () => {
this.updateZoomOutButtonState(zoomInBtnElement);
});
}
});
this.pswp.ui.registerElement({
name: 'zoomToStart',
title: 'Zoom to start position',
order: 8,
isButton: true,
html: {
isCustomSVG: true,
inner: '<path d="M11.213 9.587 9.961 7.91l-1.852 5.794 6.082-.127-1.302-1.744a5.201 5.201 0 0 1 7.614 6.768 5.2 5.2 0 0 1-7.103 1.903L12 22.928a8 8 0 1 0-.787-13.34Z" id="pswp__icn-zoom-to-start"/>',
outlineID: 'pswp__icn-zoom-to-start'
},
onClick: (e, zoomToStartBtnElement) => {
this.zoomToStart();
this.updateZoomToStartButtonState(zoomToStartBtnElement);
},
onInit: (zoomToStartBtnElement) => {
pswp.on('zoomPanUpdate', () => {
this.updateZoomToStartButtonState(zoomToStartBtnElement);
});
}
});
}
/**
* Return the closest layer scale
*
* @param {Number} scale
*/
getClosestLayerZoomLevel(scale) {
const { tiler } = this.pswp.currSlide;
if (!tiler) {
return scale;
}
const layersScale = tiler.layers.map((layer) => layer.scale);
const closestZoomLevel = layersScale.reduce((prev, curr) => {
return (
Math.abs(curr - scale) < Math.abs(prev - scale)
? curr
: prev
);
});
return closestZoomLevel;
}
adjustPreloaderBehavior() {
this.pswp.on('afterInit', () => {
this.preloaderInterval = setInterval(() => {
if (!document.hidden && pswp.ui.updatePreloaderVisibility) {
pswp.ui.updatePreloaderVisibility();
}
}, 500);
});
this.pswp.addFilter('isContentLoading', (isLoading, content) => {
if (!isLoading && content.slide && content.slide.tiler) {
return !content.slide.tiler.manager.activeTilesLoaded();
}
return isLoading;
});
this.pswp.on('destroy', () => {
if (this.preloaderInterval) {
clearInterval(this.preloaderInterval);
this.preloaderInterval = null;
}
});
}
incrementalZoomIn(point) {
const { tiler } = this.pswp.currSlide;
let destZoomLevel;
if (tiler) {
destZoomLevel = this.pswp.currSlide.currZoomLevel * 2;
const closestZoomLevel = this.getClosestLayerZoomLevel(destZoomLevel);
if (closestZoomLevel > this.pswp.currSlide.currZoomLevel) {
destZoomLevel = closestZoomLevel;
}
destZoomLevel = Math.min(destZoomLevel, this.pswp.currSlide.zoomLevels.secondary);
} else {
destZoomLevel = this.pswp.currSlide.zoomLevels.secondary;
}
this.pswp.zoomTo(
destZoomLevel,
point,
this.pswp.options.zoomAnimationDuration
);
}
zoomToStart() {
this.pswp.zoomTo(
this.pswp.currSlide.zoomLevels.fit,
false,
this.pswp.options.zoomAnimationDuration
);
}
incrementalZoomOut(point) {
const { tiler } = this.pswp.currSlide;
let destZoomLevel;
if (tiler) {
destZoomLevel = this.pswp.currSlide.currZoomLevel / 2;
const closestZoomLevel = this.getClosestLayerZoomLevel(destZoomLevel);
if (closestZoomLevel < this.pswp.currSlide.currZoomLevel) {
destZoomLevel = closestZoomLevel;
}
destZoomLevel = Math.max(destZoomLevel, this.pswp.currSlide.zoomLevels.initial);
} else {
destZoomLevel = this.pswp.currSlide.zoomLevels.initial;
}
this.pswp.zoomTo(
destZoomLevel,
point,
this.pswp.options.zoomAnimationDuration
);
}
updateZoomInButtonState(el) {
if (!this.pswp.currSlide.currZoomLevel ||
!this.pswp.currSlide.isZoomable() ||
this.pswp.currSlide.currZoomLevel >= this.pswp.currSlide.zoomLevels.secondary) {
el.setAttribute('disabled', 'disabled');
} else {
el.removeAttribute('disabled');
}
}
updateZoomOutButtonState(el) {
if (!this.pswp.currSlide.currZoomLevel ||
!this.pswp.currSlide.isZoomable() ||
this.pswp.currSlide.currZoomLevel <= this.pswp.currSlide.zoomLevels.fit) {
el.setAttribute('disabled', 'disabled');
} else {
el.removeAttribute('disabled');
}
}
updateZoomToStartButtonState(el) {
if (!this.pswp.currSlide.currZoomLevel ||
!this.pswp.currSlide.isZoomable() ||
this.pswp.currSlide.currZoomLevel <= this.pswp.currSlide.zoomLevels.initial * 3) {
el.setAttribute('disabled', 'disabled');
el.style.display = 'none';
} else {
el.removeAttribute('disabled');
el.style.display = 'block';
}
}
}
export default DeepZoomUI;