@knaw-huc/osd-iiif-viewer 0.1.0 → 0.1.2
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 +46 -1
- package/dist/Overlay.d.ts +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -12
- package/dist/useImageInfo.d.ts +5 -0
- package/package.json +5 -1
- package/dist/HighlightOverlay.d.ts +0 -11
package/README.md
CHANGED
|
@@ -1 +1,46 @@
|
|
|
1
|
-
# osd-iiif-viewer
|
|
1
|
+
# @knaw-huc/osd-iiif-viewer
|
|
2
|
+
|
|
3
|
+
React wrapper around OpenSeadragon to display and browse image sources from iiif manifests.
|
|
4
|
+
|
|
5
|
+
Current features (WIP):
|
|
6
|
+
- Canvas navigation
|
|
7
|
+
- Highlight overlay
|
|
8
|
+
- Zoom and fullscreen controls
|
|
9
|
+
- Manifest parsing (iiif manifests v3, ImageService2)
|
|
10
|
+
|
|
11
|
+
## Minimal example
|
|
12
|
+
```tsx
|
|
13
|
+
import {useEffect} from 'react';
|
|
14
|
+
import {
|
|
15
|
+
ViewerProvider,
|
|
16
|
+
ViewerCanvas,
|
|
17
|
+
useLoadManifest,
|
|
18
|
+
useManifest,
|
|
19
|
+
} from '@knaw-huc/osd-iiif-viewer';
|
|
20
|
+
|
|
21
|
+
export function Example() {
|
|
22
|
+
return <ViewerProvider>
|
|
23
|
+
<Viewer/>
|
|
24
|
+
</ViewerProvider>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function Viewer() {
|
|
28
|
+
const loadManifest = useLoadManifest();
|
|
29
|
+
const manifest = useManifest();
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
loadManifest('/manifest.json');
|
|
33
|
+
}, [loadManifest]);
|
|
34
|
+
|
|
35
|
+
if (!manifest.data) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<div style={{width: '100%', height: '100vh'}}>
|
|
41
|
+
<ViewerCanvas/>
|
|
42
|
+
</div>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { useStore } from "zustand/index";
|
|
2
|
+
import { createContext, useContext, useMemo, useState, useEffect, useRef, useCallback } from "react";
|
|
3
|
+
import { createStore } from "zustand/vanilla";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
1
5
|
import { jsx } from "react/jsx-runtime";
|
|
2
6
|
import { Viewer } from "openseadragon";
|
|
3
|
-
import { createContext, useContext, useRef, useEffect, useState, useCallback } from "react";
|
|
4
|
-
import { createStore } from "zustand/vanilla";
|
|
5
|
-
import { useStore } from "zustand/index";
|
|
6
7
|
const createInstanceSlice = (set) => ({
|
|
7
8
|
viewer: null,
|
|
8
9
|
viewerReady: !1,
|
|
@@ -153,13 +154,43 @@ const defaultManifest = { data: null, url: "", isLoading: !1, error: null }, cre
|
|
|
153
154
|
function useViewerStore() {
|
|
154
155
|
return useContext(ViewerContext) ?? orThrow("viewer hook must be used within viewer provider");
|
|
155
156
|
}
|
|
156
|
-
function findTileSource(canvas) {
|
|
157
|
-
return canvas.imageServiceId + "/info.json";
|
|
158
|
-
}
|
|
159
157
|
function useViewerStoreSelector(selector) {
|
|
160
158
|
const store = useViewerStore();
|
|
161
159
|
return useStore(store, selector);
|
|
162
160
|
}
|
|
161
|
+
function useViewer() {
|
|
162
|
+
return useViewerStoreSelector((s) => s.viewer);
|
|
163
|
+
}
|
|
164
|
+
function useViewerReady() {
|
|
165
|
+
return useViewerStoreSelector((s) => s.viewerReady);
|
|
166
|
+
}
|
|
167
|
+
function useImageInfo() {
|
|
168
|
+
const viewer = useViewer(), ready = useViewerReady();
|
|
169
|
+
return useMemo(() => {
|
|
170
|
+
if (!viewer || !ready)
|
|
171
|
+
return null;
|
|
172
|
+
const item = viewer.world.getItemAt(0);
|
|
173
|
+
if (!item)
|
|
174
|
+
return null;
|
|
175
|
+
const size = item.getContentSize();
|
|
176
|
+
return { location: item.imageToViewportRectangle(0, 0, size.x, size.y), size };
|
|
177
|
+
}, [viewer, ready]);
|
|
178
|
+
}
|
|
179
|
+
function Overlay({ location, children }) {
|
|
180
|
+
const viewer = useViewer(), [container] = useState(() => {
|
|
181
|
+
const el = document.createElement("div");
|
|
182
|
+
return el.style.position = "absolute", el.style.pointerEvents = "none", el;
|
|
183
|
+
});
|
|
184
|
+
return useEffect(() => {
|
|
185
|
+
if (viewer)
|
|
186
|
+
return viewer.addOverlay({ element: container, location }), () => {
|
|
187
|
+
viewer.removeOverlay(container);
|
|
188
|
+
};
|
|
189
|
+
}, [viewer, location, container]), viewer ? createPortal(children, container) : null;
|
|
190
|
+
}
|
|
191
|
+
function findTileSource(canvas) {
|
|
192
|
+
return canvas.imageServiceId + "/info.json";
|
|
193
|
+
}
|
|
163
194
|
function useCanvas() {
|
|
164
195
|
const { currentIndex } = useViewerStoreSelector((s) => s.canvas), goTo = useViewerStoreSelector((s) => s.goToCanvas), next = useViewerStoreSelector((s) => s.nextCanvas), prev = useViewerStoreSelector((s) => s.prevCanvas), current = useViewerStoreSelector(
|
|
165
196
|
(s) => s.manifest.data?.canvases[s.canvas.currentIndex] ?? null
|
|
@@ -205,9 +236,6 @@ function ViewerProvider({ children }) {
|
|
|
205
236
|
const [store] = useState(() => createViewerStore());
|
|
206
237
|
return /* @__PURE__ */ jsx(ViewerContext.Provider, { value: store, children });
|
|
207
238
|
}
|
|
208
|
-
function useViewer() {
|
|
209
|
-
return useViewerStoreSelector((s) => s.viewer);
|
|
210
|
-
}
|
|
211
239
|
function useViewerControls(fullscreenRef) {
|
|
212
240
|
const viewer = useViewer(), store = useViewerStore(), zoomLevel = useViewerStoreSelector((s) => s.zoomLevel), zoomMin = useViewerStoreSelector((s) => s.zoomMin), zoomMax = useViewerStoreSelector((s) => s.zoomMax), isFullPage = useViewerStoreSelector((s) => s.isFullPage);
|
|
213
241
|
useEffect(() => {
|
|
@@ -240,9 +268,6 @@ function useViewerControls(fullscreenRef) {
|
|
|
240
268
|
isFullPage
|
|
241
269
|
};
|
|
242
270
|
}
|
|
243
|
-
function useViewerReady() {
|
|
244
|
-
return useViewerStoreSelector((s) => s.viewerReady);
|
|
245
|
-
}
|
|
246
271
|
function useManifest() {
|
|
247
272
|
return useViewerStoreSelector((s) => s.manifest);
|
|
248
273
|
}
|
|
@@ -250,9 +275,11 @@ function useLoadManifest() {
|
|
|
250
275
|
return useViewerStoreSelector((s) => s.loadManifest);
|
|
251
276
|
}
|
|
252
277
|
export {
|
|
278
|
+
Overlay,
|
|
253
279
|
ViewerCanvas,
|
|
254
280
|
ViewerProvider,
|
|
255
281
|
useCanvas,
|
|
282
|
+
useImageInfo,
|
|
256
283
|
useLoadManifest,
|
|
257
284
|
useManifest,
|
|
258
285
|
useViewer,
|
package/package.json
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knaw-huc/osd-iiif-viewer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/knaw-huc/osd-iiif-viewer.git"
|
|
7
|
+
},
|
|
4
8
|
"type": "module",
|
|
5
9
|
"main": "dist/index.js",
|
|
6
10
|
"types": "dist/index.d.ts",
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Id } from './Id.ts';
|
|
2
|
-
export type Highlight = {
|
|
3
|
-
id: Id;
|
|
4
|
-
path: string;
|
|
5
|
-
};
|
|
6
|
-
type HighlightOverlayProps = {
|
|
7
|
-
highlights: Highlight[];
|
|
8
|
-
onHover?: (highlightId: Id | null, event: MouseEvent) => void;
|
|
9
|
-
};
|
|
10
|
-
export declare function HighlightOverlay({ highlights, onHover }: HighlightOverlayProps): null;
|
|
11
|
-
export {};
|