I was able to adding the Annotorous (v2.7.11) into my ImageGallery Vuejs3 component. Also adding a custom widget as described here (and shown in the example below) was not a problem (apart from the parameter of type any, but that's not the question here). However, I would like to create a more complex widget and for that I would like to create the widget with a Vue component. The main problem I'm facing here is, that Annotorious is expecting the widget as a HTMLDivElement type and the Vue component obviously isn't of this type.
<template>
<div id="my-annotation-toolbar-container"></div>
<img id="image" v-bind:src="imageUrl" />
</template>
<script lang="ts">
import { Annotorious } from "@recogito/annotorious";
import "@recogito/annotorious/dist/annotorious.min.css";
import Toolbar from "@recogito/annotorious-toolbar";
import SelectorPack from "@recogito/annotorious-selector-pack";
import BetterPolygon from "@recogito/annotorious-better-polygon";
export default defineComponent({
name: "ImageGallery",
props: {
imageUrl: {
type: String,
required: true,
},
},
setup() {
const anno = ref(null);
onMounted(() => {
anno.value = new Annotorious({
image: document.getElementById("image"),
widgets: [colorSelectorWidget, "TAG"],
formatter: colorFormatter,
});
SelectorPack(anno.value, { tools: ["multipolygon"] });
Toolbar(
anno.value,
document.getElementById("my-annotation-toolbar-container")
);
BetterPolygon(anno.value);
});
const colorFormatter = (annotation: any) => {
var highlightBody = annotation.bodies.find(function (b: any) {
return b.purpose == "highlighting";
});
if (highlightBody) return highlightBody.value;
};
const colorSelectorWidget = (args: any) => {
// 1. Find a current color setting in the annotation, if any
var currentColorBody = args.annotation
? args.annotation.bodies.find(function (b: any) {
return b.purpose == "highlighting";
})
: null;
// 2. Keep the value in a variable
var currentColorValue = currentColorBody ? currentColorBody.value : null;
// 3. Triggers callbacks on user action
var addTag = function (evt: any) {
if (currentColorBody) {
args.onUpdateBody(currentColorBody, {
type: "TextualBody",
purpose: "highlighting",
value: evt.target.dataset.tag,
});
} else {
args.onAppendBody({
type: "TextualBody",
purpose: "highlighting",
value: evt.target.dataset.tag,
});
}
};
// 4. This part renders the UI elements
var createButton = function (value: string) {
var button = document.createElement("button");
if (value == currentColorValue) button.className = "selected";
button.dataset.tag = value;
button.style.backgroundColor = value;
button.addEventListener("click", addTag);
return button;
};
var container = document.createElement("div");
container.className = "colorselector-widget";
var button1 = createButton("RED");
var button2 = createButton("GREEN");
var button3 = createButton("BLUE");
container.appendChild(button1);
container.appendChild(button2);
container.appendChild(button3);
return container;
};
return {};
},
});
</script>
<style>
.colorselector-widget {
padding: 5px;
border-bottom: 1px solid #e5e5e5;
}
.colorselector-widget button {
outline: none;
border: none;
display: inline-block;
width: 20px;
height: 20px;
border-radius: 50%;
cursor: pointer;
opacity: 0.5;
margin: 4px;
}
.colorselector-widget button.selected,
.colorselector-widget button:hover {
opacity: 1;
}
svg.a9s-annotationlayer .a9s-annotation.RED .a9s-outer {
stroke: red;
stroke-width: 3;
fill: rgba(255, 0, 0, 0.3);
}
svg.a9s-annotationlayer .a9s-annotation.GREEN .a9s-outer {
stroke: green;
stroke-width: 3;
fill: rgba(0, 255, 0, 0.3);
}
svg.a9s-annotationlayer .a9s-annotation.BLUE .a9s-outer {
stroke: blue;
stroke-width: 3;
fill: rgba(0, 0, 255, 0.3);
}
svg.a9s-annotationlayer .a9s-annotation.RED .a9s-inner,
svg.a9s-annotationlayer .a9s-annotation.GREEN .a9s-inner,
svg.a9s-annotationlayer .a9s-annotation.BLUE .a9s-inner {
fill: transparent;
stroke: none;
}
</style>