Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to @iiif/helpers from Vault + new Atlas version. #237

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
546 changes: 346 additions & 200 deletions docs/api-reference/vault.md

Large diffs are not rendered by default.

121 changes: 78 additions & 43 deletions docs/examples/10-handling-choice.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,50 +4,77 @@ sidebar_position: 10

# Handling Choice

import { GitHubDiscussion } from "../../GitHubDiscussion.js";
import choicesReactSandbox from '@site/sandboxes/choices-react.csb/_load';
import simpleChoice from '@site/sandboxes/10-choices/simpleChoice.csb/_load';
import choice1 from '@site/sandboxes/10-choices/choice1.csb/_load';
import { Sandbox } from '@site/Sandbox';

A Canvas have have multiple images. Sometimes, they are all a part of the scene to be rendered and the developer doesn't have to do anything extra - Canvas Panel will just render the scene.

But sometimes, the multiple images form a set of choices, for the user to pick from. Multispectral images are an example of this.

For further details on this scenario, see the IIIF Cookbook [Choice example](https://preview.iiif.io/cookbook/3333-choice/recipe/0033-choice/). (TODO - replace with published link)

You don't necessarily need to know in advance that the Canvas has resources with Choice for something to render. In simple scenarios, you might not need to know, because there's nothing you can do about it anyway: let canvas panel make a sensible default choice, because anything more means you need to provide _more_ user interface to deal with the user making one or more choices. At the other end, your app might be sophisticated and allow blending of layers, e.g., to view multispectral captures of paintings.

For the more sophisticated UI, you need to react to the presence of one or more Choices on the canvas. You need to know what choices are available - their labels, ids and their "stacking" order.

You can then render UI for offering the choices to the user - and react to that choice by telling Canvas Panel to update the scene to reflect changes. Your UI component might be _bound_ to Canvas Panel.

You might also support blending: "Show the choice with id xxx at 80% opacity AND show the choice with id yyy at 50% opacity, all the others are at 0%".

Usually, if Choice is present at all, it's only one set of choices, for the whole canvas. But it's possible for a scene to be made of multiple content resources each of which have their own set of choices.
import { GitHubDiscussion } from "../../GitHubDiscussion.js"; import
choicesReactSandbox from '@site/sandboxes/choices-react.csb/\_load'; import
simpleChoice from '@site/sandboxes/10-choices/simpleChoice.csb/\_load'; import
choice1 from '@site/sandboxes/10-choices/choice1.csb/\_load'; import { Sandbox }
from '@site/Sandbox';

A Canvas have have multiple images. Sometimes, they are all a part of the scene
to be rendered and the developer doesn't have to do anything extra - Canvas
Panel will just render the scene.

But sometimes, the multiple images form a set of choices, for the user to pick
from. Multispectral images are an example of this.

For further details on this scenario, see the IIIF Cookbook
[Choice example](https://preview.iiif.io/cookbook/3333-choice/recipe/0033-choice/).
(TODO - replace with published link)

You don't necessarily need to know in advance that the Canvas has resources with
Choice for something to render. In simple scenarios, you might not need to know,
because there's nothing you can do about it anyway: let canvas panel make a
sensible default choice, because anything more means you need to provide _more_
user interface to deal with the user making one or more choices. At the other
end, your app might be sophisticated and allow blending of layers, e.g., to view
multispectral captures of paintings.

For the more sophisticated UI, you need to react to the presence of one or more
Choices on the canvas. You need to know what choices are available - their
labels, ids and their "stacking" order.

You can then render UI for offering the choices to the user - and react to that
choice by telling Canvas Panel to update the scene to reflect changes. Your UI
component might be _bound_ to Canvas Panel.

You might also support blending: "Show the choice with id xxx at 80% opacity AND
show the choice with id yyy at 50% opacity, all the others are at 0%".

Usually, if Choice is present at all, it's only one set of choices, for the
whole canvas. But it's possible for a scene to be made of multiple content
resources each of which have their own set of choices.

## Simple scenario - known choice

<!-- TODO: GH-106 -->

```html
<canvas-panel iiif-content="http://example.org/canvas-1.json" choice-id="http://example.org/choice-1" />
<canvas-panel
iiif-content="http://example.org/canvas-1.json"
choice-id="http://example.org/choice-1"
/>
```

<Sandbox stacked project={choice1} />


Here the value of `choice-id` is the `id` of the content resource within a set of choices. You don't need to specify which set of choices, in the rare event that there is more than one - although you can specify more than one value:
Here the value of `choice-id` is the `id` of the content resource within a set
of choices. You don't need to specify which set of choices, in the rare event
that there is more than one - although you can specify more than one value:

```html
<canvas-panel iiif-content="http://example.org/canvas-1.json"
choice-id="http://example.org/choice-set-a/3, http://example.org/choice-set-b/7" />
<canvas-panel
iiif-content="http://example.org/canvas-1.json"
choice-id="http://example.org/choice-set-a/3, http://example.org/choice-set-b/7"
/>
```

## Before loading

Before you put the `<canvas-panel />` web component on a page, you can first load the manifest into the vault, find out if there is a choice and render a UI.
Before you put the `<canvas-panel />` web component on a page, you can first
load the manifest into the vault, find out if there is a choice and render a UI.

In this example, the "choice" event is fired when Canvas Panel detects that a Choice is present on the rendered Canvas.
In this example, the "choice" event is fired when Canvas Panel detects that a
Choice is present on the rendered Canvas.

:::tip

Expand All @@ -57,37 +84,42 @@ The choice event may be fired multiple times as Canvas Panel loads

<Sandbox project={simpleChoice} />

Canvas panel also has the additional helpers for scenarios where you don't want to react to the choice event:
Canvas panel also has the additional helpers for scenarios where you don't want
to react to the choice event:

```js
cp.setDefaultChoiceIds(ids);
cp.makeChoice(id, options)
cp.makeChoice(id, options);
```

And you can render a choice directly, with opacity, via attributes (e.g., if generating the markup on the server):
And you can render a choice directly, with opacity, via attributes (e.g., if
generating the markup on the server):

```html
<canvas-panel iiif-content="http://example.org/canvas-1.json" choice-id="http://example.org/choice-1#opacity=0.5" />
<canvas-panel
iiif-content="http://example.org/canvas-1.json"
choice-id="http://example.org/choice-1#opacity=0.5"
/>
```

## Choice React Example

This is a more realistic use of Canvas Panel's choice-handling capability:


<Sandbox project={choicesReactSandbox} />


## Additional choice helper API

There is an additional helper that can be used to extract choices.

```js
import { createPaintingAnnotationsHelper } from '@iiif/vault-helpers';
import { createPaintingAnnotationsHelper } from "@iiif/helpers";

const helper = createPaintingAnnotationsHelper(element.vault);
const choice = helper.extractChoices("http://example.org/manifest/canvas-1.json");
// Choice looks like this:
const choice = helper.extractChoices(
"http://example.org/manifest/canvas-1.json"
);
// Choice looks like this:
// {
// type: 'single-choice';
// label?: InternationalString;
Expand All @@ -99,19 +131,22 @@ const choice = helper.extractChoices("http://example.org/manifest/canvas-1.json"
// }
```

You might want to analyse the canvas even earlier, to decide what UI to render. You need to ensure that the Manifest
is loaded before you extract the choices for your canvas.
You might want to analyse the canvas even earlier, to decide what UI to render.
You need to ensure that the Manifest is loaded before you extract the choices
for your canvas.

Using this helper gives complete flexibility over choices at the data level, and can happen before anything is rendered to the user.
Using this helper gives complete flexibility over choices at the data level, and
can happen before anything is rendered to the user.

Since the `choice-id` attribute also drives the users choice, I could do the following to manually set the choice ID.
Since the `choice-id` attribute also drives the users choice, I could do the
following to manually set the choice ID.

```js
element.setAttribute('choice-id', 'http://example.org/choice-1')
element.setAttribute("choice-id", "http://example.org/choice-1");

// or even

element.setAttribute('choice-id', 'http://example.org/choice-1#opacity=20')
element.setAttribute("choice-id", "http://example.org/choice-1#opacity=20");
```

<GitHubDiscussion ghid="10" />
130 changes: 73 additions & 57 deletions docs/examples/20-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ sidebar_position: 20

# Styling

import externalStylesheet from '@site/sandboxes/external-stylesheet.csb/_load';
import opacity from '@site/sandboxes/20-styling/opacity.csb/_load';
import opacity2 from '@site/sandboxes/20-styling/opacity2.csb/_load';
import flexbox from '@site/sandboxes/01-show-canvas/flexbox.csb/_load';
import { Sandbox } from '@site/Sandbox';
import externalStylesheet from '@site/sandboxes/external-stylesheet.csb/\_load';
import opacity from '@site/sandboxes/20-styling/opacity.csb/\_load'; import
opacity2 from '@site/sandboxes/20-styling/opacity2.csb/\_load'; import flexbox
from '@site/sandboxes/01-show-canvas/flexbox.csb/\_load'; import { Sandbox }
from '@site/Sandbox';

Comment on lines +7 to 12
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: fix. Looks like the automatic linting wrecked this (and a few more)

<!-- Stephen
Needs a really good example of how to make it stick to 4 sides of container
Expand All @@ -19,33 +19,37 @@ A discussion of styling quirks
You can also style image services using their image service ID (no canvas ID)
-->

There are 3 types of object you can style:
There are 3 types of object you can style:

* Canvases
* Annotation pages
* Annotations
- Canvases
- Annotation pages
- Annotations

As there is no representation of an Annotation Page in the viewer, this style is used as a cascade for styling
annotations. Any styles applied to annotation pages will be applied to annotations inside. This allows you to style
full sets of annotations at once.
As there is no representation of an Annotation Page in the viewer, this style is
used as a cascade for styling annotations. Any styles applied to annotation
pages will be applied to annotations inside. This allows you to style full sets
of annotations at once.

Canvases only support opacity. Annotations support box styles, but may also have custom CSS applied to them.
Canvases only support opacity. Annotations support box styles, but may also have
custom CSS applied to them.

Styles can be applied either by using a **vault helper** or by using a property from the web component. If you use the
Vault helper you can apply styles prior to rendering your canvas panel. If you use the Vault Helper you should ensure
Styles can be applied either by using a **vault helper** or by using a property
from the web component. If you use the Vault helper you can apply styles prior
to rendering your canvas panel. If you use the Vault Helper you should ensure
that you pass in a scope of `atlas` as the 3rd argument.

## Box styles

There are currently a subset of styles that can be applied to annotations that will be rendered using the HTML canvas
if that is available. This will improve performance if you have large numbers of annotations being displayed - such
as OCR annotations.
There are currently a subset of styles that can be applied to annotations that
will be rendered using the HTML canvas if that is available. This will improve
performance if you have large numbers of annotations being displayed - such as
OCR annotations.

```ts
cp.applyStyles(annotationPage, {
backgroundColor: 'rgba(255, 0, 0, 0.5)',
border: '3px solid blue',
outline: '3px solid #000',
backgroundColor: "rgba(255, 0, 0, 0.5)",
border: "3px solid blue",
outline: "3px solid #000",
opacity: 0.5,
});
```
Expand Down Expand Up @@ -74,63 +78,73 @@ interface BoxStyles {

### States

You can set hover and active states, that support all the above properties. This can be used to create some basic
interactivity for your annotations. These should be enough for most cases and avoid de-optimising and using CSS classes
You can set hover and active states, that support all the above properties. This
can be used to create some basic interactivity for your annotations. These
should be enough for most cases and avoid de-optimising and using CSS classes
directly.

```ts
cp.applyStyles(annotationPage, {
backgroundColor: 'rgba(255, 0, 0, 0.5)',
':hover': {
backgroundColor: 'rgba(255, 0, 0, 1)',
backgroundColor: "rgba(255, 0, 0, 0.5)",
":hover": {
backgroundColor: "rgba(255, 0, 0, 1)",
},
':active': {
backgroundColor: 'blue',
":active": {
backgroundColor: "blue",
},
});
```

### Vault helper

If you decide to use [Vault helpers](https://github.com/IIIF-Commons/vault-helpers) you will need to ensure you pass
in the correct scope when you apply styles.
If you decide to use
[Vault helpers](https://github.com/IIIF-Commons/vault-helpers) you will need to
ensure you pass in the correct scope when you apply styles.

```ts
import { createStyleHelper } from '@iiif/vault-helpers';
import { globalVault } from '@iiif/vault';
import { createStyleHelper } from "@iiif/helpers";
import { globalVault } from "@iiif/helpers/vault";

const helper = createStyleHelper(globalVault());

// For box styles.
helper.applyStyle(annotation, {
background: 'red'
}, 'atlas');
helper.applyStyle(
annotation,
{
background: "red",
},
"atlas"
);

// For setting a class name
helper.applyStyle(annotation, {
className: 'my-custom-style',
}, 'html');
helper.applyStyle(
annotation,
{
className: "my-custom-style",
},
"html"
);
```


### Quirks
Some quirks of the box style.

* You can only use solid borders and outlines
* Box-sizing is fixed to content-box (so annotations may be shifted by borders)
* Some styles may not match exactly
Some quirks of the box style.

- You can only use solid borders and outlines
- Box-sizing is fixed to content-box (so annotations may be shifted by borders)
- Some styles may not match exactly

## CSS Styles

If you would like to add more styles than these options you can set a custom class name instead.
If you would like to add more styles than these options you can set a custom
class name instead.

```ts
cp.setClassName(annotationPage, 'my-custom-class');
cp.setClassName(annotationPage, "my-custom-class");
```

Canvas panel exists in a web-component, so styles will not work out of the box. You have 3 options for applying
styles.
Canvas panel exists in a web-component, so styles will not work out of the box.
You have 3 options for applying styles.

**1. Using `::part()`, which must be used instead of `.my-custom-class`**

Expand Down Expand Up @@ -163,28 +177,30 @@ styles.

## Styling with FlexBox

To demonstrate how canvas panel can flex to fill its container, it's best to open this demo in the code sandbox and then open the preview in a new window.
To demonstrate how canvas panel can flex to fill its container, it's best to
open this demo in the code sandbox and then open the preview in a new window.

<Sandbox project={flexbox} />

## Opacity

You can set the opacity of resources via their `id`. In this case, the `id` of the image resource that is the body of the painting annotation:
You can set the opacity of resources via their `id`. In this case, the `id` of
the image resource that is the body of the painting annotation:

<Sandbox project={opacity2} />

You can also set the opacity of a particular item within a Choice:

```html
<canvas-panel
iiif-content="http://example.org/canvas-1.json"
choice-id="http://example.org/choice-set-a/3, http://example.org/choice-set-b/7#opacity=0.5"
/> Useful for static rendering -----^
<canvas-panel
iiif-content="http://example.org/canvas-1.json"
choice-id="http://example.org/choice-set-a/3, http://example.org/choice-set-b/7#opacity=0.5"
/>
Useful for static rendering -----^
Comment on lines -179 to +199
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: fix

```

<Sandbox project={opacity} />

Tile rendering is not as optimised when applying opacity. Canvas Panel does not layer multiple tiles when zooming - just one layer of tiles, so no nice blending, otherwise you'd see through to the fallback layers with the opacity.



Tile rendering is not as optimised when applying opacity. Canvas Panel does not
layer multiple tiles when zooming - just one layer of tiles, so no nice
blending, otherwise you'd see through to the fallback layers with the opacity.
Loading