Skip to content

Layer System

Annota’s layer system allows you to organize annotations into logical groups with independent styling and visibility control.

Use the useLayerManager hook to create and manage layers:

import { useLayerManager } from 'annota';
function LayerPanel() {
const layerManager = useLayerManager();
const handleCreateLayer = () => {
layerManager.createLayer({
id: 'tumor',
name: 'Tumor Regions',
visible: true,
style: {
fill: 'rgba(255, 0, 0, 0.3)',
stroke: '#ff0000',
strokeWidth: 2,
},
});
};
return (
<button onClick={handleCreateLayer}>
Create Tumor Layer
</button>
);
}

Each layer has the following properties:

PropertyTypeDescription
idstringUnique identifier for the layer
namestringDisplay name for the layer
visiblebooleanWhether annotations in this layer are visible
opacitynumberLayer transparency (0-1)
lockedbooleanPrevent editing of annotations
styleAnnotationStyleDefault style for annotations in this layer

Annotations can be assigned to layers via their properties.layer field:

const annotation = {
id: 'ann-1',
shape: {
type: 'rectangle',
geometry: { x: 100, y: 100, width: 200, height: 150 },
},
properties: {
layer: 'tumor', // Assign to tumor layer
},
};

Or when using tools:

const polygonTool = new PolygonTool({
layer: 'tumor', // All annotations created will be assigned to this layer
});

Toggle layer visibility to show/hide all annotations in a layer:

function LayerList() {
const layerManager = useLayerManager();
return (
<div>
{layerManager.layers.map(layer => (
<div key={layer.id}>
<input
type="checkbox"
checked={layer.visible}
onChange={(e) =>
layerManager.updateLayer(layer.id, {
visible: e.target.checked,
})
}
/>
{layer.name}
</div>
))}
</div>
);
}

Layers define default styles for their annotations. Individual annotations can override:

// Layer style (default for all annotations in layer)
const layerStyle = {
fill: 'rgba(255, 0, 0, 0.3)',
stroke: '#ff0000',
strokeWidth: 2,
};
// Annotation-specific style override
const annotation = {
id: 'special-1',
properties: { layer: 'tumor' },
style: {
fill: 'rgba(255, 255, 0, 0.5)', // Override fill color
},
};

Delete a layer and optionally remove all its annotations:

// Delete layer and keep annotations (they become unassigned)
layerManager.deleteLayer('tumor', false);
// Delete layer and remove all its annotations
layerManager.deleteLayer('tumor', true);

By Tissue Type

  • “Tumor”
  • “Stroma”
  • “Necrosis”
  • “Normal”

By Annotator

  • “Pathologist-A”
  • “Pathologist-B”
  • “AI-Model”

By Status

  • “Reviewed”
  • “Pending”
  • “Rejected”

By Source

  • “Manual”
  • “Model-v1”
  • “Model-v2”
import { useLayerManager, useLayers } from 'annota';
import { useState } from 'react';
function LayerPanel() {
const layerManager = useLayerManager();
const layers = useLayers();
const [newLayerName, setNewLayerName] = useState('');
const createLayer = () => {
if (!newLayerName) return;
layerManager.createLayer({
id: newLayerName.toLowerCase().replace(/\s+/g, '-'),
name: newLayerName,
visible: true,
style: {
fill: `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 0.3)`,
stroke: '#000000',
strokeWidth: 2,
},
});
setNewLayerName('');
};
return (
<div className="layer-panel">
<h3>Layers</h3>
<div className="create-layer">
<input
value={newLayerName}
onChange={(e) => setNewLayerName(e.target.value)}
placeholder="Layer name"
/>
<button onClick={createLayer}>Add</button>
</div>
<ul>
{layers.map(layer => (
<li key={layer.id}>
<input
type="checkbox"
checked={layer.visible}
onChange={(e) =>
layerManager.updateLayer(layer.id, { visible: e.target.checked })
}
/>
<span>{layer.name}</span>
<button onClick={() => layerManager.deleteLayer(layer.id, true)}>
Delete
</button>
</li>
))}
</ul>
</div>
);
}