@knaw-huc/osd-iiif-viewer 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -10
- package/dist/ControlSlice.d.ts +4 -1
- package/dist/InstanceSlice.d.ts +4 -1
- package/dist/Resettable.d.ts +3 -0
- package/dist/ViewerStore.d.ts +2 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +52 -43
- package/dist/manifest/CanvasSlice.d.ts +2 -2
- package/dist/manifest/ManifestSlice.d.ts +3 -3
- package/dist/manifest/useManifest.d.ts +1 -2
- package/package.json +1 -1
- package/dist/manifest/getAnnotationPageIds.d.ts +0 -3
package/README.md
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
# @knaw-huc/osd-iiif-viewer
|
|
2
2
|
|
|
3
|
-
React wrapper around OpenSeadragon to display and browse image sources from
|
|
3
|
+
Lightweight React wrapper around OpenSeadragon to display and browse image sources from IIIF manifests.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Features:
|
|
6
6
|
- Canvas navigation
|
|
7
7
|
- Highlight overlay
|
|
8
8
|
- Zoom and fullscreen controls
|
|
9
|
-
-
|
|
9
|
+
- IIIF manifest loading
|
|
10
|
+
|
|
11
|
+
## Example
|
|
10
12
|
|
|
11
|
-
## Minimal example
|
|
12
13
|
```tsx
|
|
13
|
-
import {
|
|
14
|
+
import {useEffect} from 'react';
|
|
14
15
|
import {
|
|
15
16
|
Viewer,
|
|
16
17
|
ViewerProvider,
|
|
@@ -20,27 +21,28 @@ import {
|
|
|
20
21
|
|
|
21
22
|
export function Example() {
|
|
22
23
|
return <ViewerProvider>
|
|
23
|
-
<
|
|
24
|
+
<MyOsdIiifView/>
|
|
24
25
|
</ViewerProvider>
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
function
|
|
28
|
+
function MyOsdIiifView() {
|
|
28
29
|
const loadManifest = useLoadManifest();
|
|
29
|
-
const
|
|
30
|
+
const {isReady} = useManifest();
|
|
30
31
|
|
|
31
32
|
useEffect(() => {
|
|
32
33
|
loadManifest('/manifest.json');
|
|
33
34
|
}, [loadManifest]);
|
|
34
35
|
|
|
35
|
-
if (
|
|
36
|
+
if (!isReady) {
|
|
36
37
|
return null;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
return (
|
|
40
|
-
<div style={{
|
|
41
|
+
<div style={{width: '100%', height: '100vh'}}>
|
|
41
42
|
<Viewer/>
|
|
42
43
|
</div>
|
|
43
44
|
);
|
|
44
45
|
}
|
|
45
46
|
```
|
|
46
47
|
|
|
48
|
+
For more examples, run `npm i && npm start` and open http://localhost:5173
|
package/dist/ControlSlice.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
import { ViewerStore } from './ViewerStore.ts';
|
|
3
|
-
|
|
3
|
+
import { Resettable } from './Resettable.ts';
|
|
4
|
+
export type ControlState = {
|
|
4
5
|
zoomLevel: number | null;
|
|
5
6
|
zoomMin: number | null;
|
|
6
7
|
zoomMax: number | null;
|
|
7
8
|
isFullPage: boolean;
|
|
8
9
|
rotation: number;
|
|
10
|
+
};
|
|
11
|
+
export type ControlSlice = Resettable & ControlState & {
|
|
9
12
|
setZoomLevel: (zoomLevel: number | null) => void;
|
|
10
13
|
setZoomMin: (zoomMin: number | null) => void;
|
|
11
14
|
setZoomMax: (zoomMax: number | null) => void;
|
package/dist/InstanceSlice.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
import { default as OpenSeadragon } from 'openseadragon';
|
|
3
3
|
import { ViewerStore } from './ViewerStore.ts';
|
|
4
|
-
|
|
4
|
+
import { Resettable } from './Resettable.ts';
|
|
5
|
+
export type InstanceState = {
|
|
5
6
|
viewer: OpenSeadragon.Viewer | null;
|
|
6
7
|
viewerReady: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type InstanceSlice = Resettable & InstanceState & {
|
|
7
10
|
setViewer: (viewer: OpenSeadragon.Viewer | null) => void;
|
|
8
11
|
setViewerReady: (viewerReady: boolean) => void;
|
|
9
12
|
};
|
package/dist/ViewerStore.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import { InstanceSlice } from './InstanceSlice.ts';
|
|
|
2
2
|
import { ControlSlice } from './ControlSlice.ts';
|
|
3
3
|
import { ManifestSlice } from './manifest/ManifestSlice.ts';
|
|
4
4
|
import { CanvasSlice } from './manifest/CanvasSlice.ts';
|
|
5
|
-
|
|
5
|
+
import { Resettable } from './Resettable.ts';
|
|
6
|
+
export type ViewerStore = InstanceSlice & ControlSlice & ManifestSlice & CanvasSlice & Resettable;
|
|
6
7
|
export declare const createViewerStore: () => import('zustand').StoreApi<ViewerStore>;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,4 +12,3 @@ export { useVault } from './manifest/useVault';
|
|
|
12
12
|
export { findTileSource } from './manifest/findTileSource';
|
|
13
13
|
export { findThumbnail } from './manifest/findThumbnail';
|
|
14
14
|
export { getImageServiceId } from './manifest/getImageServiceId';
|
|
15
|
-
export { getAnnotationPageIds } from './manifest/getAnnotationPageIds.ts';
|
package/dist/index.js
CHANGED
|
@@ -1774,60 +1774,73 @@ var E = class {
|
|
|
1774
1774
|
this.dispatch(typeof r2 == "function" ? i2.setMetaValueDynamic({ id: e2, meta: t3, key: n2, updateValue: r2 }) : i2.setMetaValue({ id: e2, meta: t3, key: n2, value: r2 }));
|
|
1775
1775
|
}
|
|
1776
1776
|
};
|
|
1777
|
-
const
|
|
1777
|
+
const defaultState$1 = {
|
|
1778
1778
|
viewer: null,
|
|
1779
|
-
viewerReady: !1
|
|
1779
|
+
viewerReady: !1
|
|
1780
|
+
}, createInstanceSlice = (set) => ({
|
|
1781
|
+
...defaultState$1,
|
|
1780
1782
|
setViewer: (viewer) => set({ viewer }),
|
|
1781
|
-
setViewerReady: (viewerReady) => set({ viewerReady })
|
|
1782
|
-
|
|
1783
|
+
setViewerReady: (viewerReady) => set({ viewerReady }),
|
|
1784
|
+
reset: () => set(defaultState$1)
|
|
1785
|
+
}), defaultState = {
|
|
1783
1786
|
zoomLevel: null,
|
|
1784
1787
|
zoomMin: null,
|
|
1785
1788
|
zoomMax: null,
|
|
1786
1789
|
isFullPage: !1,
|
|
1787
|
-
rotation: 0
|
|
1790
|
+
rotation: 0
|
|
1791
|
+
}, createControlSlice = (set) => ({
|
|
1792
|
+
...defaultState,
|
|
1788
1793
|
setZoomLevel: (zoomLevel) => set({ zoomLevel }),
|
|
1789
1794
|
setZoomMin: (zoomMin) => set({ zoomMin }),
|
|
1790
1795
|
setZoomMax: (zoomMax) => set({ zoomMax }),
|
|
1791
1796
|
setIsFullPage: (isFullPage) => set({ isFullPage }),
|
|
1792
|
-
setRotation: (rotation) => set({ rotation })
|
|
1793
|
-
|
|
1794
|
-
|
|
1797
|
+
setRotation: (rotation) => set({ rotation }),
|
|
1798
|
+
reset: () => set(defaultState)
|
|
1799
|
+
}), defaultManifest = {
|
|
1800
|
+
url: null,
|
|
1801
|
+
isLoading: !1,
|
|
1802
|
+
error: null
|
|
1803
|
+
}, createManifestSlice = (vault) => (set) => ({
|
|
1804
|
+
vault,
|
|
1805
|
+
...defaultManifest,
|
|
1795
1806
|
loadManifest: async (url) => {
|
|
1796
|
-
|
|
1797
|
-
set({ manifest: { vault: vault2, url, isLoading: !0, error: null } });
|
|
1807
|
+
set({ url, isLoading: !0, error: null });
|
|
1798
1808
|
try {
|
|
1799
|
-
await
|
|
1809
|
+
await vault.loadManifest(url), set({ isLoading: !1, error: null });
|
|
1800
1810
|
} catch (e2) {
|
|
1801
1811
|
const error = e2 instanceof Error ? e2.message : "Unknown error";
|
|
1802
|
-
set({
|
|
1812
|
+
set({ isLoading: !1, error });
|
|
1803
1813
|
}
|
|
1804
|
-
}
|
|
1805
|
-
}), createCanvasSlice = (set, get) => ({
|
|
1806
|
-
canvas: {
|
|
1807
|
-
currentIndex: 0
|
|
1808
1814
|
},
|
|
1815
|
+
reset: () => set(defaultManifest)
|
|
1816
|
+
}), defaultCanvas = {
|
|
1817
|
+
currentIndex: 0
|
|
1818
|
+
}, createCanvasSlice = (set, get) => ({
|
|
1819
|
+
...defaultCanvas,
|
|
1809
1820
|
goToCanvas: (index) => {
|
|
1810
|
-
const { vault, url } = get()
|
|
1821
|
+
const { vault, url } = get();
|
|
1811
1822
|
if (!url)
|
|
1812
1823
|
return;
|
|
1813
1824
|
const manifest = vault.get({ id: url, type: "Manifest" }), clamped = Math.max(0, Math.min(index, manifest.items.length - 1));
|
|
1814
|
-
set({
|
|
1825
|
+
set({ currentIndex: clamped });
|
|
1815
1826
|
},
|
|
1816
1827
|
nextCanvas: () => {
|
|
1817
|
-
const {
|
|
1818
|
-
goToCanvas(
|
|
1828
|
+
const { currentIndex, goToCanvas } = get();
|
|
1829
|
+
goToCanvas(currentIndex + 1);
|
|
1819
1830
|
},
|
|
1820
1831
|
prevCanvas: () => {
|
|
1821
|
-
const {
|
|
1822
|
-
goToCanvas(
|
|
1823
|
-
}
|
|
1832
|
+
const { currentIndex, goToCanvas } = get();
|
|
1833
|
+
goToCanvas(currentIndex - 1);
|
|
1834
|
+
},
|
|
1835
|
+
reset: () => set(defaultCanvas)
|
|
1824
1836
|
}), createViewerStore = () => {
|
|
1825
|
-
const vault = new E();
|
|
1837
|
+
const vault = new E(), resets = [], withReset = (slice) => (resets.push(slice.reset), slice);
|
|
1826
1838
|
return createStore((...a2) => ({
|
|
1827
|
-
...createInstanceSlice(...a2),
|
|
1828
|
-
...createControlSlice(...a2),
|
|
1829
|
-
...createManifestSlice(vault)(...a2),
|
|
1830
|
-
...createCanvasSlice(...a2)
|
|
1839
|
+
...withReset(createInstanceSlice(...a2)),
|
|
1840
|
+
...withReset(createControlSlice(...a2)),
|
|
1841
|
+
...withReset(createManifestSlice(vault)(...a2)),
|
|
1842
|
+
...withReset(createCanvasSlice(...a2)),
|
|
1843
|
+
reset: () => resets.forEach((fn) => fn())
|
|
1831
1844
|
}));
|
|
1832
1845
|
}, ViewerContext = createContext(null);
|
|
1833
1846
|
function orThrow(msg) {
|
|
@@ -1920,7 +1933,7 @@ function useViewerStoreSelector(selector) {
|
|
|
1920
1933
|
return useStore(store, selector);
|
|
1921
1934
|
}
|
|
1922
1935
|
function useCanvas() {
|
|
1923
|
-
const
|
|
1936
|
+
const vault = useViewerStoreSelector((s2) => s2.vault), url = useViewerStoreSelector((s2) => s2.url), isLoading = useViewerStoreSelector((s2) => s2.isLoading), currentIndex = useViewerStoreSelector((s2) => s2.currentIndex), goTo = useViewerStoreSelector((s2) => s2.goToCanvas), next = useViewerStoreSelector((s2) => s2.nextCanvas), prev = useViewerStoreSelector((s2) => s2.prevCanvas), { current, total } = useMemo(() => {
|
|
1924
1937
|
if (!url || isLoading)
|
|
1925
1938
|
return { current: null, total: 0 };
|
|
1926
1939
|
const manifest = vault.get({ id: url, type: "Manifest" }), canvasRef = manifest.items[currentIndex] ?? orThrow("No canvas ref for " + currentIndex), current2 = vault.get(canvasRef), total2 = manifest.items.length;
|
|
@@ -1929,21 +1942,20 @@ function useCanvas() {
|
|
|
1929
1942
|
return { currentIndex, current, total, goTo, next, prev };
|
|
1930
1943
|
}
|
|
1931
1944
|
function useVault() {
|
|
1932
|
-
return useViewerStoreSelector((s2) => s2.
|
|
1945
|
+
return useViewerStoreSelector((s2) => s2.vault);
|
|
1933
1946
|
}
|
|
1934
1947
|
function Viewer({ showControls = !0 }) {
|
|
1935
1948
|
const containerRef = useRef(null), store = useViewerStore(), vault = useVault(), { current } = useCanvas(), tileSource = current ? findTileSource(vault, current) : null;
|
|
1936
1949
|
return useEffect(() => {
|
|
1937
|
-
if (!containerRef.current
|
|
1950
|
+
if (!containerRef.current)
|
|
1938
1951
|
return;
|
|
1939
1952
|
const viewer = new Viewer$1({
|
|
1940
1953
|
element: containerRef.current,
|
|
1941
1954
|
prefixUrl: "https://openseadragon.github.io/openseadragon/images/",
|
|
1942
1955
|
crossOriginPolicy: "Anonymous",
|
|
1943
|
-
tileSources: tileSource,
|
|
1944
1956
|
showNavigationControl: showControls
|
|
1945
1957
|
});
|
|
1946
|
-
store.getState().setViewer(viewer), viewer.
|
|
1958
|
+
store.getState().setViewer(viewer), viewer.addHandler("open", () => {
|
|
1947
1959
|
const state2 = store.getState();
|
|
1948
1960
|
state2.setViewerReady(!0), state2.setZoomLevel(viewer.viewport.getZoom()), state2.setZoomMin(viewer.viewport.getMinZoom()), state2.setZoomMax(viewer.viewport.getMaxZoom()), state2.setRotation(viewer.viewport.getRotation());
|
|
1949
1961
|
});
|
|
@@ -1953,11 +1965,12 @@ function Viewer({ showControls = !0 }) {
|
|
|
1953
1965
|
store.getState().setRotation(viewer.viewport.getRotation());
|
|
1954
1966
|
};
|
|
1955
1967
|
return viewer.addHandler("animation-start", onZoom), viewer.addHandler("animation-finish", onZoom), viewer.addHandler("rotate", onRotate), () => {
|
|
1956
|
-
viewer.
|
|
1957
|
-
const state2 = store.getState();
|
|
1958
|
-
state2.setViewer(null), state2.setViewerReady(!1), state2.setZoomLevel(null), state2.setZoomMin(null), state2.setZoomMax(null), state2.setIsFullPage(!1), state2.setRotation(0);
|
|
1968
|
+
viewer.destroy(), store.getState().reset();
|
|
1959
1969
|
};
|
|
1960
|
-
}, [
|
|
1970
|
+
}, [showControls, store]), useEffect(() => {
|
|
1971
|
+
const viewer = store.getState().viewer;
|
|
1972
|
+
!viewer || !tileSource || viewer.open(tileSource);
|
|
1973
|
+
}, [tileSource, store]), /* @__PURE__ */ jsx(
|
|
1961
1974
|
"div",
|
|
1962
1975
|
{
|
|
1963
1976
|
id: "viewer",
|
|
@@ -2040,8 +2053,8 @@ function useViewerControls(fullscreenRef) {
|
|
|
2040
2053
|
};
|
|
2041
2054
|
}
|
|
2042
2055
|
function useManifest() {
|
|
2043
|
-
const
|
|
2044
|
-
return {
|
|
2056
|
+
const url = useViewerStoreSelector((s2) => s2.url), isLoading = useViewerStoreSelector((s2) => s2.isLoading), error = useViewerStoreSelector((s2) => s2.error);
|
|
2057
|
+
return { url, isLoading, error, isReady: !!url && !isLoading && !error };
|
|
2045
2058
|
}
|
|
2046
2059
|
function useLoadManifest() {
|
|
2047
2060
|
return useViewerStoreSelector((s2) => s2.loadManifest);
|
|
@@ -2049,16 +2062,12 @@ function useLoadManifest() {
|
|
|
2049
2062
|
function findThumbnail(vault, canvas, height = 120) {
|
|
2050
2063
|
return getImageServiceId(vault, canvas) ? `/full/,${height}/0/default.jpg` : null;
|
|
2051
2064
|
}
|
|
2052
|
-
function getAnnotationPageIds(canvas) {
|
|
2053
|
-
return canvas.annotations.map((ref) => ref.id).filter((id) => !!id);
|
|
2054
|
-
}
|
|
2055
2065
|
export {
|
|
2056
2066
|
Overlay,
|
|
2057
2067
|
Viewer,
|
|
2058
2068
|
ViewerProvider,
|
|
2059
2069
|
findThumbnail,
|
|
2060
2070
|
findTileSource,
|
|
2061
|
-
getAnnotationPageIds,
|
|
2062
2071
|
getImageServiceId,
|
|
2063
2072
|
useCanvas,
|
|
2064
2073
|
useImageInfo,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
import { ViewerStore } from '../ViewerStore.ts';
|
|
3
|
+
import { Resettable } from '../Resettable.ts';
|
|
3
4
|
export type CanvasState = {
|
|
4
5
|
currentIndex: number;
|
|
5
6
|
};
|
|
6
|
-
export type CanvasSlice = {
|
|
7
|
-
canvas: CanvasState;
|
|
7
|
+
export type CanvasSlice = Resettable & CanvasState & {
|
|
8
8
|
goToCanvas: (index: number) => void;
|
|
9
9
|
nextCanvas: () => void;
|
|
10
10
|
prevCanvas: () => void;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { StateCreator } from 'zustand/vanilla';
|
|
2
2
|
import { Vault } from '@iiif/helpers/vault';
|
|
3
3
|
import { ViewerStore } from '../ViewerStore.ts';
|
|
4
|
+
import { Resettable } from '../Resettable.ts';
|
|
4
5
|
export type ManifestState = {
|
|
5
6
|
url: string | null;
|
|
6
|
-
vault: Vault;
|
|
7
7
|
isLoading: boolean;
|
|
8
8
|
error: string | null;
|
|
9
9
|
};
|
|
10
|
-
export type ManifestSlice = {
|
|
11
|
-
|
|
10
|
+
export type ManifestSlice = Resettable & ManifestState & {
|
|
11
|
+
vault: Vault;
|
|
12
12
|
loadManifest: (url: string) => Promise<void>;
|
|
13
13
|
};
|
|
14
14
|
export declare const createManifestSlice: (vault: Vault) => StateCreator<ViewerStore, [], [], ManifestSlice>;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
export declare function useManifest(): {
|
|
2
|
-
isReady: boolean;
|
|
3
2
|
url: string | null;
|
|
4
|
-
vault: import('@iiif/helpers/vault').Vault;
|
|
5
3
|
isLoading: boolean;
|
|
6
4
|
error: string | null;
|
|
5
|
+
isReady: boolean;
|
|
7
6
|
};
|
|
8
7
|
export declare function useLoadManifest(): (url: string) => Promise<void>;
|
package/package.json
CHANGED