How to create a custom Annotorious Widget using a Vue Component?

210 Views Asked by At

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>

0

There are 0 best solutions below