[ui] image annotation via Annotorious

exact structure in upend might change
feat/vaults
Tomáš Mládek 2022-02-12 23:23:52 +01:00
parent 950d026f1e
commit 08386052df
No known key found for this signature in database
GPG Key ID: 65E225C8B3E2ED8A
1 changed files with 138 additions and 8 deletions

View File

@ -1,29 +1,159 @@
<script lang="ts">
import type { PutResult } from "upend/types";
import { fetchEntity, useEntity } from "../../../lib/entity";
import Spinner from "../../utils/Spinner.svelte";
export let address: string;
export let editable: boolean;
const { entity } = useEntity(address);
let imageLoaded = false;
let imageEl: HTMLImageElement;
interface Annotorious {
addAnnotation: (a: W3cAnnotation) => void;
on: ((
e: "createAnnotation" | "deleteAnnotation",
c: (a: W3cAnnotation) => void
) => void) &
((
e: "updateAnnotation",
c: (a: W3cAnnotation, b: W3cAnnotation) => void
) => void);
clearAnnotations: () => void;
readOnly: boolean;
}
interface W3cAnnotation {
type: "Annotation";
body: Array<{ type: "TextualBody"; value: string; purpose: "commenting" }>;
target: {
selector: {
type: "FragmentSelector";
conformsTo: "http://www.w3.org/TR/media-frags/";
value: string;
};
};
"@context": "http://www.w3.org/ns/anno.jsonld";
id: string;
}
let anno: Annotorious;
$: if (anno) anno.readOnly = !editable;
$: if (anno) {
anno.clearAnnotations();
$entity?.backlinks
.filter((e) => e.attribute == "ANNOTATES")
.forEach(async (e) => {
const annotation = await fetchEntity(e.entity);
if (annotation.get("W3C_FRAGMENT_SELECTOR")) {
anno.addAnnotation({
type: "Annotation",
body: annotation.attr["LBL"].map((e) => {
return {
type: "TextualBody",
value: String(e.value.c),
purpose: "commenting",
};
}),
target: {
selector: {
type: "FragmentSelector",
conformsTo: "http://www.w3.org/TR/media-frags/",
value: String(annotation.get("W3C_FRAGMENT_SELECTOR")),
},
},
"@context": "http://www.w3.org/ns/anno.jsonld",
id: e.entity,
});
}
});
}
async function loaded() {
imageLoaded = true;
return; // TODO - CRUD for annotations
const { Annotorious } = await import("@recogito/annotorious");
const anno = new Annotorious({
anno = new Annotorious({
image: imageEl,
drawOnSingleClick: true,
fragmentUnit: "percent",
});
console.log(anno);
anno.on("createAnnotation", (annotation) => {
console.log("Created!", annotation);
anno.on("createAnnotation", async (annotation) => {
const lensUuidFetch = await fetch("api/obj", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
entity: {
t: "Uuid",
},
}),
});
const [_, uuid] = (await lensUuidFetch.json()) as PutResult;
await fetch("api/obj", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify([
{
entity: uuid,
attribute: "ANNOTATES",
value: {
t: "Address",
c: address,
},
},
{
entity: uuid,
attribute: "W3C_FRAGMENT_SELECTOR",
value: {
t: "String",
c: annotation.target.selector.value,
},
},
...annotation.body.map((body) => {
return {
entity: uuid,
attribute: "LBL",
value: {
t: "String",
c: body.value,
},
};
}),
]),
});
});
anno.on("updateAnnotation", (annotation, previous) => {
console.log("Updated!", { annotation, previous });
anno.on("updateAnnotation", async (annotation) => {
const annotationObject = await fetchEntity(annotation.id);
await Promise.all(
annotationObject.attr["LBL"].map(async (e) => {
fetch(`api/obj/${e.address}`, { method: "DELETE" });
})
);
await fetch("api/obj", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(
annotation.body.map((body) => {
return {
entity: annotation.id,
attribute: "LBL",
value: {
t: "String",
c: body.value,
},
};
})
),
});
});
anno.on("deleteAnnotation", (annotation) => {
console.log("Deleted!", annotation);
anno.on("deleteAnnotation", async (annotation) => {
await fetch(`api/obj/${annotation.id}`, {
method: "DELETE",
});
});
}
</script>