Viewer
A UI component that renders a multicanvas IIIF item viewer with pan-zoom support for Image
via OpenSeadragon (opens in a new tab) and Video
and Sound
content resources using the HTML video element (opens in a new tab).
Features
Provide a IIIF Presentation API (opens in a new tab) Manifest or Collection and the component:
- Renders a multi-canvas Video, Sound, and Image viewer
- Renders thumbnails as navigation between canvases
- Renders annotations with the motivation (opens in a new tab) of
supplementing
with a content resource having the format oftext/vtt
for Video and Sound - Video and Sound are rendered within a HTML5
<video>
element - Image canvases are renderered with OpenSeadragon (opens in a new tab)
- Supports HLS streaming for Video and Audio canvases
- Supports IIIF Collections and toggling between child Manifests
- Supports
placeholderCanvas
for Image canvases.
Installation
npm install @samvera/clover-iiif
Usage
React
Add the Viewer
component to your jsx
or tsx
code.
import Viewer from "@samvera/clover-iiif/viewer";
Render Viewer
with a IIIF Manifest or Collection URI. The only required prop is the iiifContent
, which is the URI of the IIIF Manifest or Collection.
<Viewer iiifContent="https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif" />
Vanilla JavaScript
The Viewer can also be implemented in Vanilla Javascript by use of a web component. This web component example sources a registered <clover-viewer>
web component.
<html>
<head>
<title>Clover IIIF - Viewer - Web Component</title>
<meta charset="UTF-8" />
</head>
<body>
<script src="https://www.unpkg.com/@samvera/clover-iiif@latest/dist/web-components/index.umd.js"></script>
<clover-viewer
id="https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif"
/>
</body>
</html>
Next.js
Implementation with Next.js requires a dynamic import (opens in a new tab) utilizing next/dynamic
. This is due to Next's node compilation method creating issue with an OpenSeadragon
(a dependency of Clover IIIF) assumption of a browser document
object.
import dynamic from "next/dynamic";
const Viewer = dynamic(
() => import("@samvera/clover-iiif").then((Clover) => Clover.Viewer),
{
ssr: false,
},
);
const MyCustomViewer = () => {
const iiifContent =
"https://api.dc.library.northwestern.edu/api/v2/collections/c373ecd2-2c45-45f2-9f9e-52dc244870bd?as=iiif";
return <Viewer iiifContent={iiifContent} />;
};
API Reference
Viewer
can configured through an options
prop, which will serve as a object for common options.
Prop | Type | Required | Default |
---|---|---|---|
iiifContent | string | Yes | |
canvasIdCallback | function | No | |
customDisplays | See Custom Displays | No | |
customTheme | object | No | |
options | object | No | |
options.background | string CSS (opens in a new tab) | No | transparent |
options.canvasBackgroundColor | string CSS (opens in a new tab) | No | #1a1d1e |
options.canvasHeight | string CSS (opens in a new tab) | No | 500px |
options.ignoreCaptionLabels | string[] | No | [] |
options.openSeadragon | OpenSeadragon.Options | No | |
options.informationPanel | See Information Panel | No | |
options.requestHeaders | IncomingHttpHeaders | No | { "Content-Type": "application/json" } |
options.showDownload | boolean | No | true |
options.showIIIFBadge | boolean | No | true |
options.showTitle | boolean | No | true |
options.withCredentials | boolean | No | false |
- Options
canvasBackgroundColor
andcanvasHeight
will apply to both<video>
elements and the OpenseaDragon canvas. - Option
withCredentials
being set astrue
will inform IIIF resource requests to be made using credentials (opens in a new tab) such as cookies, authorization headers or TLS client certificates. - Option
options.openSeadragon
will grant you ability to override the OpenSeadragon default options (opens in a new tab) set within the Clover IIIF Viewer to adjust touch and mouse gesture settings and various other configurations.
Canvas Height
The height of the canvas can be set using the options.canvasHeight
prop. This prop accepts a string value that is a valid CSS height value. The default value is 500px
.
Automatic Height
If the height is set to auto
or 100%
, the Viewer will expand to the height of its wrapping container element. The wrapping element must have a position relative
, along with a defined height
for this to display as expected. Be aware to set a z-index
value of 0
or an applicable value within your consuming application to ensure the viewer does not conflict with other page elements.
export default function App() {
const iiifContent =
"https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif";
const options = {
canvasHeight: "auto", // or "100%"
};
return (
<div style={{ position: "relative", height: "80vh", zIndex: "0" }}>
<Viewer iiifContent={iiifContent} options={options} />
</div>
);
}
Information Panel
The information panel is a collapsible panel that displays information about the current Manifest and renders supplementing resources for the active canvas. It is rendered by default, but can be configured to be hidden or to render only certain tabs.
Prop | Type | Required | Default |
---|---|---|---|
options.informationPanel.open | boolean | No | true |
options.informationPanel.vtt.autoScroll | See Auto Scroll | No | true |
options.informationPanel.renderAbout | boolean | No | true |
options.informationPanel.renderAnnotation | boolean | No | true |
options.informationPanel.renderSupplementing | boolean | No | true |
options.informationPanel.renderToggle | boolean | No | true |
Auto Scroll
When VTT annotations are displayed, the Clover IIIF Viewer can automatically scroll the information panel to keep the currently active caption in view. Whether it does so (and how) is governed by the informationPanel.vtt.autoScroll
configuration option. The possible values are:
{ behavior: (behavior), block: (block) }
: auto-scroll using the given settings (see below).true
: Auto-scroll using the default behavior. This is equivalent to{ behavior: "smooth", block: "center" }
.false
: Do not auto-scroll.
The settings take the form { behavior: "auto" | "instant" | "smooth", block: "center" | "end" | "nearest" | "start" }
, and have the same effect as the scrollIntoViewOptions
object documented with the Element.scrollIntoView()
(opens in a new tab) Web API method. (The inline
option does not apply since there is no horizontal scrolling involved.)
Custom Displays
Clients may wish to use their own display components (for example a PDF Viewer, or an audio player, etc). To configure custom displays, use the customDisplays
prop, which is an array of objects defining display
and target
properties. See an example implementation
display.component
is a custom React component, and display.componentProps
are pass-through props which Viewer
will attach to your Custom Display component. The target
object provides two methods of matching a Canvas to a Custom Display: target.canvasId
which is a manifest's canvas id
. Or by target.paintingFormat
(ie. application/pdf
) which is the body.type
in a canvas's Annotation
of type "painting".
Prop | Type | Required | Default |
---|---|---|---|
customDisplays.display.component | React.Node | No | |
customDisplays.display.componentProps | object | No | |
customDisplays.target.canvasId | string[] | No | |
customDisplays.target.paintingFormat | string[] | No |
Deprecated Options
Prop | In Favor Of | Deprecated |
---|---|---|
id | iiifContent | v2.0.0 |
manifestId | iiifContent | v2.0.0 |
options.renderAbout | options.informationPanel.renderAbout | v2.0.3 |
options.showInformationToggle | options.informationPanel.renderToggle | v2.0.3 |
Basic Configuration
Example customization of various options
.
const options = {
// Primary title (Manifest label) for top level canvas. Defaults to true
showTitle: false,
// IIIF Badge and popover containing options. Defaults to true
showIIIFBadge: false,
// Ignore supplementing canvases by label value that are not for captioning
ignoreCaptionLabels: ['Chapters'],
// Override canvas background color, defaults to #1a1d1e
canvasBackgroundColor: "#000",
// Set canvas zooming onScoll (this defaults to false)
openSeadragon: {
gestureSettingsMouse: {
scrollToZoom: true;
}
}
}
<Viewer
iiifContent="https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif"
options={options}
/>
Active Canvas
Example on using canvasIdCallback
to return to your consuming application the active canvas ID. This will return as a string.
const iiifContent =
"https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif";
const handlCanvasIdCallback = (activeCanvasId) => {
if (activeCanvasId) console.log(activeCanvasId);
};
return (
<Viewer iiifContent={iiifContent} canvasIdCallback={handlCanvasIdCallback} />
);
Captions
WebVTT content resources are the source for both content mapped closed captioning <track/>
elements in the HTML 5 video player and to the navigator panel adjacent to it. You may ignore these resources as tracks if they are not intended for closed captioning or subtitling by string values matching the label of the content resource. This is a manual option within the viewer as there is no defined way for a manifest to prescribe motivation for these resources beyond supplementing
.
export default function App() {
const iiifContent =
"https://raw.githubusercontent.com/samvera-labs/clover-iiif/main/public/fixtures/iiif/manifests/captions.json";
const options = {
ignoreCaptionLabels: ["Chapters"],
};
return <Viewer iiifContent={iiifContent} options={options} />;
}
Custom Theme
You may choose to override the base theme by setting optional colors and fonts. Naming conventions for colors are limited to those shown in the config example below.
const iiifContent =
"https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif";
const customTheme = {
colors: {
/**
* Black and dark grays in a light theme.
* All must contrast to 4.5 or greater with `secondary`.
*/
primary: "#37474F",
primaryMuted: "#546E7A",
primaryAlt: "#263238",
/**
* Key brand color(s).
* `accent` must contrast to 4.5 or greater with `secondary`.
*/
accent: "#C62828",
accentMuted: "#E57373",
accentAlt: "#B71C1C",
/**
* White and light grays in a light theme.
* All must must contrast to 4.5 or greater with `primary` and `accent`.
*/
secondary: "#FFFFFF",
secondaryMuted: "#ECEFF1",
secondaryAlt: "#CFD8DC",
},
fonts: {
sans: "'Helvetica Neue', sans-serif",
display: "Optima, Georgia, Arial, sans-serif",
},
};
return <Viewer iiifContent={iiifContent} customTheme={customTheme} />;
CSS Classes
Additional CSS classes are made available on structural HTML elements in the Viewer, which may be referenced in a client's own CSS files/style definitions to further customize the Viewer's appearance. You may inspect the DOM to see classes applied to each element, but in general it follows a pattern similar to:
<div class="clover-viewer">
<header class="clover-viewer-header" />
<div class="clover-viewer-content">
<div class="clover-viewer-painting">...</div>
</div>
</div>
Request Headers
In some cases, a client may need to request Manifest or Collection resources with custom request headers, ex: Authorization
. This can be done by passing a requestHeaders
object to the options
prop. This object will be passed to the request call made by the Viewer. Accepted header keys are defined in the IncomingHttpHeaders (opens in a new tab) interface.
const iiifContent =
"https://api.dc.library.northwestern.edu/api/v2/works/8a833741-74a8-40dc-bd1d-c416a3b1bb38?as=iiif";
const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
return (
<Viewer
iiifContent={iiifContent}
options={{
requestHeaders: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}}
/>
);
Custom canvas displays
Clients may wish to use their own display components instead of Clover Viewer's default displays (OpenSeadragon (opens in a new tab) for images and HTML Video Player (opens in a new tab) for audio/video). The Viewer
component allows a client to target individual canvas
items in a IIIF Manifest by either direct reference to a canvas id
or format
(ie. video/ogg
). See the Type Definition below for CustomDisplay
, and an example implementation.
import AnotherCustomDisplay from "./AnotherCustomDisplay";
type CustomDisplay = {
display: {
component: React.ElementType;
componentProps: {
// Any custom props you want to pass to your component
[key: string]: any;
};
};
target: {
canvasId: string[];
paintingFormat: string[]; // "application/pdf" or "application/epub+zip"
};
};
function MyCustomDisplay({ id, annotationBody, ...restProps }: CustomDisplay) {
return (
<div>
<h1>My Custom Display</h1>
<p>Canvas ID: {id}</p>
<p>Annotation Body:</p>
<pre>{JSON.stringify(annotationBody)}</pre>
<p>Custom props:</p>
<pre>{JSON.stringify(restProps)}</pre>
...your display here
</div>
);
}
<Viewer
iiifContent={iiifContent}
customDisplays={[
{
display: {
component: MyCustomDisplay,
componentProps: {
foo: "bar",
},
},
target: {
canvasId: [
"https://uri-for-a-canvas-id/access/0",
"https://uri-for-a-canvas-id/access/1",
],
},
},
{
display: {
component: AnotherCustomDisplay,
},
target: {
paintingFormat: ["application/pdf", "image/gif"],
},
},
]}
/>;
The Viewer
component will pass the following props to your custom display component:
id
: The canvasid
for the resource being rendered. This may be helpful if you wanted to use the canvasid
to fetch additional data from your application's API.annotationBody
: Thebody
value for a canvasAnnotation
item withmotivation
"painting".
{
"id": "https://uri-for-a-canvas-id/access/0",
"type": "Annotation",
"motivation": "painting",
"body": {
"format": "application/pdf",
"height": 1686,
"id": "http://localhost:3000/media/pdf/file-sample_150kB.pdf",
"width": 1192
}
}
See a complete recipe for a PDF Viewer (opens in a new tab) using custom canvas displays.