Spaces:
Build error
Build error
File size: 3,229 Bytes
cf9842a eec7490 80f9a97 eec7490 6736e17 eec7490 6736e17 eec7490 1d5cfba eec7490 6736e17 eec7490 6736e17 cf9842a 6736e17 eec7490 6736e17 17c4592 6736e17 eec7490 1d5cfba eec7490 17c4592 6736e17 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 80f9a97 eec7490 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import { useEffect, useMemo, useRef, type FC } from 'react'
import OpenSeadragon from 'openseadragon'
import { RetroButton } from './retro'
interface Props {
/** URL du IIIF Image Service (zoom tuilé natif) */
iiifServiceUrl?: string | null
/** URL image statique (fallback si pas de service IIIF) */
fallbackImageUrl?: string | null
onViewerReady?: (viewer: OpenSeadragon.Viewer) => void
}
const Viewer: FC<Props> = ({ iiifServiceUrl, fallbackImageUrl, onViewerReady }) => {
const containerRef = useRef<HTMLDivElement>(null)
const viewerRef = useRef<OpenSeadragon.Viewer | null>(null)
const onViewerReadyRef = useRef(onViewerReady)
onViewerReadyRef.current = onViewerReady
useEffect(() => {
if (!containerRef.current) return
const viewer = OpenSeadragon({
element: containerRef.current,
showNavigationControl: false,
gestureSettingsMouse: { clickToZoom: false, scrollToZoom: true, dragToPan: true },
gestureSettingsTouch: { scrollToZoom: true, dragToPan: true, pinchToZoom: true },
animationTime: 0.3,
minZoomLevel: 0.1,
maxZoomLevel: 20,
crossOriginPolicy: 'Anonymous',
})
viewerRef.current = viewer
return () => {
viewer.destroy()
viewerRef.current = null
}
}, [])
// Source à ouvrir : préférer le service IIIF (zoom tuilé), sinon image statique
const source = useMemo(
() => iiifServiceUrl || fallbackImageUrl || '',
[iiifServiceUrl, fallbackImageUrl]
)
useEffect(() => {
const viewer = viewerRef.current
if (!viewer || !source) return
// Remove previous handlers to avoid accumulation on rapid page changes
viewer.removeAllHandlers('open')
viewer.removeAllHandlers('open-failed')
if (iiifServiceUrl) {
// Zoom tuilé natif — OpenSeadragon fetch info.json et configure les tuiles
viewer.open(iiifServiceUrl + '/info.json')
} else {
// Image statique simple (pas de zoom tuilé)
viewer.open({ type: 'image', url: source })
}
viewer.addOnceHandler('open', () => {
onViewerReadyRef.current?.(viewer)
})
viewer.addOnceHandler('open-failed', () => {
console.warn('[Viewer] Failed to open image source:', source)
})
}, [source, iiifServiceUrl])
return (
<div className="relative w-full h-full bg-retro-black">
<div ref={containerRef} className="w-full h-full" />
<div className="absolute bottom-2 right-2 flex gap-[2px]">
<RetroButton
size="sm"
onClick={() => viewerRef.current?.viewport.zoomBy(1.5)}
title="Zoom +"
>
+
</RetroButton>
<RetroButton
size="sm"
onClick={() => viewerRef.current?.viewport.zoomBy(0.67)}
title="Zoom -"
>
-
</RetroButton>
<RetroButton
size="sm"
onClick={() => viewerRef.current?.viewport.goHome()}
title="Reset"
>
o
</RetroButton>
<RetroButton
size="sm"
onClick={() => viewerRef.current?.setFullScreen(true)}
title="Plein ecran"
>
[]
</RetroButton>
</div>
</div>
)
}
export default Viewer
|