Annotations
Ogma Annotations provides five types of annotations that you can place on your graph to highlight, label, and explain data.
Overview
All annotations are based on the GeoJSON specification, making them easy to serialize, store, and share. Each annotation type has specific properties and default behaviors.
Annotation Types
Arrow
Arrows are directional lines that connect points on the graph. They can be used to show relationships, flows, or point to specific areas.
Default Behavior:
- By default, arrows have no heads or tails (just a plain line)
- Arrows can be connected to other annotations via links (see below)
- When an arrow is linked, moving the target annotation automatically updates the arrow position
- Arrows support interactive editing with handles at both ends
Example:
import { createArrow } from "@linkurious/ogma-annotations";
// Create a simple arrow
const arrow = createArrow(0, 0, 100, 100, {
strokeColor: "#3498db",
strokeWidth: 2,
head: "arrow"
});
controller.add(arrow);Text
Text annotations are labels or notes placed at specific positions on the graph. They automatically size to fit their content as you type.
Default Behavior:
- Text boxes are positioned by their top-left corner
- Double-click to edit text content
- Text automatically wraps within the box dimensions
- Background has rounded corners by default (
borderRadius: 8) - Text scales with graph zoom unless
fixedSize: true
Example:
import { createText } from "@linkurious/ogma-annotations";
const label = createText(50, 50, 150, 40, "Important Node", {
fontSize: 16,
color: "#2c3e50",
background: "#ecf0f1"
});
controller.add(label);Box
Boxes are rectangular areas used to group or highlight parts of the graph.
Default Behavior:
- Boxes have a light gray background by default
- No border by default (
strokeWidth: 0) - Positioned by top-left corner
- Boxes scale with graph zoom by default
- Can be resized by dragging corner handles
Example:
import { createBox } from "@linkurious/ogma-annotations";
const highlight = createBox(0, 0, 200, 150, {
background: "rgba(52, 152, 219, 0.2)",
strokeColor: "#3498db",
strokeWidth: 2
});
controller.add(highlight);Polygon
Polygons are multi-point shapes that can highlight irregular areas on the graph.
Default Behavior:
- Transparent background by default
- Black border with 2px width
- Automatically closes the polygon (connects last point to first)
- Click to add vertices during interactive creation
- Press Escape to finish drawing
- Can be edited by dragging vertices
Example:
import { createPolygon } from "@linkurious/ogma-annotations";
const area = createPolygon(
[
[
[0, 0],
[100, 0],
[100, 100],
[50, 150],
[0, 100],
[0, 0] // Closes the polygon
]
],
{
style: {
background: "rgba(46, 204, 113, 0.3)",
strokeColor: "#27ae60",
strokeWidth: 2
}
}
);
controller.add(area);Comment
Comments are special annotations that combine a text box with an arrow pointing to a specific location. They're perfect for annotating specific nodes or areas with detailed notes.
Default Behavior:
- Comments can be collapsed to show just an icon or expanded to show full text
- The arrow automatically points from the comment box to the target location
- Comments always have an arrow attached (unlike standalone text)
- Double-click to toggle between collapsed and expanded modes
- Moving a comment updates both the text box and arrow positions
Interactive Creation Example:
// For interactive creation (user clicks to place)
controller.enableCommentDrawing({
offsetX: 200,
offsetY: -150,
commentStyle: {
content: "This node is important because...",
style: {
color: "#2c3e50",
background: "#ffffff",
fontSize: 14,
font: "Arial"
}
},
arrowStyle: {
style: {
strokeColor: "#3498db",
strokeWidth: 2,
head: "arrow"
}
}
});Programmatic Creation Example:
import { createCommentWithArrow } from "@linkurious/ogma-annotations";
// Create a comment pointing to a specific location
const { comment, arrow } = createCommentWithArrow(
100,
100, // Target position (where arrow starts)
300,
50, // Comment position (where arrow points to)
"Important node!", // Comment text
{
commentStyle: {
style: {
background: "#FFFACD",
color: "#333"
}
},
arrowStyle: {
strokeColor: "#3498db",
strokeWidth: 2,
head: "arrow"
}
}
);
// Add both to the controller
controller.add(comment);
controller.add(arrow);TIP
Always use createCommentWithArrow() for programmatic creation, as comments require at least one arrow. The arrow automatically points from the target TO the comment and is linked to it.
Links
Links are a powerful feature that connect arrows to other annotations or graph elements. When you create a link, the arrow automatically follows the linked target. They are encoded within the annotation arrows themselves.
How Links Work
When an arrow is linked to a target:
- The arrow's start or end point automatically attaches to the target
- If the target moves, the arrow updates to maintain the connection
- If the target is deleted, the link is removed (arrow remains but becomes unlinked)
- Links are stored in the
arrow.properties.linkproperty
What Can Be Linked?
Arrows can link to:
- Text annotations: Arrow points to the text box
- Graph nodes: Arrow follows node position
- Comments: Arrow connects to comment box
- Boxes: Arrow attaches to box edges
- Polygons: Arrow attaches to polygon edges
Creating Links
Links are created by setting the link property on arrow annotations. This can happen:
- Automatically during interactive drawing when you click on an annotation or node
- Programmatically by setting
arrow.properties.linkwhen creating the arrow
Example:
import { createArrow, createText } from "@linkurious/ogma-annotations";
// Create a text annotation
const label = createText(100, 100, 150, 40, "Important");
controller.add(label);
// Create an arrow with a link to the text annotation
const arrow = createArrow(0, 0, 100, 120, {
strokeColor: "#3498db",
head: "arrow"
});
// Set up the link on the arrow's end point
arrow.properties.link = {
end: {
id: label.id,
side: "end",
type: "text",
magnet: { x: 0, y: 0 } // Relative position on the target
}
};
controller.add(arrow);
// Now when you move the text, the arrow's end follows!TIP
You can link both the start and end points of an arrow by setting both arrow.properties.link.start and arrow.properties.link.end.
Breaking Links
To remove a link, update the arrow and remove the link property:
const arrow = controller.getFeature(arrowId);
// Remove the end link
if (arrow.properties.link) {
delete arrow.properties.link.end;
}
// Or remove all links
arrow.properties.link = undefined;
// Update the annotation
controller.update(arrow);Detecting Links
Check if an arrow has links by inspecting its properties:
const arrow = controller.getFeature(arrowId);
if (arrow.properties.link?.end) {
console.log("Arrow end is linked to:", arrow.properties.link.end.id);
}
if (arrow.properties.link?.start) {
console.log("Arrow start is linked to:", arrow.properties.link.start.id);
}GeoJSON Structure
All annotations follow the GeoJSON Feature format:
{
id: "unique-id",
type: "Feature",
geometry: {
type: "Point" | "LineString" | "Polygon",
coordinates: [...],
bbox: [minX, minY, maxX, maxY] // Optional bounding box
},
properties: {
type: "arrow" | "text" | "box" | "polygon" | "comment",
style: { /* style properties */ },
// ... type-specific properties
}
}This structure makes annotations:
- Easy to serialize to JSON
- Compatible with GIS tools
- Simple to store in databases
- Portable across systems
Best Practices
1. Use the Right Annotation Type
Choose the annotation that best fits your use case:
- Arrows: Show direction, relationships, or flows
- Text: Label specific items or add notes
- Boxes: Group related items or highlight areas
- Polygons: Highlight irregular shapes or custom regions
- Comments: Add detailed explanations with context
2. Consider Zoom Behavior
For labels that should remain readable at all zoom levels:
const label = createText(50, 50, 150, 40, "Always Readable", {
fixedSize: true // Maintains size regardless of zoom
});4. Use Transparent Backgrounds for Subtle Highlights
const highlight = createBox(0, 0, 200, 150, {
background: "rgba(52, 152, 219, 0.1)", // Very subtle blue tint
strokeColor: "#3498db",
strokeWidth: 2
});Next Steps
- Events - Listen to annotation changes
- Creating Annotations - Add annotations programmatically
- Interactive Creation - Let users draw annotations
- Styling - Customize annotation appearance