Coder Social home page Coder Social logo

annotorious / annotorious Goto Github PK

View Code? Open in Web Editor NEW
606.0 21.0 91.0 3.81 MB

Add image annotation functionality to any web page with a few lines of JavaScript.

Home Page: http://annotorious.github.io

License: BSD 3-Clause "New" or "Revised" License

HTML 2.34% JavaScript 1.84% CSS 0.82% TypeScript 79.54% Svelte 15.46%
annotation image-annotation annotation-tool data-annotation-tools image-annotation-tool

annotorious's Introduction

Aerial view of Schönbrunn Palace in Vienna annotated with Annotorious

IMPORTANT This repository is work in progress. I am building the next major release of Annotorious. If you are looking for the most recent official release, visit the main project homepage. Documentation in this Readme is only for the upcoming alpha release and will not work with Annotorious 2.7.x!

Annotorious 3.0 Beta

Add image annotation functionality to any web page with a few lines of JavaScript.

Getting Started

npm install --save @annotorious/annotorious

Create an annotator instance on an existing Image element.

import { createImageAnnotator } from '@annotorious/annotorious';

// Import essential CSS styles
import '@annotorious/annotorious/annotorious.css';

// Image element ID or DOM element
const anno = createImageAnnotator('sample-image');

// Load annotations in W3C Web Annotation format
anno.loadAnnotations('./annotations.w3c.json');
       
// Attach listeners to handle annotation events
anno.on('createAnnotation', function(annotation) {
  console.log('created', annotation);
});

Script Import via CDN

<html>
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@annotorious/annotorious@latest/dist/annotorious.css">
    <script src="https://cdn.jsdelivr.net/npm/@annotorious/annotorious@latest/dist/annotorious.js"></script>
  </head>
  <body>
    <img id="my-image" src="my-image.jpg" />

    <script>
      window.onload = function() {
        var anno = Annotorious.createImageAnnotator('my-image');
      }
    </script>
  </body>
</html>

Using with OpenSeadragon

Annotorious provides seamless integration with the OpenSeadragon viewer for zoomable images and IIIF.

npm install @annotorious/openseadragon

Set up your OpenSeadragon viewer first, and then create an annotator instance for the viewer. Note that Annotorious requires OpenSeadragon 3 or higher.

import { createOSDAnnotator } from '@annotorious/openseadragon';

// Import essential CSS styles
import '@annotorious/annotorious/annotorious-openseadragon.css';

window.onload = function() {
  var viewer = OpenSeadragon({
    id: 'openseadragon',
    tileSources: {
      type: 'image',
      url:  '/my-image.jpg'
    }
  });

  var anno = createOSDAnnotator(viewer);

  anno.loadAnnotations('./annotations.w3c.json');
       
  anno.on('createAnnotation', function(annotation) {
    console.log('created', annotation);
  });
}

Script Import via CDN

<html>
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@annotorious/openseadragon@latest/dist/annotorious-openseadragon.css">
    <script src="https://cdn.jsdelivr.net/npm/@annotorious/openseadragon@latest/dist/annotorious-openseadragon.js"></script>
  </head>
  <body>
    <div id="openseadragon"></div>

    <script>
      window.onload = function() {
        var viewer = OpenSeadragon({
          id: 'openseadragon',
          tileSources: {
            type: 'image',
            url:  '/my-image.jpg'
          }
        });
        
        var anno = AnnotoriousOSD.createOSDAnnotator(viewer);
      }
    </script>
  </body>
</html>

Using in React

Annotorious provides React bindings for both the standard and the OpenSeadragon module.

npm install @annotorious/react

The <Annotorious> component provides a root context for all Annotorious utility hooks. Use <ImageAnnotator> or <OpenSeadragonAnnotator> to attach annotation layers on images or OpenSeadragon.

import { Annotorious, ImageAnnotator } from '@annotorious/react';

import '@annotorious/react/annotorious-react.css';

export function AnnotatableImage() => {

  return (
    <Annotorious>
      <ImageAnnotator>
        <img src="my-image.jpg" alt="Example" />
      </ImageAnnotator>
    </Annotorious>
  )

}

annotorious's People

Contributors

abiswas97 avatar alexmili avatar andrewadev avatar andrheapaltao avatar ap-- avatar architrixs avatar bibliotechy avatar bricesanchez avatar dbil25 avatar dependabot[bot] avatar derek-young avatar erikradisch avatar hero-solutions avatar lauxley avatar martimpassos avatar oleksandr-danylchenko avatar rsimon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

annotorious's Issues

Box selection resize handles on Firefox missing/shifted

The selection resize handles are not properly rendered on Firefix if the image is scaled from its original size with CSS. The reason is that transform-origin works differently than in Chrome. The usual fix (adding transform-box: fill-box) doesn't work completely, because the resize origin isn't at the center of the handles.

This will need a bit of a redesign in order to work robustly on FF for responsive & retina images.

Revise headless mode

I think headless mode needs to be rethought. Instead of instant creation with applyTemplate, we should keep this a two step process. On the one hand, things will make things more consistent with popup mode. On the other hand, it will give more flexibility to how host applications can implement their workflow in headless.

The two scenarios I want to be possible are:

  • Picking a tag from a list/menu and then labeling (like applyTemplate works now)
  • Draw first, and then edit annotation contents in you own (eg sidebar) editor while the annotation is still in draft mode

Thank you

Hey, just wanted to say thank you for your constant work over the years. I remember using it long time ago (still old repo) for an internal experimental project and i just stumbled upon this repo - im amazed by your work. I hope more projects will be maintained so good (and long) :)

(And of course i stumbled upon it because im looking for annotations again, but react bundled in is a little bit too much for my taste :) )

Uncaught TypeError: Cannot read property 'removeChild' of null

Get the following error in console:

annotorious.min.js?73e3:1 Uncaught TypeError: Cannot read property 'removeChild' of null
    at l.eval (annotorious.min.js?73e3:1)
    at eval (annotorious.min.js?73e3:1)
    at o.emit (annotorious.min.js?73e3:1)
    at HTMLDocument.eval (annotorious.min.js?73e3:1)

This happens when I do the following:

1.) Add annotation
2.) delete annotation
3.) Click on the image (do not draw bounding box, just do a click

image

Unable to highlight shape when headless = true?

Hello,
There is any way to highlight a shape when 'headless:true'? I'm trying to use anno.selectAnnotation(annotation), but this only work when headless is false. I want to highlight a shape but hiding the editor. Thanks in advance.

Really full featured and precise polygon tool

The current poly drawing tool is really just a minimum viable product. We need a full featured tool that:

  • is touch compatible
  • works on click-and-drag as well as click (then move and click again)
  • supports adding/removing points
  • provides a good crosshair cursor on all platforms

Editor-less mode

On request: totally disabling the editor, for those who want to roll their own thing (without hacking Annotorious itself). Use case is that the host page has a (potentially complex) editor panel next to the image.

Annotorious should only handle image drawing/selection. The popup should never show up. Creating the annotation would happen via .applyTemplate(...) and "viewing" would be handled externally as well, triggered by the selectAnnotation event.

Can annotorious used in OpenSeaDragon like the old version?

Hello, It's nice to find out that someone have rebooted the annotorious. I have used the old version of annotorious in my project for the Openseadragon Viewer, so I'm wondering can this new version use in the OpenSeaDragon like the old one?

createSelection event

Fire an event when a selection is made, i.e. when the box was drawn. This would be especially useful for real-time collaboration (because we could show some kind of ghosted selection on other users’ screens.)

For the full thing, we’d also need the feature to render ghost selection previews and, probably, a moveSelection event, too.

devicePixelRatio

Looks like coordinates are off on Retina devices. Investigate where device pixel ratio plays a role.

Deselecting a large annotation in front of a smaller one

When creating or updating annotations, everything gets properly sorted by size so that larger annotations never obstruct smaller ones. However, when selecting and then deselecting an annotation (by clicking cancel), they are not sorted. Larger ones obstruct smaller ones.

Error: <svg> attribute viewbox: Expected number, ...

I am using VueJS to create a single page app. I get the following console error (Chrome and Edge, haven't tried other browsers):

image

Here's my code:
script section:
mounted() { const anno = new Annotorious({ image: this.photo.id }) // Attach listeners to handle annotation events anno.on('createAnnotation', function(annotation) { console.log('Created!', annotation) })

template section:
<img :src="photo.url" :id="photo.id" :alt="photo.title" />

I should mention that it does work, it's just that I get that console error. It's possible that the DOM hasn't been fully rendered. Here's the debug info:

image

Sanitize embedded SVG

I think there's currently the possibility of script injection when loading annotations with embedded SVG markup. Sanitize them beforehand, allowing only g and shapes (but arbitrary levels of nesting).

Demo page

Like the Readme, the demo page needs an overhaul. A bit of design & instructions how to use the tool (click and drag etc)

Bug after polygon drawing

There is a bug after the polygon drawing while clicking the cancel button on the editor panel. I draw a polygon then the editor panel appears and when I click the cancel button the editor panel disappears but the polygon does not. The polygon still appears even if clicking the cancel button. The same steps work while drawing a rectangle, but it doesn't work by drawing a polygon.

Could you fix this bug, please?

(tested with chrome browser)

Div wrapper remains on destroy

Destroying annotation layer does not remove the wrapper div that is created.

See original html:
image

and the inspected html after calling anno.destroy()
image

Read-only mode

This should work out-of-the-box for the most part, in principle (because it's part of the imported components). But probably lacks some final plumbing in index.js and the ImageAnnotator.

Equality for Selections

We should probably hand out IDs already in the selection state, so we can check for equality. (Object equality isn't useful because of immutable updates.)

At the moment, when you create a selection, type some text and then move the selection (or pan the image in OpenSeadragon), the text field gets erased, because the component re-renders.

Or can we safely assume that there will only ever be one selection?

New editor fields

I would like to add a some fields to the editor. This might be specific to me. I think it would be nice to be able to add a function that allows you to add a new text field and pass in parameters. Something like this:

anno.addFields([{'placeholder': 'Rights', 'field': 'rights'}, {'placeholder': 'Language', 'field': 'body.language'}])

Where placeholder is the text field placeholder and field is the field in the annotation.
If this already exists please let me know.

'window is not defined' workaround

I'm trying to get annotorious to work in Wix Corvid engine, but it seems that only importing the module already results in an attempt to access the window object, is there a workaround for that?

This is the code:

import { Annotorious } from '@recogito/annotorious';  

// The import above accesses window and throws an error since window is not available directly, or at least that's what I think...

// $w.onReady(function () {
//   const anno = new Annotorious({
//     image: $w("Image"),
//   });
// });

And this is the error:

console.js:35 There was an error in your script
e.<computed> @ console.js:35
console.js:35 ReferenceError: window is not defined
    at Object.1 (https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:1:749)
    at o (https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:1:543)
    at https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:1:578
    at Object.2.@recogito/annotorious (https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:9:112295)
    at o (https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:1:543)
    at e (https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:1:703)
    at https://c4a8074e-f162-4306-9f5a-9efe29718b05.static.pub.wix-code.com/static/v2/822b9d6c-c00e-4f00-b471-78c10d1ecc8b/c4a8074e-f162-4306-9f5a-9efe29718b05/pages/f6i3c.js?empty-if-missing=true&inject-dollar-w=true:1:720
    at eval (https://static.parastorage.com/services/wix-code-viewer-app/1.559.0/app.js:25:4615)
    at Array.map (<anonymous>)
    at runUserCode (https://static.parastorage.com/services/wix-code-viewer-app/1.559.0/app.js:25:4488)
    at eval (https://static.parastorage.com/services/wix-code-viewer-app/1.559.0/app.js:3:11776)
    at eval (https://static.parastorage.com/services/wix-code-viewer-app/1.559.0/app.js:3:11929)
    at Object.eval [as traceSync] (https://static.parastorage.com/services/wix-code-viewer-app/1.559.0/app.js:3:17158)
    at Object.createControllers (https://static.parastorage.com/services/wix-code-viewer-app/1.559.0/app.js:3:11582)
    at callAppCreateControllers (https://www.exposeprofi.de/_partials/wix-bolt/1.6443.0/node_modules/viewer-platform-worker/dist/bolt-worker.js:18:89840)
    at https://www.exposeprofi.de/_partials/wix-bolt/1.6443.0/node_modules/viewer-platform-worker/dist/bolt-worker.js:18:91528
    at async Promise.all (index 0)

NPM install 404 error


0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   'i',
1 verbose cli   '@recogito/annotorious'
1 verbose cli ]
2 info using [email protected]
3 info using [email protected]
4 verbose npm-session a855050a092fed1a
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 http fetch GET 404 https://registry.npmjs.org/@recogito%2fannotorious 731ms
8 http fetch GET 404 https://registry.npmjs.org/@recogito%2fannotorious 140ms
9 silly fetchPackageMetaData error for @recogito/annotorious@latest 404 Not Found - GET https://registry.npmjs.org/@recogito%2fannotorious - Not found
10 timing stage:rollbackFailedOptional Completed in 1ms
11 timing stage:runTopLevelLifecycles Completed in 19512ms
12 verbose stack Error: 404 Not Found - GET https://registry.npmjs.org/@recogito%2fannotorious - Not found
12 verbose stack     at C:\nvm\v12.0.0\node_modules\npm\node_modules\npm-registry-fetch\check-response.js:104:15
12 verbose stack     at processTicksAndRejections (internal/process/task_queues.js:88:5)
13 verbose statusCode 404
14 verbose pkgid @recogito/annotorious@latest
16 verbose Windows_NT 10.0.18363
17 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "i" "@recogito/annotorious"
18 verbose node v12.0.0
19 verbose npm  v6.9.0
20 error code E404
21 error 404 Not Found - GET https://registry.npmjs.org/@recogito%2fannotorious - Not found
22 error 404
23 error 404 '@recogito/annotorious@latest' is not in the npm registry.
24 error 404 You should bug the author to publish it (or use the name yourself!)
25 error 404 Note that you can also install from a
26 error 404 tarball, folder, http url, or git url.
27 verbose exit [ 1, true ]

removeAnnotation

Hello,

I'm learning and I'm trying to remove an existing annotation with the removeAnnotation(annotation_id) method as follow.

`
$(".labels-container").on("click", ".remove-annotation", function () {

var annotation_id = String($(this).attr('id'));
console.log(' I get the annotation:', annotation_id);
anno.removeAnnotation(annotation_id);

})
`

But the image still shows the rectangle. Thanks in advance.

Footer class conflicts with Bootstrap

Great tool, just timeboxed adding to our app. Unfortunately the pop up editor uses a class called "footer" which conflicts with a Bootstrap class of the same name. I edited code in min.js just as work around. Might be worth changing footer to annofooter or some such to improve Bootstrap interop.

(UX) When adding tag, don't require pressing Enter to save tag

In Microsoft Edge, I can add a tag , however, the tag is not saved unless you press Enter on the keyboard. Can we make it so if the user also clicks elsewhere in the annotation UI the tag will also be saved? Sometimes I will forget to press Enter when adding tags.

Weird interaction in demo page

Firefox 75.0 - Windows 10

When I start a rectangle outside the already drawn rectangle, as soon as I enter the first rectangle, selection goes wildly in other directions.

Minimal popup?

For most people, the full RecogitoJS popup config might be overkill. Perhaps think of a massively simplified widget set (and a more compact CSS theme)?

Code for this should probably go into the ˋrecogito-client-addonsˋ repo.

window is not defined

Hi,

I am trying to integrate this module into my NextJs web application but I am facing this error message "window is not defined" while trying to import the module. Is there any solution for this?

Below is my code:
import { Annotorious } from "@recogito/annotorious";

Below is the error message:
`Server Error
ReferenceError: window is not defined

This error happened while generating the page. Any console logs will be displayed in the terminal window.
Source
external%20%22@recogito\annotorious%22 (1:0) @ Object.@recogito/annotorious

1 | module.exports = require("@recogito/annotorious");`

Please help, thank you!

Touch support

The old Annotorious was fairly usable on touch (with proper care...)

Readme

The Readme is really bad right now. Clean up - and link to the Wiki! (Also, replace the logo with a high-res version.)

Error: \node_modules\@recogito\annotorious\src\index.js: Unexpected token (47:6)

Hi,

The demo example on this (https://www.npmjs.com/package/@recogito/annotorious) and the github page worked fine when using simple index and js files with "python -m http.server" but I was then planing for the big project.

I developed whole backend in Node.js using this library but now when I implemented it in React.js by the method that is written in the same pages as the following steps

  1. npm i @recogito/annotorious
  2. import { Annotorious } from '@recogito/annotorious';
  3. const anno = new Annotorious({ image: 'annotoriousLabels' });

but It produces error on step no. 2 (import), below is the error picture
image

And the component file in which I'm including it is as following:

`import React from "react";
// @material-ui/core components
import { makeStyles } from "@material-ui/core/styles";
// core components
import GridItem from "components/Grid/GridItem.js";
import GridContainer from "components/Grid/GridContainer.js";
import Button from "components/CustomButtons/Button.js";
import Card from "components/Card/Card.js";
import CardHeader from "components/Card/CardHeader.js";
import CardBody from "components/Card/CardBody.js";
import CardFooter from "components/Card/CardFooter.js";

import { Annotorious } from '@recogito/annotorious';

import { apiURL } from '../../../config';
// import an from './annotorious';

const styles = {
cardCategoryWhite: {
color: "rgba(255,255,255,.62)",
margin: "0",
fontSize: "14px",
marginTop: "0",
marginBottom: "0"
},
cardTitleWhite: {
color: "#FFFFFF",
marginTop: "0px",
minHeight: "auto",
fontWeight: "300",
fontFamily: "'Roboto', 'Helvetica', 'Arial', sans-serif",
marginBottom: "3px",
textDecoration: "none"
}
};

const useStyles = makeStyles(styles);

const ImageCard = (props) => {
const classes = useStyles();

const anno = new Annotorious({ image: 'annotoriousLabels' });

return (






Picture


Please label the picture below.




<img
className = "annotatable"
id = "annotoriousLabels"
src = {apiURL + '/' + props.photo.url}
alt = "To be labelled..."
width = '100%'
height = '100%'
/>


Save Changes





);
}

export default ImageCard;
`

Annotation box does not appear in online demo on first visit

When I view the online demo for the first time, I don't see any annotation boxes. Here's what I see in Edge and Chrome when I visit the demo link:

image

However, when I refresh the page, the annotation box does appear.

Not sure if it's an issue on my end.

Mouse coords vs. SVG coords

There is a mix in some places between SVG coordinates and DOM element offsets. Make sure all mouse coordinates are always transformed to SVG coordinates for drawing operations. That will make sure drawing also works correctly on scaled/responsive images.

Bonus benefit: once that is implemented, we should be able to reuse this as-is for the OpenSeadragon implementation.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.