MarkinJS API Documentation

Complete guide to getting started and API reference

What is MarkinJS?

MarkinJS is a lightweight, zero-dependency library for creating precise SVG-based annotations on images. It's perfect for computer vision datasets, machine learning training data, and research projects that need pixel-perfect annotation tools.

Installation

Download

Download markin.js from the releases page and include it in your HTML:

<script src="path/to/markin.js"></script>

Quick Start

Step 1: Prepare Your HTML

<!DOCTYPE html>
<html>
<head>
    <title>My Annotation Tool</title>
    <script src="markin .js"></script>
</head>
<body>
    <img id="my-image" src="image.jpg" alt="Image to annotate">
</body>
</html>

Step 2: Initialize the Annotator

// Create annotator on your image
const annotator = MarkinJS.createImageAnnotator('my-image', {
    keyboardControls: true,
    zoom: 1.0
});

// Listen for when annotations are created
annotator.on('annotationcreated', function(data) {
    console.log('New annotation:', data);
});

Step 3: Create Your First Annotation

// Add a bounding box for object detection
annotator.createAnnotation({
    class: "person",
    bbox: [100, 100, 300, 400]
});

That's it! You now have a working annotation tool.

Common Use Cases

1. Object Detection Dataset

const detector = MarkinJS.createImageAnnotator('dataset-image');

// Add person detection
detector.createAnnotation({
    class: "person",
    bbox: [150, 100, 300, 400]
});

// Add car detection
detector.createAnnotation({
    class: "car", 
    bbox: [400, 200, 600, 350]
});

// Export annotations for training
detector.on('annotationcreated', (data) => {
    saveAnnotation({
        image: 'dataset-image.jpg',
        class: data.class,
        bbox: getBBoxCoordinates(data.group)
    });
});

2. Instance Segmentation

const segmenter = MarkinJS.createImageAnnotator('segmentation-image');

// Create annotation with precise polygon outline
segmenter.createAnnotation({
    class: "building",
    bbox: [200, 150, 500, 400],
    segmentation: [220, 170, 480, 170, 480, 380, 350, 380, 220, 300],
    bindElements: true  // Polygon moves with bounding box
});

3. Keypoint Detection

const keypointDetector = MarkinJS.createImageAnnotator('keypoint-image');

// Facial keypoint annotation
keypointDetector.createAnnotation({
    class: "face",
    bbox: [100, 80, 200, 180],
    keypoints: [
        { name: "left_eye", point: [130, 110] },
        { name: "right_eye", point: [170, 110] },
        { name: "nose", point: [150, 130] },
        { name: "mouth", point: [150, 150] }
    ],
    containRules: ["keypoint"]  // Keep keypoints inside bbox
});

Interactive Features

Keyboard Controls

Once an element is selected, you can move it precisely:

  • Arrow Keys: Move 1 pixel
  • Shift + Arrow Keys: Move 10 pixels
  • Ctrl + Arrow Keys: Move 0.2 pixels (sub-pixel precision)
  • Delete Key: Remove selected annotation

Mouse Interactions

  • Click: Select elements
  • Drag: Move elements around
  • Handles: Resize bounding boxes by dragging corners/edges

Event Handling

// Track user interactions
annotator.on('select', (data) => {
    console.log('Selected:', data.type, data.class);
    showEditPanel(data);
});

annotator.on('elementmoved', (data) => {
    console.log('Moved to:', data.position);
    updateCoordinateDisplay(data.position);
});

annotator.on('delete', (data) => {
    console.log('Deleted annotation:', data.groupId);
    updateAnnotationCount();
});

Configuration Options

Basic Configuration

const annotator = MarkinJS.createImageAnnotator('image', {
    // Enable keyboard arrow key movement
    keyboardControls: true,
    
    // Current zoom level
    zoom: 1.0,
    
    // Bind child elements to parent elements
    bindElements: true,
    
    // Keep polygons inside bounding boxes
    bboxContainPolygon: true,
    
    // Keep keypoints inside bounding boxes  
    bboxContainKeypoints: true
});

Advanced Deletion Rules

const annotator = MarkinJS.createImageAnnotator('image', {
    deletionRules: {
        // When bbox is deleted, also delete keypoints and polygons
        "bbox": ["keypoint", "polygon"],
        
        // When keypoint is deleted, don't delete anything else
        "keypoint": [],
        
        // When polygon is deleted, also delete bbox
        "polygon": ["bbox"]
    }
});

Best Practices

1. Performance

  • Use event delegation for large numbers of annotations
  • Clean up event listeners when destroying annotators
  • Consider pagination for datasets with many images

2. User Experience

// Provide visual feedback
annotator.on('dragstart', () => {
    document.body.style.cursor = 'grabbing';
});

annotator.on('dragend', () => {
    document.body.style.cursor = 'default';
});

// Show coordinate information
annotator.on('elementmoved', (data) => {
    document.getElementById('coordinates').textContent = 
        `(${Math.round(data.position.x)}, ${Math.round(data.position.y)})`;
});

3. Data Validation

// Validate annotation data before creating
function createValidatedAnnotation(data) {
    if (!data.class) {
        throw new Error('Annotation must have a class');
    }
    
    if (data.bbox && data.bbox.length !== 4) {
        throw new Error('Bbox must have exactly 4 coordinates');
    }
    
    annotator.createAnnotation(data);
}

API Reference - Initialization

MarkinJS.createImageAnnotator(imageId, options)

Creates an SVG overlay positioned directly on top of an existing image element.

Parameters:
imageId (String): ID of the image element to overlay
options (Object): Configuration options
Returns: Annotator instance
const annotator = MarkinJS.createImageAnnotator('my-image', {
    zoom: 1.0,
    keyboardControls: true,
    bindElements: true
});

Additional Methods Available:

  • getImageElement(): Returns the underlying image element
  • getSVGElement(): Returns the generated SVG element
  • updateDimensions(): Manually updates SVG dimensions to match image
  • getContainerElement(): Returns the container wrapping image and SVG

Core Methods

enable()

Enables the annotator, allowing user interaction.

disable()

Disables the annotator, preventing user interaction.

setZoom(zoomLevel)

Sets the zoom level for the annotator.

Parameters:
zoomLevel (Number): Zoom level (e.g., 1.0 = 100%, 2.0 = 200%)

getSelectedElement()

Returns information about the currently selected element.

Returns: Object with properties:
element (SVGElement): The DOM element
type (String): Element type ("rect", "circle", "polygon", "g")
data (Object): Element-specific data
uuid (String): Element UUID (if available)
class (String): Element class (if available)

deleteSelectedElement()

Deletes the currently selected element and applies deletion rules.

Event System

on(eventName, callback)

Registers an event handler.

Parameters:
eventName (String): Name of the event
callback (Function): Handler function

off(eventName, callback)

Removes an event handler.

Available Events

Event Description Data Object
select Element selected {element, type, data, uuid, class}
deselect Element deselected {element, type}
annotationcreated New annotation created {uuid, class, group, elements}
elementmoved Element moved {element, type, deltaX, deltaY, position}
delete After element deletion {role, groupId}

Annotation Creation

createAnnotation(options)

Creates a new annotation with the specified options.

Annotation Options:

{
    uuid: "unique-id",              // Optional: auto-generated if not provided
    class: "person",                // Classification label
    bbox: [x1, y1, x2, y2],        // Bounding box coordinates
    segmentation: [x1,y1,x2,y2,...], // Polygon points (flat array)
    keypoints: [                    // Named keypoints
        { name: "head", point: [x, y] },
        { name: "center", point: [x, y] }
    ],
    bindElements: true,             // Bind child elements to parent
    containRules: ["keypoint"],     // Elements to keep inside bbox
    deletionRules: {                // Custom deletion behavior
        "bbox": ["keypoint", "polygon"],
        "polygon": ["bbox"]
    }
}

Element Management

Keyboard Controls

When enabled, selected elements can be moved using:

  • Arrow keys: Move by 1px
  • Shift + Arrow keys: Move by 10px
  • Ctrl + Arrow keys: Move by 0.2px (fine adjustment)
  • Delete key: Delete selected element

enableKeyboardControls()

Enables keyboard controls for element movement and deletion.

disableKeyboardControls()

Disables keyboard controls.

setDeletionRules(rules)

Sets custom deletion rules for the annotator.

annotator.setDeletionRules({
    "bbox": ["keypoint", "polygon", "group"],
    "keypoint": [],
    "polygon": ["bbox"]
});

Advanced Usage Examples

Custom Event Handling

const annotator = MarkinJS.createImageAnnotator('image');

// Track all annotation changes
annotator.on('annotationcreated', (data) => {
    console.log(`Created ${data.class} annotation:`, data.uuid);
});

annotator.on('delete', (data) => {
    console.log(`Deleted annotation group:`, data.groupId);
});

// Real-time coordinate tracking
annotator.on('elementmoved', (data) => {
    updateCoordinateDisplay(data.element, data.position);
});

Complex Annotation Creation

// Medical imaging annotation
const medicalAnnotation = annotator.createAnnotation({
    class: "lesion",
    uuid: "lesion_001",
    bbox: [200, 150, 350, 280],
    keypoints: [
        { name: "center", point: [275, 215] },
        { name: "boundary_north", point: [275, 160] },
        { name: "boundary_south", point: [275, 270] }
    ],
    segmentation: [210, 160, 340, 160, 340, 270, 210, 270],
    bindElements: true,
    containRules: ["keypoint", "polygon"],
    deletionRules: {
        "bbox": ["keypoint", "polygon"],
        "keypoint": [],
        "polygon": ["keypoint"]
    }
});

Ready to Build?

Explore examples or start building your annotation tool