Rasterex APINPM Package/docs/components/measurement/creation

Annotation Events

Listen for annotation creation, selection, and deletion events emitted by Canvas using the SDK.

Overview

Use viewer.annotations.on(...) to listen for annotation creation, selection, and deletion events emitted by Canvas.

Annotation event subscriptions can be registered after the viewer is created. They connect to Canvas once ready:

typescript
import { createViewer } from "@rasterex/viewer";

const viewer = createViewer({
  container: "#viewer"
});

const stopCreated = viewer.annotations.on("created", (event) => {
  console.log(event.guid);
});

await viewer.mount();
await viewer.ready();
Overview

Supported Events

Register listeners for these key SDK events:

  • created: Normalized annotation created events.
  • createdWithDetail: Detailed/raw annotation creation events.
  • selected: Normalized selection events.
  • selectedWithDetail: Detailed/raw selection events.
  • deleted: Normalized deletion events.
  • deletedWithDetail: Detailed/raw deletion events.
typescript
const stopCreated = viewer.annotations.on("created", (event) => {
  console.log("Created GUID:", event.guid);
});

const stopSelected = viewer.annotations.on("selected", (event) => {
  console.log("Selected GUID:", event.guid);
});

// To clean up:
stopCreated();
stopSelected();
Supported Events

Event Payload Shape

Every annotation event has the following SDK shape:

typescript
type AnnotationEvent = {
  guid: string;
  data: AnnotationNormalizedData | Record<string, unknown> | string;
  dbUniqueID: unknown | null;
  source: "current-canvas";
  detail: "normalized" | "raw";
};
Event Payload Shape

Normalized vs Detail Events

Use normalized events for standard UI workflows, and detail events for raw RxCore markup data:

typescript
// Normalized properties
viewer.annotations.on("created", (event) => {
  console.log(event.data);
});

// Raw RxCore details
viewer.annotations.on("createdWithDetail", (event) => {
  console.log(event.data);
});
Normalized vs Detail Events

Vanilla Example

Complete integration code setup for Vanilla HTML/JS environments:

<div id="viewer" style="height: 640px"></div>
<div>
  <button type="button" id="freehand-tool">Freehand</button>
</div>
<ol id="annotation-log"></ol>
Vanilla Example

React Integration

Complete React Component implementation details:

tsx
import { useEffect, useRef, useState } from "react";
import { createViewer, type RasterexViewer, type ToolAction } from "@rasterex/viewer";

type LogItem = {
  id: number;
  message: string;
};

export function AnnotationEvents() {
  const hostRef = useRef<HTMLDivElement | null>(null);
  const viewerRef = useRef<RasterexViewer | null>(null);
  const [activeTool, setActiveTool] = useState<ToolAction | null>(null);
  const [log, setLog] = useState<LogItem[]>([]);

  useEffect(() => {
    let disposed = false;
    let nextId = 1;
    const viewer = createViewer({ container: hostRef.current! });
    viewerRef.current = viewer;

    function addLog(message: string) {
      setLog((items) => [{ id: nextId++, message }, ...items]);
    }

    const stopCreated = viewer.annotations.on("created", (event) => {
      if (!disposed) {
        setActiveTool(null);
        addLog(`Created ${event.guid}`);
      }
    });

    const stopSelected = viewer.annotations.on("selected", (event) => {
      if (!disposed) {
        addLog(`Selected ${event.guid}`);
      }
    });

    const stopDeleted = viewer.annotations.on("deleted", (event) => {
      if (!disposed) {
        addLog(`Deleted ${event.guid}`);
      }
    });

    async function start() {
      await viewer.mount();
      await viewer.ready();
      await viewer.documents.open({
        url: "https://files.example.com/sample.pdf",
        displayName: "Sample PDF.pdf"
      });
    }

    void start().catch((error) => {
      if (!disposed) {
        addLog(error instanceof Error ? error.message : "Viewer failed");
      }
    });

    return () => {
      disposed = true;
      stopCreated();
      stopSelected();
      stopDeleted();
      viewer.destroy();
      viewerRef.current = null;
    };
  }, []);

  async function enableTool(action: ToolAction) {
    await viewerRef.current?.tools.set({ action, enabled: true });
    setActiveTool(action);
  }

  return (
    <section>
      <div ref={hostRef} style={{ height: 640 }} />
      <div>
        <button type="button" onClick={() => void enableTool("TEXT")}>Text</button>
        <button type="button" onClick={() => void enableTool("PAINT_FREEHAND")}>Freehand</button>
      </div>
      <ol>
        {log.map((item) => (
          <li key={item.id}>{item.message}</li>
        ))}
      </ol>
    </section>
  );
}
React Integration

Canvas Broker Mapping

Broker message mapping for annotation events:

  • viewer.annotations.on("created", ...) listens to annotationCreated.
  • viewer.annotations.on("selected", ...) listens to annotationSelected.
  • viewer.annotations.on("deleted", ...) listens to annotationDeleted.