diff --git a/__tests__/integration/mirador/mirador-configs/index.js b/__tests__/integration/mirador/mirador-configs/index.js index db4e6f90f..e1f0e3d3a 100644 --- a/__tests__/integration/mirador/mirador-configs/index.js +++ b/__tests__/integration/mirador/mirador-configs/index.js @@ -20,12 +20,6 @@ export default { transitions: {}, }, windows: [{ - canvasId: 'https://iiif.harvardartmuseums.org/manifests/object/299843/canvas/canvas-47174892', - manifestId: 'https://iiif.harvardartmuseums.org/manifests/object/299843', - }, - { - canvasId: 'https://iiif.bodleian.ox.ac.uk/iiif/canvas/e58b8c60-005c-4c41-a22f-07d49cb25ede.json', - manifestId: 'https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json', - thumbnailNavigationPosition: 'far-bottom', + manifestId: 'https://wellcomelibrary.org/iiif/b18035723/manifest', }], }; diff --git a/src/components/OpenSeadragonComponent.js b/src/components/OpenSeadragonComponent.js index d8eedca0b..6f81d85be 100644 --- a/src/components/OpenSeadragonComponent.js +++ b/src/components/OpenSeadragonComponent.js @@ -10,7 +10,7 @@ import OpenSeadragonViewerContext from '../contexts/OpenSeadragonViewerContext'; /** Handle setting up OSD for use in mirador + react */ function OpenSeadragonComponent({ - children = undefined, Container = 'div', osdConfig = {}, viewerConfig = {}, onUpdateViewport = () => {}, setViewer = () => {}, style = {}, ...passThruProps + children = undefined, Container = 'div', osdConfig = {}, viewerConfig = {}, worldBounds = undefined, onUpdateViewport = () => {}, setViewer = () => {}, style = {}, ...passThruProps }) { const id = useId(); const ref = useRef(); @@ -33,6 +33,13 @@ function OpenSeadragonComponent({ bounds: viewport.getBounds(), flip: viewport.getFlip(), rotation: viewport.getRotation(), + worldBounds: (() => { + const homeBounds = viewport.viewer?.world?.getHomeBounds(); + + if (!homeBounds) return undefined; + + return [homeBounds.x, homeBounds.y, homeBounds.width, homeBounds.height]; + })(), x: Math.round(viewport.centerSpringX.target.value), y: Math.round(viewport.centerSpringY.target.value), zoom: viewport.zoomSpring.target.value, @@ -59,14 +66,16 @@ function OpenSeadragonComponent({ viewport.setFlip(viewerConfig.flip); } + const bounds = viewerConfig.bounds || worldBounds; + if (!viewerConfig.x && !viewerConfig.y && !viewerConfig.zoom) { - if (viewerConfig.bounds) { - viewport.fitBounds(new Openseadragon.Rect(...viewerConfig.bounds), true); + if (bounds) { + viewport.fitBounds(new Openseadragon.Rect(...bounds), true); } else { viewport.goHome(true); } } - }, [initialViewportSet, viewerConfig]); + }, [initialViewportSet, viewerConfig, worldBounds]); useEffect(() => { const viewer = viewerRef.current; @@ -100,19 +109,44 @@ function OpenSeadragonComponent({ viewport.setFlip(viewerConfig.flip); } - if (viewerConfig.bounds && !viewerConfig.x && !viewerConfig.y && !viewerConfig.zoom) { - const rect = new Openseadragon.Rect(...viewerConfig.bounds); - if (rect.equals(viewport.getBounds())) { + const bounds = viewerConfig.bounds || worldBounds; + if (bounds && !viewerConfig.x && !viewerConfig.y && !viewerConfig.zoom) { + const rect = new Openseadragon.Rect(...bounds); + if (!rect.equals(viewport.getBounds())) { + viewport.fitBounds(rect, false); + } + } + }, [initialViewportSet, setInitialBounds, viewerConfig, viewerRef, worldBounds]); + + useEffect(() => { + if (!osdConfig.preserveViewport) return; + if (!viewerConfig?.worldBounds || !worldBounds) return; + + const viewer = viewerRef.current; + if (!viewer) return; + const { viewport } = viewer; + + const [_x, _y, width, height] = viewerConfig.worldBounds; + const [_x1, _y1, width1, height1] = worldBounds; + + const previousAspectRatio = (1.0 * width) / height; + const newAspectRatio = (1.0 * width1) / height1; + + if ((previousAspectRatio < (1 - osdConfig.resetViewportAfterAspectRatioDelta) * newAspectRatio) + || (previousAspectRatio > (1 + osdConfig.resetViewportAfterAspectRatioDelta) * newAspectRatio)) { + const rect = new Openseadragon.Rect(...worldBounds); + if (!rect.equals(viewport.getBounds())) { viewport.fitBounds(rect, false); } } - }, [initialViewportSet, setInitialBounds, viewerConfig, viewerRef]); + }, [osdConfig, viewerConfig, worldBounds, viewerRef]); // initialize OSD stuff when this component is mounted useEffect(() => { const viewer = Openseadragon({ element: ref.current, ...osdConfig, + preserveViewportAspectRatio: undefined, }); viewer.addHandler('canvas-drag', () => { @@ -200,6 +234,7 @@ OpenSeadragonComponent.propTypes = { y: PropTypes.number, zoom: PropTypes.number, }), + worldBounds: PropTypes.arrayOf(PropTypes.number), }; export default OpenSeadragonComponent; diff --git a/src/components/OpenSeadragonViewer.js b/src/components/OpenSeadragonViewer.js index 0e7d7fd3d..1ce85d7d4 100644 --- a/src/components/OpenSeadragonViewer.js +++ b/src/components/OpenSeadragonViewer.js @@ -25,7 +25,7 @@ const StyledSection = styled('section')({ * and rendering OSD. */ export function OpenSeadragonViewer({ - children = null, label = null, windowId, osdConfig = {}, viewerConfig = null, + children = null, label = null, windowId, osdConfig = {}, viewerConfig = undefined, drawAnnotations = false, infoResponses = [], canvasWorld, nonTiledImages = [], updateViewport, ...rest }) { @@ -33,11 +33,12 @@ export function OpenSeadragonViewer({ const apiRef = useRef(); const [viewer, setViewer] = useState(null); const onViewportChange = useCallback(({ - flip, rotation, x, y, zoom, + flip, rotation, worldBounds, x, y, zoom, }) => { updateViewport(windowId, { flip, rotation, + worldBounds, x, y, zoom, @@ -89,7 +90,8 @@ export function OpenSeadragonViewer({ className={classNames(ns('osd-container'))} Container={StyledSection} osdConfig={osdConfig} - viewerConfig={viewerConfig || (canvasWorld.hasDimensions() ? { bounds: canvasWorld.worldBounds() } : undefined)} + viewerConfig={viewerConfig} + worldBounds={(canvasWorld.hasDimensions() ? canvasWorld.worldBounds() : undefined)} onUpdateViewport={onViewportChange} setViewer={setViewer} aria-label={t('item', { label })} diff --git a/src/config/settings.js b/src/config/settings.js index c40dac40f..9b8ca5a71 100644 --- a/src/config/settings.js +++ b/src/config/settings.js @@ -545,6 +545,7 @@ export default { blendTime: 0.1, preserveImageSizeOnResize: true, preserveViewport: true, + resetViewportAfterAspectRatioDelta: 0.25, showNavigationControl: false, zoomPerClick: 1, // disable zoom-to-click zoomPerDoubleClick: 2.0