Skip to content

Annotation Data Model

At the core of Annotorious is a flexible data model that closely aligns with the W3C Web Annotation Data Model, but with a few key differences to optimize for performance and ease of use.

Anatomy of an Annotation

Every annotation in Annotorious is represented by a JavaScript object with the following structure:

{
id: '7fb76422-3a8c-4c87-bbad-7c8bb68399a0',
target: {
selector: {
type: 'RECTANGLE',
geometry: {
bounds: {
minX: 272,
minY: 169,
maxX: 393,
maxY: 259
},
x: 272,
y: 169,
w: 121,
h: 90,
}
}
}
}
  • id - a unique identifier for the annotation. The ID can be any alphanumeric string. If you provide an annotation without ID, Annotorious will automatically assign a globally unique UUID on load. Annotations created by users will also receive a UUID automatically.

  • target - the target represents the part of the image that the annotation is associated with. In this example, the selector specifies that the annotation is a rectangle with the given coordinates and dimensions.

  • bounds - represents the bounding box of the annotation, useful for quick calculations without parsing the entire geometry.

Here’s another example for a polygon annotation, where the geometry object contains a list of X/Y points.

{
id: '64d7dda8-c156-4e1e-a4f9-55192399208b',
target: {
selector: {
type: 'POLYGON',
geometry: {
bounds: {
minX: 60,
minY: 88,
maxX: 248,
maxY: 223
},
points: [
[60, 221],
[136, 88],
[248, 148],
[172, 223]
]
}
}
}
}

Annotation Bodies

In addition to the target, annotations can also have one or more bodies. Annotation bodies are designed to carry application-specific payload, such as comments, tags, or other metadata associated with the annotation.

It’s important to note that Annotorious does not process or display body information directly. Instead, bodies serve as an extensible data structure that you can use according to your application’s needs, e.g. to drive info popups, hover tooltips, or data-driven filters and styles.

{
id: '64d7dda8-c156-4e1e-a4f9-55192399208b',
bodies: [{
id: '3f4d0a8c-803a-4e59-ad0b-20c82d87c815',
purpose: 'commenting',
value: 'This is a comment'
}],
target: {
// ...
}
}

The structure of bodies in Annotorious is closely aligned with the W3C Web Annotation bodies, with a few small differences and simplifications.

  • id: any alphanumeric string. If you provide a body without an ID, Annotorious will automatically assign a UUID on load.
  • purpose: used similarly to the W3C model, identifying the reason for the inclusion of the body in the annotation.
  • value: a generic field that you can use according to your application’s needs.

Other optional fields include:

  • creator: the user who created the body.
  • created: the creation timestamp of the body.
  • updatedBy: the user who last updated the body.
  • updated: stores the last update timestamp of the body.

Leveraging Bodies in Your Application

While Annotorious provides the structure for the bodies, it’s up to you as the developer to decide how to use them. Here are some ways to leverage annotation bodies:

  1. Custom popups: display body information when users interact with annotations. This could include showing comments, tags or metadata in a tooltip or sidebar.
  2. Data-driven styles: use body properties for dynamic styling. For example:
    • Apply different styles based on the purpose, e.g. different colors for commenting vs. tagging.
    • Use the value of tagging bodies to color-code annotations based on labels.
  3. Data-driven filters: filter annotations dynamically, based on body properties such as purpose, creator or updated timestamp.
  4. Application-Specific Metadata: store any additional metadata your application needs in the value field, or by adding your own properties to the body object.

Annotorious provides a number of helpers and utility functions to simplify these scenarios. To read more, see documentation on:

Key Differences from the W3C Model

While the Annotorious model shares similarities with the W3C Web Annotation Data Model, there are key differences designed to enhance performance and simplify usage when building web applications:

  1. Simplified Structure: Annotorious makes no claim to support the full range of the extensive W3C Web Annotation standard. Annotorious streamlines the annotation structure to focus on the essential elements that it implements, while staying close enough to the W3C model to make crosswalking as easy as possible.

  2. Optimized for Performance: the model prioritizes performance by having explicit representations for shape geometry, thus avoiding the need to repeatedly parse and serialize the selectors from and to the W3C model’s string-based representations. For example, Annotorious uses direct coordinate values instead of SVG path strings, allowing for faster rendering and manipulation of annotations.

  3. Ease of Use: Annotorious aims to be intuitive and easy to use, with a focus on providing a smooth developer experience. Whereas the W3C model is designed to be more general-purpose, Annotorious’ restricted use case allows it to make certain assumptions and simplifications.

The W3C Adapter

Despite the differences, Annotorious also provides a built-in feature that allows you to use W3C Web annotations directly, through a utility called the W3CImageAdapter.

The W3CImageAdapter automatically crosswalks annotations between the W3C- and the Annotorious model, allowing you to use the Annotorious API while still adhering to the W3C standard. Through the adapter, Annotorious offers the best of both worlds - the performance and ease of use of its native data model, with the flexibility to conform to the W3C standard when needed.

The W3CImageAdapter accepts a single constructor argument (type string), which will be used for the source property of the annotation target.

import { createImageAnnotator, W3CImageAdapter } from '@annotorious/annotorious';
import '@annotorious/annotorious/annotorious.css';
const anno = createImageAnnotator('sample-image', {
adapter: W3CImageAdapter('sample-image')
});