Data format
Data format
One versioned JSON document, with coordinates in percent. It travels as HTML too, and bad input fails in a known way.
The document
serializeAnnotations writes one JSON document with a version and a list. Store it as it is. This one is the package's own output for three marks.
{
"version": 1,
"annotations": [
{"kind":"area","box":[8,12,30,34],"label":"Bands too tight"},
{"kind":"pointer","point":[74,24],"label":"Keep this orange","side":"auto"},
{"kind":"marker","point":[24,62],"text":"Lift the <strong>blue</strong>"}
]
}Coordinates
Every number is a percentage of the image, from 0 to 100, rounded to one decimal. A box is left, top, width and height. A line runs from x1, y1 to x2, y2, and an arrow points at its second end. A point is x and y. Because nothing is in pixels, the same document fits a thumbnail and a full-width image.
HTML transport
annotationsToHtml writes the marks as an ordered list, which survives a rich text editor, a CMS field or an email. annotationsFromHtml reads them back. Marker text keeps only strong, em and code.
<ol data-annotations>
<li data-kind="area" data-box="8 12 30 34">Bands too tight</li>
<li data-kind="pointer" data-point="74 24">Keep this orange</li>
<li data-kind="marker" data-point="24 62">Lift the <strong>blue</strong></li>
</ol>Validation
parseAnnotations throws when the whole document is wrong, and drops single marks it cannot read. Out-of-range numbers are clamped. Each result below is what the package returns for that input.
| Input | Result |
|---|---|
{ version: 2, annotations: [] } | throws RangeError: Unsupported annotation version. |
"{ not json" | throws SyntaxError |
42 | throws TypeError: Annotations must be an array or a versioned annotation document. |
[{ kind: "area", box: [10, 20] }] | [] |
[{ kind: "pointer", point: [50, 50] }] | [] |
[{ kind: "area", box: [-5, 20, 140, 30], label: "Edge" }] | [{"kind":"area","box":[0,20,100,30],"label":"Edge"}] |
[{ kind: "marker", point: [40, 40], text: "<b onclick=…>Lift</b> it" }] | [{"kind":"marker","point":[40,40],"text":"<strong>Lift</strong> it"}] |
In code
import {
annotationsFromHtml,
annotationsToHtml,
parseAnnotations,
serializeAnnotations,
} from "@reuse-sh/annotations";
// Load. An unknown version throws, invalid marks are dropped.
const marks = parseAnnotations(await db.get("proof-3"));
// Store
await db.put("proof-3", serializeAnnotations(marks));
// Send as HTML, for an editor or an email, and read it back.
const html = annotationsToHtml(marks);
const again = annotationsFromHtml(element);import { parseAnnotations, serializeAnnotations } from "@reuse-sh/annotations";
import { AnnotationEditor } from "@reuse-sh/annotations/react";
export function StoredProof({ stored, onSave }) {
const [annotations, setAnnotations] = useState(() => parseAnnotations(stored));
return (
<AnnotationEditor
{...image}
annotations={annotations}
onChange={(next) => {
setAnnotations(next);
onSave(serializeAnnotations(next));
}}
/>
);
}