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 provides three annotation tools:
Marker
A pin shape placed at a point on the image. Useful for highlighting specific locations or features.
- Modes:
numbered(auto-increments),fill,outline - Shapes:
circleorrectangle - Sizes:
sm,md,lg
Numbered markers are the most common choice for legend-style annotations (e.g. "1 = Main entrance, 2 = Parking").
Label
A floating text badge attached to a point.
- Variants:
pill,rounded,rectangle - Sizes:
sm,md,lg - Modes:
filloroutline
Use labels when you want inline text visible directly on the image without a separate legend.
Callout
A rich card connected to an anchor point by a line. The most expressive annotation type.
- Modes:
minimal— compact, shows a single initial letter or icondetailed— full card with title, description, optional image thumbnail, and stat rows
- Connector: A line from the card to the anchor point on the image; can be enabled or disabled per callout.
Callouts work well for location maps where each pin needs a label and a short description, or for property photos where specific features are explained.
Parameters
The editDialog call for the annotation dialog accepts:
type: Set to'annotation'.path(string, required): Payload path where the annotation data will be stored.image(string, required): URL of the base image to annotate. Use a reasonably sized version (e.g. 1200×1200) — not an original that may be tens of megabytes. This does not need to match the display URL exactly; it is only shown inside the annotation editor.config.visualGallery(string[], optional): An array of SVG icon URLs shown as selectable icon tiles in the editor's visual picker. When provided, users can attach an icon from the gallery to a marker or callout. Omit if icons are not needed.value(optional): The current annotation data from the payload. If omitted or empty, the editor starts with no annotations.
Saved Data Format
On save, the dialog writes the following structure to path:
{
"schema": "uhuu.annotation.v1",
"annotations": [
{
"id": "abc123",
"type": "marker",
"x": 42.5,
"y": 31.0,
"mode": "numbered",
"variant": "circle",
"size": "md",
"number": 1,
"color": "#ffffff"
},
{
"id": "def456",
"type": "label",
"x": 68.0,
"y": 55.5,
"text": "Main entrance",
"variant": "pill",
"size": "sm",
"mode": "fill",
"color": "#1e293b"
}
],
"annotationSvg": "<svg>…</svg>"
}x and y are percentages (0–100) relative to the image dimensions. annotationSvg is a pre-rendered SVG string of the full annotation layer — ready to use as an overlay image in the template without re-rendering.
Example
Opening the annotation dialog directly
$uhuu.editDialog({
path: 'page.heroAnnotation',
type: 'annotation',
image: 'https://example.com/photos/hero-1200.jpg',
config: {
visualGallery: [
'https://cdn.example.com/icons/hospital.svg',
'https://cdn.example.com/icons/school.svg',
'https://cdn.example.com/icons/bus-stop.svg',
]
},
value: payload.page?.heroAnnotation
});With ImageBlock in a JSX template
When using ImageBlock from uhuu-components, pass the annotation config as the annotation prop. It coexists independently with the dialog prop (which opens the image picker):
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 the annotation overlay. Both store their data at independent payload paths.
Rendering Annotations in the Template
The annotationSvg field in the saved data is a pre-built SVG string you can overlay on the base image directly in the template:
{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>
)}For PDF output, the SVG overlay renders at full vector quality — pin shapes, text labels, and connector lines stay sharp at any print resolution.
Notes
- The
imageURL inside the annotation dialog config is only used as the editor background. The base image displayed in the template comes from a separate field and must be managed independently. annotationSvgis only present when at least one annotation has been saved. Always check for its existence before rendering.- Annotation positions are stored as percentages, so they remain correct if the display size of the image block changes between breakpoints or page sizes.
- The
visualGalleryicons should be SVGs hosted on a publicly accessible URL, not local file paths.