Skip to main content

Styling

There are 3 types of object you can style:

  • 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.

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 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.

cp.applyStyles(annotationPage, {
backgroundColor: 'rgba(255, 0, 0, 0.5)',
border: '3px solid blue',
outline: '3px solid #000',
opacity: 0.5,
});

Full list of properties:

interface BoxStyles {
backgroundColor: string; // colour or gradient function
opacity: number;
borderColor: string;
borderWidth: string;
borderStyle: string; // 'solid' only
outlineColor: string;
outlineWidth: string;
outlineOffset: string;
outlineStyle: string; // 'solid' only

// Parsed.
boxShadow: string;
border: string; // 'solid' only
outline: string; // 'solid' only
background: string; // Alias for `backgroundColor:`
}

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 directly.

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

Vault helper

If you decide to use Vault helpers you will need to ensure you pass in the correct scope when you apply styles.

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

const helper = createStyleHelper(globalVault());

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

// For setting a class name
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

CSS Styles

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

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.

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

<style>
canvas-panel::part(my-custom-class) {
background: red;
}
</style>

2. Using style-id, where you can use normal CSS classses.

<style id="my-style">
.my-custom-class {
background: red;
}
</style>
<canvas-panel style-id="my-style"></canvas-panel>

3. Using an external stylesheet (where you can use normal CSS classes)

<canvas-panel stylesheet="https://example.org/styles.css"></canvas-panel>
<canvas-panel
  preset="zoom"
  manifest-id="https://gist.githubusercontent.com/stephenwf/19e61dac5c329c77db8cf22fe0366dad/raw/04971529e364063ac88de722db786c97e2df0e6b/manifest.json"
  canvas-id="https://preview.iiif.io/cookbook/3333-choice/recipe/0036-composition-from-multiple-images/canvas/p1"
  highlight="3526,911,2003,1398"
  highlight-css-class="my-annotation"
  stylesheet="https://stephenwf.github.io/anno.css"
/>

<!-- try changing highlight-css-class to
  "my-blue-annotation" or "my-green-annotation" -->

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.

html,
body {
  margin: 0;
  height: 100%;
}

body {
  display: flex;
}

canvas-panel {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0; /* Required for downsizing */

  --atlas-container-flex: 1 1 0px;
  --atlas-background: #9b6631;
}

.resize {
  resize: both;
  overflow: auto;
  padding: 30px;
  margin: 30px;
  min-width: 0;
  width: 100%;
  display: flex;
}

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:

import "@digirati/canvas-panel-web-components";
import "./styles.css";

// There are three painting annotations on this canvas, the ids of the image resources are:
const image1 =
  "https://dlc.services/iiif-img/7/6/1715f43d-b997-45d2-a5a5-d8a080d4c604/full/full/0/default.jpg";
const image2 =
  "https://dlc.services/iiif-img/7/9/989806db-4e6c-4b08-a47c-79a36c1c1acf/full/full/0/default.jpg";
const image3 =
  "https://dlc.services/iiif-img/7/9/2e519ba0-c6c5-4892-9f36-d96873514630/full/full/0/default.jpg";

const cp = document.getElementById("cp");

// Try swapping image1, image2, image3
cp.applyStyles(image2, { opacity: 0.5 });

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

<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 id="cp2"
  manifest-id="https://preview.iiif.io/cookbook/3333-choice/recipe/0033-choice/manifest.json"
  canvas-id="https://preview.iiif.io/cookbook/3333-choice/recipe/0033-choice/canvas/p1"
  choice-id="https://iiif.io/api/image/3.0/example/reference/421e65be2ce95439b3ad6ef1f2ab87a9-dee-natural/full/max/0/default.jpg, https://iiif.io/api/image/3.0/example/reference/421e65be2ce95439b3ad6ef1f2ab87a9-dee-xray/full/max/0/default.jpg#opacity=0.5" 
/>     

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.