[ui] image annotation via Annotorious
exact structure in upend might changefeat/vaults
parent
950d026f1e
commit
08386052df
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue