These components are built a variety of community plugins and concepts to create a declarative and composable set of APIs that read IIIF resources and display them.

This set of components is less focused on the look, layout and presentational aspects of IIIF Viewers, and more focused on creating a top-down data-driven model that can be used as the functional skeleton for all IIIF experiences or viewers.

You can see these components in action At the main site

One of the goals is to create a cookbook of skeletons that can be used as a starting point. A representative example a cookbook entry might look like:

(
  <Manifest url="...">
    <CanvasProvider startCanvas={3}>
      <CanvasNavigation />
      <SingleTileSource>
        <OpenSeadragonViewer maxHeight={500} />
      </SingleTileSource>
      <MetadataPanel />
    </CanvasProvider>
  </Manifest>
)

From this you get all of the functionality you need to drive the IIIF resource and can work on wrapping components to customise them:

function CustomCanvasNavigation(props) {
  return (
    <div className="my-navigation">
        <img src="path/to/logo.png" />
        <CanvasNavigation {...props}/>
    </div>
  );
}

This very simple example wraps up the canvas navigation. Which could replace the component from the cookbook:

(
  <Manifest url="...">
    <CanvasProvider startCanvas={3}>
-      <CanvasNavigation />
+      <CustomCanvasNavigation />
      ...
    </CanvasProvider>
  </Manifest>
)

In general, when over-riding any component you must pass through the props in order for the data to continue flowing. This also applies when using inline JSX in components, the following example will not work:

(
  <Manifest url="...">
    <CanvasProvider startCanvas={3}>
+     <div className="my-wrapper">
        <CanvasNavigation />
+     </div>
      <SingleTileSource>
        <OpenSeadragonViewer maxHeight={500} />
      </SingleTileSource>
      <MetadataPanel />
    </CanvasProvider>
  </Manifest>
)

Since the data will be passed to the <div> element, instead of the navigation. One caveat that may be solved if we change to use something like Reacts context to implicitly pass the state to all the children.

Manifesto is a library for working with IIIF resources and provides a fluent and typed API for accessing fields, translations and abstracts breaking changes.

src/manifesto/AnnotationListProvider/AnnotationListProvider.js

The annotation list provider will call its children for every annotation list, allowing you to iterate through all of the annotations available on the manifest. It passes down props, so you can compose into CanvasRepresentations for displaying the annotations.

Loading...
src/manifesto/AnnotationProvider/AnnotationProvider.js

Annotation provider requires an annotationList to be provided either from a Provider or through its props.

The annotation provider takes an annotation and adds extra information. You get the annotations as an array which you can loop through.

You can extract the information and display it out, no viewer required.

Loading...

Or you can you use it to compose a CanvasRepresentation and paint the annotations to the canvas space.

Loading...
src/manifesto/CanvasProvider/CanvasProvider.js

Minimum viable viewer

This is the absolute minimum viewer for IIIF manifest.

Loading...
src/manifesto/LocaleString/LocaleString.js

Locale String example

This can be used to render a translatable string from Manifesto.

Loading...
src/manifesto/Manifest/Manifest.js

How the components work

Loading a manifest:

(
    <Manifest url={manifests.main}>
        ...
    </Manifest>
)

When you use this component, much like all the other data-driven components, when they parse, load or create resources, they pass them down to their children. There are two ways to access this:

(
    <Manifest url={manifests.main}>
      {({manifest}) => (
         <div>{ manifest.getDefaultLabel() }</div>
      )}
    </Manifest>
)

The first way is by passing a function as the children. This allows you to explicitly get the manifest variable (or whatever the module provides), and pass it down to child components as you need to.

The second way is to simple add children element:

class MyAwesomeComponent extends React.Component {
  render() {
    const {manifest} = this.props;
    return (
      <div>{manifest.getDefaultLabel()}</div>
    );
  }
}
(
    <Manifest url={manifests.main}>
      <MyAwesomeComponent />
    </Manifest>
)

In this example, because MyAwesomeComponent is a direct child, it will automatically get the manifest variable.

This is a common pattern through the prototype. It allows you to create, manipulate contexts and pass them through to custom components to create UIs.

src/manifesto/ManifestThumbnails/ManifestThumbnails.js

Returns all thumbnails from the manifest.

Loading...
src/manifesto/RangeNavigationProvider/RangeNavigationProvider.js

The range navigation provider allows you to track navigating a manifest based on a range.

Loading...

Presentation 3 examples

  • id: https://digirati.com/balenciaga3/c1
  • range: https://digirati.com/balenciaga3/sequence
  • Index: 0
src/manifesto/SearchProvider/SearchProvider.js

Search provider example

Loading...

viewers something something

src/viewers/FullPageViewport/FullPageViewport.js

This viewport can be used to fill the whole screen (position fixed) or an entire container (position absolute). This can be changed in the properties. You can also make the image non-interactive, so you can control wht the viewport shown is.

Loading...
src/viewers/OpenSeadragonViewer/OpenSeadragonViewer.js

Simple example

Loading...
src/viewers/OpenSeadragonViewport/OpenSeadragonViewport.js
src/viewers/SizedViewport/SizedViewport.js
src/viewers/StaticImageViewport/StaticImageViewport.js

Example with single image.

Static image viewport.

Loading...

Example P3 manifest

src/viewers/Viewport/Viewport.js

Viewport is how you control, or hand over control of the viewport for viewing IIIF resources.

In this example, Viewport is built as the size of the IIIF resource and scaled to fit the maxWidth. Control over the size and position of the viewport is then passed to OpenSeadragon, so when it moves, any other layers under the viewport get updated and sync. So the annotations in this example are follow the OpenSeadragon image.

Loading...

Important note: All children of viewport must declare their ratio if it is to be scaled less than 1. This allows the viewport to correctly scale content. So if you are wrapping another component that is scaled, you need to define the ratio prop.

<Viewport maxWidth={500}>
- <div>
+ <div ratio={0.1}>
    <CanvasRepresentation ratio={0.1}>
      ...
    </CanvasRepresentation>
  </div>
</Viewport>

Example P3 OpenseaDragon

hello components

src/components/Annotation/Annotation.js
src/components/AnnotationCanvasRepresentation/AnnotationCanvasRepresentation.js
src/components/AnnotationDetail/AnnotationDetail.js

Simple annotation details demo, clicking on an annotation will show a popup box with content customised for this particular manifest. This could however be expanded greatly into a general purpose annotation reading tool.

Loading...
Click annotation to see more.

p3 Example

Click annotation to see more.
src/components/AnnotationRepresentation/AnnotationRepresentation.js
src/components/AnnotationResizers/AnnotationResizers.js
src/components/Bem/Bem.js
src/components/CanvasNavigation/CanvasNavigation.js

Next and previous

The only controls currently

Loading...
src/components/CanvasRepresentation/CanvasRepresentation.js

Example canvas representation with manual annotations.

Loading...
src/components/EditableAnnotation/EditableAnnotation.js

Editable annotation bounding box example, demonstrates the drag and drop and resize functionality, which works with both, mouse and touch devices.

Loading...
Annotation:
x: 100.33
y: 100.33
height: 200.66
width: 200.33

Custom box styles

Custom box styles can be passed to the EditableAnnotation component using boxStyles property. The standard className attribute also available.

Loading...

Adding annotations dynamically

Loading...
src/components/Fullscreen/Fullscreen.js

Demo of the fullscreen component

Testing full screen

Lots of text

Lots of text

Lots of text

Not full screen

Not full screen

Not full screen

Advanced use

Fullscreen works well with other components. You can create canvas representations that look and act differently in full screen. This is a lengthy example, but demonstrates a more complex use case. We are also making use of the FullPageViewport in this example too, which by default fills up all the available space.

In this example, we are rendering a static image, prompting the user to click which opens a fullscreen OSD viewer. This is useful on mobile where it won't interfere with touch events.

Loading...
src/components/ObservableElement/ObservableElement.js

The observable element allows you to update the props to an element from a non-react source, while still being efficient with rendering and not throwing away the whole tree every time. This is used in plugins for custom HTML attributes that make the plugins function like HTML web components, observing the data properties.

Counter: 1
src/components/SearchResultsRepresentation/SearchResultsRepresentation.js
src/components/SingleTileSource/SingleTileSource.js

Example image

Example image.

Loading...

Example tile source string

This example grabs the tile source id that can be passed down to other components like OSD viewer.

Loading...

Presentation 3 manifest

Image Uri:
[]
src/components/ThumbnailList/ThumbnailList.js

Plain thumbnail list

Loading...

Vertical thumbnail list

Loading...

Do not center selected thumbnail

Loading...

Slideshow with thumbnail list

Loading...

Vertical 2 columns thumbnail list

Loading...