Skip to content

Annotation Dialog

The annotation dialog lets users place interactive pins on any image inside the Uhuu Editor — without touching the source image. It opens a full-screen annotation editor where users can add markers, text labels, and callout cards at precise positions.

Why SVG Overlay Instead of Merging Into the Image

Most annotation tools burn annotations directly into a rasterized copy of the image. Uhuu takes a different approach: annotations are rendered as an SVG layer on top of the base image, and saved as structured data.

This matters for three reasons:

Non-destructive editing. Because annotations are a separate data record, not pixels baked into the image, users can always reposition, relabel, recolor, or delete individual pins. Changing the underlying photo does not erase the annotation layout — the pins simply reappear on the new image.

Crisp print output. Uhuu templates produce PDFs. Rasterized annotations degrade at high DPI because they were created at screen resolution. SVG annotations are mathematical shapes — circles, lines, text — that the PDF renderer reproduces at full vector quality at any print size, with no blurring or pixelation.

Annotations are data. The saved payload is a structured JSON record (schema: "uhuu.annotation.v1"), not an image blob. This means annotations can be read, transformed, re-rendered, or exported as a standalone SVG overlay by the template — for instance to composite the base photo and the annotation layer separately during PDF generation.

Annotation Types

The editor has two annotation tools:

Callout

A rich card connected to an anchor point by a line. The most expressive type.

  • Modes: minimal (compact badge) or detailed (full card with title, description, optional icon/image, and stat rows)
  • Connector: a line from the card to the anchor point; can be toggled per callout
  • Visual: attach an icon from the gallery to the card

Badge

A floating text label attached to a point.

  • Variants: pill, rounded, rectangle
  • Sizes: sm, md, lg
  • Modes: fill or outline

Parameters

js
$uhuu.editDialog({
  path: 'page.heroAnnotation',
  type: 'annotation',
  image: 'https://example.com/photo-1200.jpg',
  config: {
    visualGallery: [
      'https://cdn.example.com/icons/hospital.svg',
      'https://cdn.example.com/icons/school.svg',
    ]
  },
  value: payload.page?.heroAnnotation
})
ParameterTypeDescription
typestring'annotation'
pathstringPayload path where annotation data is saved
imagestringURL of the background image shown in the editor. Use a reasonably sized version (e.g. 1200 × 1200px) — not a full-resolution original
config.visualGallerystring[]Optional array of SVG icon URLs shown as selectable tiles in the visual picker. Defaults to a set of Phosphor icons. Pass an empty array to disable
valueobjectCurrent annotation data. If omitted the editor starts empty

Saved Data Format

json
{
  "schema": "uhuu.annotation.v1",
  "annotations": [
    {
      "id": "abc123",
      "type": "callout",
      "anchorX": 42.5,
      "anchorY": 31.0,
      "cardX": 55.0,
      "cardY": 20.0,
      "mode": "detailed",
      "variant": "rounded",
      "color": "#3b82f6",
      "scale": 1,
      "content": {
        "title": "Main entrance",
        "description": "Access from north side",
        "visual": "https://cdn.example.com/icons/building.svg"
      },
      "connector": { "enabled": true }
    },
    {
      "id": "def456",
      "type": "label",
      "x": 68.0,
      "y": 55.5,
      "text": "Parking",
      "variant": "pill",
      "size": "sm",
      "mode": "fill",
      "color": "#0f172a"
    }
  ],
  "annotationSvg": "<svg>…</svg>"
}

All positions (x, y, anchorX/Y, cardX/Y) are percentages (0–100) relative to the image dimensions. annotationSvg is a pre-rendered SVG overlay — use it directly in templates without re-rendering.

Using with ImageBlock

jsx
import { ImageBlock } from 'uhuu-components'

<ImageBlock
  src={imageUrl}
  dialog={buildPageDialog(dataBinding, 'heroImage', { type: 'image' }, heroImage)}
  annotation={buildPageDialog(
    dataBinding,
    'heroImageAnnotation',
    {
      type: 'annotation',
      image: resolveImageSrc(heroImage),
      visualGallery: Object.values(mapIcons)
    },
    page.heroImageAnnotation
  )}
/>

The user sees two separate edit controls on the image block: one for changing the photo, one for editing annotations. Both store at independent payload paths.

Rendering Annotations in Templates

jsx
{page.heroAnnotation?.annotationSvg && (
  <div className="relative">
    <img src={imageUrl} className="w-full h-full object-cover" />
    <div
      className="absolute inset-0"
      dangerouslySetInnerHTML={{ __html: page.heroAnnotation.annotationSvg }}
    />
  </div>
)}

The SVG overlay renders at full vector quality in PDFs — shapes, text, and connector lines stay sharp at any print size.

Notes

  • annotationSvg is only present when at least one annotation exists. Always guard against its absence before rendering.
  • The image URL in the dialog config is the editor background only. The image displayed in the template is managed separately.
  • Positions are percentages, so annotations stay correctly placed if the image block changes size across breakpoints.
  • visualGallery icons must be publicly accessible SVG URLs, not local paths.

Public developer documentation for Uhuu.