Annotating An Image In JavaScript – Annotorious

Category: Image , Javascript , Recommended | November 9, 2023
Views Total:542 views
Official Page:Go to website
Last Update:November 9, 2023


Annotating An Image In JavaScript – Annotorious


Annotorious is a simple yet feature-rich JavaScript image annotation library that adds custom comments, notes, tags to a specific part of an image.


  • Load pre-defined annotations from a JSON file.
  • Drag and drop to create new annotations from an editor popup.
  • Based on W3C WebAnnotation model.
  • Touch & Mobile friendly.

How to use it:

1. Install and import the Annotorious as a module.

$ npm install @recogito/annotorious --save
import { Annotorious } from '@recogito/annotorious';

2. Or download the package and insert the annotorious.min.js into the HTML document.

<link rel="annotorious.min.css" href="styles.css" />
<script src="annotorious.min.js"></script>

3. Initialize the Annotorious on the image and we’re ready to go.

<img id="example" src="example.jpg" />
var anno = Annotorious.init({
    image: 'example'

4. Define your annotations in a w3c.json file and load it on page load.

// annotations.w3c.json
    "@context": "",
    "id": "#unique-ID-Here",
    "type": "Annotation",
    "body": [{
      "type": "TextualBody",
      "value": "Comments Here"
    }, {
      "type": "TextualBody",
      "purpose": "tagging",
      "value": "Tag 1"
    }, {
      "type": "TextualBody",
      "purpose": "tagging",
      "value": "Tag 2"
    "target": {
      "selector": [{
        "type": "FragmentSelector",
        "conformsTo": "",
        "value": "xywh=pixel:270,120,90,170"

3. Enable read-only mode. Defaults to false.

var anno = Annotorious.init({
    image: 'example',
    readOnly: true

4. Disable the editor popup. Defaults to false.

var anno = Annotorious.init({
    image: 'example',
    disableEditor: true

5. Add a new annotation to the image following the structure you’ve seen in the annotations.w3c.json.

// add an annotation
anno.addAnnotation(annotation [, readOnly]);
// add an array of annotations

6. Remove an annotation from the image.


7. Get all annotations.


8. Select an annotation.

// select the current annotation
// select a specific annotation

9. Show/hide the annotations.


10. Apply a custom template to the annotation.

anno.applyTemplate(template, openEditor[TRUE/FALSE]);

11. Set & get author info.

// set
  id: '',
  displayName: 'CSSScript'
// clear

12. Switch between drawing tools: ‘rect’ or ‘polygon’.


13. Show or hide the annotation layer.


14. Set a server time timestamp.


15. Destroy the instance.


16. Event handlers.

anno.on('changeSelectionTarget', function(target) {
  // when the shape of a newly created selection
anno.on('createSelection', function(selection) {
  // when a new selection shape is drawn on the image
anno.on('cancelSelection', function(selection) {
  // do something
anno.on('selectAnnotation', function(annotation) {
  console.log('selected', annotation);
anno.on('createAnnotation', function(a) {
  console.log('created', a);
anno.on('updateAnnotation', function(annotation, previous) {
  console.log('updated', previous, 'with', annotation);
anno.on('deleteAnnotation', function(annotation) {
  console.log('deleted', annotation);
anno.on('mouseEnterAnnotation', function(annotation, event) {
  console.log('mouseEnter', annotation);
anno.on('mouseLeaveAnnotation', function(annotation, event) {
  console.log('mouseLeave', annotation);

17. Use custom formater function:

// String Example
var formatter = function(annotation) {
    var longComments = annotation.bodies.filter(function(body) {
      var isComment = body.type === 'TextualBody' && 
        (body.purpose === 'commenting' || body.purpose === 'replying');
      var isLong = body.value.length > 100;
      return isComment && isLong;
    if (longComments.length > 0) {
      // This annotation contains long comments - add CSS class
      return 'long';
var anno = Annotorious.init({
    formatter: formatter
// Object Example
var formatter = function(annotation) {
    var contributors = [];
    annotation.bodies.forEach(function(body) {
      if (body.creator)
    if (contributors.length > 1) {
      return {
        'data-users': contributors.join(', '),
        'style': 'stroke-width:2; stroke: red'
var anno = Annotorious.init({
    formatter: formatter


v2.7.13 (11/09/2023)

  • Maintenance release, adds zh locale

v2.7.11 (07/01/2023)

  • New configuration parameter disableDeleteKey that disables the default keyboard behavior of deleting the selected annotation when pressing Delete.

v2.7.10 (01/24/2023)

  • Adds proper hit test for line shapes

v2.7.9 (12/15/2022)

  • Adds proper hit test for line shapes
  • Fixed various vulnerabilities in library dependencies

v2.7.8 (09/17/2022)

  • Added Chinese and Japanese UI translations
  • Editor widget API: widgets can now add additional JSON-LD namespaces to the annotation @context.
  • When using Recogito to annotate content inside an iframe, the Editor auto-position now respects the iframe dimensions
  • Bugfixes

v2.7.7 (07/19/2022)

  • Minor maintenance release that prepares support for a line drawing plugin.

v2.7.6 (05/07/2022)

  • Adds a minor style fix, which prevents the default tabindex outline to appear around the image while annotating.

v2.7.5 (05/07/2022)

  • The Annotorious SVG element now has a tabindex element. This is a minor change in response to DEL key event handling issues with the Better Polygon plugin

v2.7.4 (05/01/2022)

  • Fixed a race condition that cause a null error in certain situations in headless mode

v2.7.3 (04/18/2022)

  • Minor tweak to getImageSnippet methods: for selected shapes, these now return the actual shape bounding box, without the area covered by the shape resize handles
  • Fixed a minor issue in the Selection class that caused error when accessing the exact field on image annotations. The call now returns null.

v2.7.2 (02/19/2022)

  • Improved input sanization for SVG polygon selectors
  • Bugfixes

v2.7.1 (01/23/2022)

  • Changes to formatters through the anno.formatters field now take effect immediately
  • Editor: line breaks in comments are now properly displayed in read-only mode
  • Editor: the default popup width is now reduced responsively on small-screen devices

v2.7.0 (01/16/2022)

  • saveSelected API method now also works in normal mode, not just headless
  • New keyboard shortcut: delete key now deletes the currently selected annotation
  • Added Russian UI translation
  • Breaking change: tag bodies are now serialized differently when terms are from a semantic vocabulary (label + URI)
  • Bugfixes

v2.6.1 (01/01/2022)

  • New API method .getImageSnippetById(annotationId)
  • New formatters init config parameter that allows setting a single formatter function as well as an array of formatters. The old formatter option is still available, but deprecated
  • New formatters instance field that allows dynamic adding/removing of formatter functions
  • Bugfixes

v2.6.0 (11/20/2021)

  • The tag widget now supports functions as vocabulary init option. The function will get the current value of the tag input field as an argument, and must return either, a list of vocabulary terms
  • Bugfixes

v2.5.10 (11/08/2021)

  • Added Thai UI translation
  • Added support for ‘non-scaling’ annotations, which remain of constant screen size, regardless of whether the underlying image is scaled. The typical (only?) use case for this is point markers. For example: you’ll always want a point marker to be a circle of 5 pixel radius, no matter if the image is displayed in original size, or scaled by 50% in a responsive UI.
  • Fixed an issue that caused an error when creating a shape in headless mode, and saving instantly

v2.5.9 (11/02/2021)

  • Added getAnnotationById API method
  • Added removeDrawingTool API method
  • When adding a drawing tool that has the same ID as an existing one, addDrawingTool will replace it
  • Drawing tools can now implement behavior where drawing starts on a single click, rather than a drag. The default polygon tool implements this behavior already. Note that this behavior is disabled by default and can be enabled with a new drawOnSingleClick: true config property
  • It’s now possible to display SVG shape annotations for which no drawing tool is available. (E.g. created with other tools, or created in another Annotorious instance that had specific tool plugins installed.) In this case, selecting the annotation will show the editor popup normally. The shape just won’t be editable.
  • Fixes a regression that broke changing selections between annotations in headless mode
  • Fixes a bug with polygon selection: when the selection was started on another shape, that shape got selected after the first click

v2.5.8 (10/24/2021)

  • Escape key now cancels drawing
  • Polygon tool: when moving the mouse outside the image and clicking (or double clicking), the tool adds the last point inside the image, rather than creating a point at the mouse position outside of the image
  • move cursor no longer shows on non-draggable surfaces
  • Cosmetic tweaks to editor auto-position behavior to avoid the jump when dragging the editor from the upwards-oriented position.
  • Text comment fields are no longer drag surfaces. This way, it’s possible to select (and copy) text from comment fields
    Comment widget: the purpose selection dropdown is no longer obscured by tags
  • onRemoveAndAppend was dropped in favour of the more flexible onBatchModify.
  • Replaced deprecated @babel/polyfill

v2.5.7 (10/09/2021)

  • Added a mechanism for widget plugins to use built-in I18N features and register their own localized UI labels
  • New event changeSelected that fires when the user changes the selection by clicking an annotation while another annotation is currently selected.
  • The editor now adjusts position when widgets are changing. This is to avoid mis-placement when the editor grows/shrinks
  • Draggable surfaces on the editor are now properly indicated with cursor move icon
  • Cosmetic tweak: in cases where the editor is pushed from its original position to remain in the view, the litte arrow now hides. This is to avoid the arrow pointing outside of the annotation.
  • Bugfixes

v2.5.6 (09/27/2021)

  • Crude support for displaying “point selectors” (Fragment selectors with zero width and height)
  • Bugfixes When importing via script-tag, source map file now loads properly

v2.5.5 (09/19/2021)

  • Added Finnish and Korean UI labels
  • Added support for percent-encoded Media Fragment selectors. (Annotorious will read both pixel and percent-encoded fragments. When new rectangle annotations are created, the fragmentUnit init parameter determines their encoding. Set fragementUnit: ‘percent’ to write percent-encoded annotations, or fragmentUnit: ‘pixel’ (default) to write pixel-encoded annotations.
  • Added support for tagging vocabularies with ontology terms, where each vocabulary item consists of a label and a URI.
  • Widget API: saveImmediately and onUpsertBody methods now properly exposed to VanillaJS widgets
  • Fixed a bug that caused broken editor offset in Firefox when using the Shape Labels plugin

v2.5.4 (08/17/2021)

  • disableSelect is now an init option
  • wigets can now a getter/setter option
  • anno.getSelected now returns live editor state
  • Minor behavior fixes to draggable editor behavior

v2.5.3 (08/11/2021)

  • Minor changes to the tool plugin API

v2.5.2 (08/07/2021)

  • Added French UI labels
  • Behavior improvements/fixes

v2.5.1 (07/15/2021)

  • New property disableSelect to temporarily disable all selection functionality
  • New event clickAnnotation
  • Added .once method for registering a one-time event handler

v2.5.0 (07/08/2021)

  • New crosshair feature that can optionally replace the mouse cursor, for more precise selection. Enable via a crosshair:true init option
  • New .setWidgets API method that allows changing editor widget configuration at runtime
  • Behavior improvements/fixes
  • Updated Editor plugin API
  • Separation of IE support reduces the core bundle size by 76kB

v2.4.4 (06/22/2021)

  • Fixes a bug that caused resize handes to be offset on Safari for responsive images, and on the OpenSeadragon plugin

v2.4.2 (06/21/2021)

  • Detachable editor: it’s now possible to grab and drag the editor away from the annotation with mouse or touch, e.g. to avoid the editor getting in the way of shape resizing. The editor stays detached until closed.
  • Internal changes to the plugin API to support drawing tools for different shape types

v2.4.1 (06/13/2021)

  • New startSelection event fired when the user starts drawing a shape
  • Editor now supports widgets built with Preact, and no longer breaks for widgets using React hooks
  • Bugfixes

v2.4.0 (05/22/2021)

  • New init option handleRadius, for setting the radius of the resize handles
  • New init option messages to override UI labels when initializing
  • Escape key now cancels editing
  • Formatters now support insertion of DOM elements into the annotation SVG group
  • Added support for React editor widgets
  • Improved auto-positioning of the editor, so that it now remains inside the viewport in (almost) all situations
  • Shapes are now constrained to the image area (when editing a shape, it’s no longer possible to push it outside the image)
  • When resizing a rectangle selection, it is now possible to move the dragged handle into neighbour quadrants without creating a zero-size rectangle
  • anno.cancelSelected() now stops drawing if a tool is currently active
  • Fixed broken .clearAnnotations() method
  • Fixed polygon area computation – larger polygons no longer cover smaller rectangles
  • Fixed polygon serialization syntax, which was working in most browser, but technically not compliant to the SVG spec
  • Calling destroy while a shape is selected no longer causes an error
  • Calling setDrawingTool in read-only mode no longer causes an error
  • Calling setVisible(false) now properly deselects the selected annotation
  • Removed axios dependency in .loadAnnotations in favor of standard fetch API, reducing uncompressed download size by ~12kB
  • SVG selectors now go through basic security sanitization: <script> tags and on… event handlers are removed
  • Added most recently available dependency security patches

v2.3.3 (03/30/2021)

  • Fixed a bug that caused polygons to close in touch mode after ~500ms of idleness, even if the finger wasn’t on the screen (intended behavior is tap-and-hold for ~500ms)
  • Touch mode now works properly on images in scrolled pages
  • Bugfix: when creating a new selection, attempting to modify the shape caused a ‘cancel’. Newly created shapes can now be modified immediately
  • Editor now (finally) auto-positions correctly when moving it outside the browser viewport
  • When allowing empty annotations (allowEmpty: true config option), empty annotations get a delete button

v2.3.2 (03/30/2021)

  • Adds CSS fixes to the style of the tag widget
  • Bugfix: calling .selectAnnotation triggered two selectAnnotation events, when it should trigger any at all – fixed
  • Regression bug fix: resize handles now scale properly again on responsive images
  • Fixed a bug that caused coordinates to shift when annotating images on scrolled-down on touch devices
  • Fixed various minor behavior bugs in touch mode
  • Upgrades some security-patched npm dependencies

v2.3.1 (03/29/2021)

  • Minor behavior tweaks to headless mode.
  • When creating annotations in headless mode that have no bodies, annotations are immediately removed (as they should be), unless the allowEmpty config option is set to true.
  • When changing the drawing tool, the current drawing tool is properly stopped in case drawing is currently ongoing.

v2.3.0 (03/28/2021)

  • Bugfix: .removeAnnotation now allows annotation object or annotation ID as argument
  • Delete Annotation button (finally!), with a mechanism that allows widget plugins to control whether delete is possible or not
  • headless config option now deprecated. Use disableEditor instead
  • disableEditor can be changed without re-initializing Annotorious
  • ReadOnly mode can now be changed without re-initializing Annotorious, through the .readOnly property
  • allowEmpty config option
  • Tweaked touch interaction: both press+hold and move+hold are now translated to double click, which closes the polygon
  • Removed Hammer.js dependency

v2.2.5 (03/17/2021)

  • Switched to Terser for code optimization, due to ongoing security issues with Uglify
  • Fixed errors in the event lifecycle
  • Size-based sorting of polygon shapes, so that large polygon annotations no longer obstruct smaller polygon shapes
  • Internal API changes to enable more powerful plugins
  • Reduced code redundancy in drawing tool implementations
  • .listDrawingTools API method

v2.2.4 (03/11/2021)

  • Fixes a bug that caused .getAnnotations API method to break when called from inside an event handler
  • Adds cancelSelected event when user cancels editing a selection

v2.2.3 (03/10/2021)

  • Fixed cancelSelected event

v2.2.2 (02/28/2021)

  • Fixes a bug that caused wrong editor position when the window is scrolled horizontally
  • Adds support for touch devices

v2.2.1 (02/15/2021)

  • Bugfixes
  • Shape edit handles can now be resized via CSS transform: scale(…)
  • Shape editing now works properly in headless mode
  • Editor: Fixed a minor bug concerning proper display of created/lastModified times; Greek UI language translation
  • Widget API: Widgets now get an updated annotation instance when the user changes the selection target (e.g. move/resize in Annotorious); Added .onSetProperty method that allows widgets to attach top-level props the annotation

v2.2.0 (01/03/2021)

  • Added Dutch UI translation
  • New API method clearAnnotations
  • Added cancelSelection event, when user hits ‘cancel’ on a newly created shape
  • Revised headless API
  • New API method saveSelected to save changes to an annotation programmatically
  • New API method cancelSelected to cancel programmatically
  • Removed support for applyTemplate API function in favor of new headless API. Example: to apply a tag automatically in headless mode

v2.1.7 (12/27/2020)

  • Editor bugfixes
  • Added getSelectedImageSnippet API method

v2.1.6 (12/20/2020)

  • Bugfixes
  • Preparations/compatibility plumbing for editable shapes in OpenSeadragon

v2.1.5 (11/30/2020)

  • Fixes a regression bug that broke shape editing in v2.1.4

v2.1.4 (11/30/2020)

  • UI/behavior: clicking outside the selected shape cancels editing and closes the editor
  • Proper handling of multi-line comments in the Comment Widget
  • Localized text labels for time expressions (“2 minutes ago”), when using authInfo
  • Added missing Spanish labels for ‘Edit’ and ‘Delete’

v2.1.3 (10/14/2020)

  • Dim mask now also available for the polygon drawing tool
  • Czech UI translation
  • Tag widget: fixed broken autosuggest behavior
  • Editor plugins: config params are now properly forwarded to plugin args

v2.1.2 (09/22/2020)

  • Environment is no longer a global object, meaning that it is now safe to use multiple Recogito/Annotorious instances on the same page
  • All CSS classes are now properly prefixed to avoid clashes with other styles on the page (either with a9s for Annotorious-specific elements or r6o for elements imported from Recogito core
  • Small bugfixes to the dim mask

v2.1.1 (09/20/2020)

  • CSS styles are no longer embedded in the JavaScript file, but now have to be imported separately.
  • Editor widgets are becoming more flexible. This release is the first to include beta support for a plugin API. As a consequence, this version introduces a minimal change to how the tag widget is configured with a controlled vocabulary.

v2.0.8 (09/13/2020)

  • Minor bugfix

v2.0.7 (08/29/2020)

  • IE11 support bugfixes

v2.0.6 (08/29/2020)

  • IE11 compatibility
  • Editable polygon shapes
  • Bugfixes concerning the behavior of the tag autosuggest component
  • Security fixes for library dependencies

v2.0.5 (07/12/2020)

  • Added babel polyfill (IE11 compat)

v2.0.4 (07/12/2020)

  • Beta support for rendering any SVG shape contained in W3C Web Annotations
  • Beta support for polygon drawing
  • Various bugfixes
  • Portuguese UI translation
  • Tag widget: controlled vocabulary autosuggest
  • Selecting an annotation now adds a selected CSS class

v2.0.3 (06/12/2020)

  • Various smaller bugfixes
  • Microsoft Edge compatibility
  • Experimental support for responsive images
  • Web Annotation standard compliance: target now includes a source property with the image source URL
  • Minor API changes: selectAnnotation method now returns selected annotation object and does not fire the selectAnnotation event
  • Added support for internationalization
  • Ability to handle user information for UI display and when creating/updating annotations
  • Ability to add created and modified timestamps, with an option for the host application to sync with the server time

v2.0.2 (05/21/2020)

  • Minor bugfixes
  • Enabling readOnly annotations

v2.0.2 (05/21/2020)

  • Minor bugfixes

You Might Be Interested In:

One thought on “Annotating An Image In JavaScript – Annotorious

Leave a Reply