README.md
# Module CVAT-CANVAS
## Description
The CVAT module written in TypeScript language.
It presents a canvas to viewing, drawing and editing of annotations.
## Versioning
If you make changes in this package, please do following:
- After not important changes (typos, backward compatible bug fixes, refactoring) do: `yarn version --patch`
- After changing API (backward compatible new features) do: `yarn version --minor`
- After changing API (changes that break backward compatibility) do: `yarn version --major`
## Commands
- Building of the module from sources in the `dist` directory:
```bash
yarn run build
yarn run build --mode=development # without a minification
```
## Using
Canvas itself handles:
- Shape context menu (PKM)
- Image moving (mousedrag)
- Image resizing (mousewheel)
- Image fit (dblclick)
- Remove point (PKM)
- Polyshape editing (Shift + LKM)
### API Methods
```ts
enum RectDrawingMethod {
CLASSIC = 'By 2 points',
EXTREME_POINTS = 'By 4 points'
}
enum CuboidDrawingMethod {
CLASSIC = 'From rectangle',
CORNER_POINTS = 'By 4 points',
}
enum Mode {
IDLE = 'idle',
DRAG = 'drag',
RESIZE = 'resize',
DRAW = 'draw',
EDIT = 'edit',
MERGE = 'merge',
SPLIT = 'split',
GROUP = 'group',
INTERACT = 'interact',
SELECT_ROI = 'select_roi',
DRAG_CANVAS = 'drag_canvas',
ZOOM_CANVAS = 'zoom_canvas',
}
interface Configuration {
smoothImage?: boolean;
autoborders?: boolean;
displayAllText?: boolean;
textFontSize?: number;
textPosition?: 'auto' | 'center';
textContent?: string;
undefinedAttrValue?: string;
showProjections?: boolean;
forceDisableEditing?: boolean;
intelligentPolygonCrop?: boolean;
forceFrameUpdate?: boolean;
creationOpacity?: number;
CSSImageFilter?: string;
}
interface DrawData {
enabled: boolean;
shapeType?: string;
rectDrawingMethod?: RectDrawingMethod;
cuboidDrawingMethod?: CuboidDrawingMethod;
numberOfPoints?: number;
initialState?: any;
crosshair?: boolean;
}
interface InteractionData {
shapeType: string;
minVertices?: number;
}
interface GroupData {
enabled: boolean;
resetGroup?: boolean;
}
interface MergeData {
enabled: boolean;
}
interface SplitData {
enabled: boolean;
}
interface InteractionResult {
points: number[];
shapeType: string;
button: number;
};
interface DrawnData {
shapeType: string;
points: number[];
objectType?: string;
occluded?: boolean;
attributes?: [index: number]: string;
label?: Label;
color?: string;
}
interface Canvas {
html(): HTMLDivElement;
setup(frameData: any, objectStates: any[], zLayer?: number): void;
setupReviewROIs(reviewROIs: Record<number, number[]>): void;
activate(clientID: number | null, attributeID?: number): void;
rotate(rotationAngle: number): void;
focus(clientID: number, padding?: number): void;
fit(): void;
grid(stepX: number, stepY: number): void;
interact(interactionData: InteractionData): void;
draw(drawData: DrawData): void;
group(groupData: GroupData): void;
split(splitData: SplitData): void;
merge(mergeData: MergeData): void;
select(objectState: any): void;
fitCanvas(): void;
bitmap(enable: boolean): void;
selectROI(enable: boolean): void;
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;
mode(): Mode;
cancel(): void;
configure(configuration: Configuration): void;
isAbleToChangeFrame(): boolean;
destroy(): void;
readonly geometry: Geometry;
}
```
### API CSS
- All drawn objects (shapes, tracks) have an id `cvat_canvas_shape_{objectState.clientID}`
- Drawn shapes and tracks have classes `cvat_canvas_shape`,
`cvat_canvas_shape_activated`,
`cvat_canvas_shape_grouping`,
`cvat_canvas_shape_merging`,
`cvat_canvas_shape_drawing`,
`cvat_canvas_shape_occluded`
- Drawn review ROIs have an id `cvat_canvas_issue_region_{issue.id}`
- Drawn review roi has the class `cvat_canvas_issue_region`
- Drawn texts have the class `cvat_canvas_text`
- Tags have the class `cvat_canvas_tag`
- Canvas image has ID `cvat_canvas_image`
- Grid on the canvas has ID `cvat_canvas_grid` and `cvat_canvas_grid_pattern`
- Crosshair during a draw has class `cvat_canvas_crosshair`
- To stick something to a specific position you can use an element with id `cvat_canvas_attachment_board`
### Events
Standard JS events are used.
```js
- canvas.setup
- canvas.activated => {state: ObjectState}
- canvas.clicked => {state: ObjectState}
- canvas.moved => {states: ObjectState[], x: number, y: number}
- canvas.find => {states: ObjectState[], x: number, y: number}
- canvas.drawn => {state: DrawnData}
- canvas.interacted => {shapes: InteractionResult[]}
- canvas.editstart
- canvas.edited => {state: ObjectState, points: number[]}
- canvas.splitted => {state: ObjectState}
- canvas.groupped => {states: ObjectState[]}
- canvas.merged => {states: ObjectState[]}
- canvas.canceled
- canvas.dragstart
- canvas.dragstop
- canvas.zoomstart
- canvas.zoomstop
- canvas.zoom
- canvas.reshape
- canvas.fit
- canvas.dragshape => {id: number}
- canvas.roiselected => {points: number[]}
- canvas.resizeshape => {id: number}
- canvas.contextmenu => { mouseEvent: MouseEvent, objectState: ObjectState, pointID: number }
- canvas.error => { exception: Error }
- canvas.destroy
```
### WEB
```js
// Create an instance of a canvas
const canvas = new window.canvas.Canvas();
console.log('Version ', window.canvas.CanvasVersion);
console.log('Current mode is ', window.canvas.mode());
// Put canvas to a html container
htmlContainer.appendChild(canvas.html());
canvas.fitCanvas();
// Next you can use its API methods. For example:
canvas.rotate(270);
canvas.draw({
enabled: true,
shapeType: 'rectangle',
crosshair: true,
rectDrawingMethod: window.Canvas.RectDrawingMethod.CLASSIC,
});
```
<!--lint disable maximum-line-length-->
## API Reaction
| | IDLE | GROUP | SPLIT | DRAW | MERGE | EDIT | DRAG | RESIZE | ZOOM_CANVAS | DRAG_CANVAS | INTERACT |
| ----------------- | ---- | ----- | ----- | ---- | ----- | ---- | ---- | ------ | ----------- | ----------- | -------- |
| setup() | + | + | + | +/- | + | +/- | +/- | +/- | + | + | + |
| activate() | + | - | - | - | - | - | - | - | - | - | - |
| rotate() | + | + | + | + | + | + | + | + | + | + | + |
| focus() | + | + | + | + | + | + | + | + | + | + | + |
| fit() | + | + | + | + | + | + | + | + | + | + | + |
| grid() | + | + | + | + | + | + | + | + | + | + | + |
| draw() | + | - | - | + | - | - | - | - | - | - | - |
| interact() | + | - | - | - | - | - | - | - | - | - | + |
| split() | + | - | + | - | - | - | - | - | - | - | - |
| group() | + | + | - | - | - | - | - | - | - | - | - |
| merge() | + | - | - | - | + | - | - | - | - | - | - |
| fitCanvas() | + | + | + | + | + | + | + | + | + | + | + |
| dragCanvas() | + | - | - | - | - | - | + | - | - | + | - |
| zoomCanvas() | + | - | - | - | - | - | - | + | + | - | - |
| cancel() | - | + | + | + | + | + | + | + | + | + | + |
| configure() | + | + | + | + | + | + | + | + | + | + | + |
| bitmap() | + | + | + | + | + | + | + | + | + | + | + |
| setZLayer() | + | + | + | + | + | + | + | + | + | + | + |
| setupReviewROIs() | + | + | + | + | + | + | + | + | + | + | + |
| destroy() | + | + | + | + | + | + | + | + | + | + | + |
<!--lint enable maximum-line-length-->
You can call setup() during editing, dragging, and resizing only to update objects, not to change a frame.
You can change frame during draw only when you do not redraw an existing object
Other methods do not change state and can be used at any time.