From 5ae9be7fa0360d9a363b4ce2df872e553f97c581 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 11:26:26 +0300 Subject: [PATCH 01/12] Disabled tracks for polyshapes in UI --- .../standard-workspace/controls-side-bar/draw-shape-popover.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index 769b5d140940..138d05761b04 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -139,6 +139,7 @@ function DrawShapePopoverComponent(props: Props): JSX.Element { From 1261476f4a75aa3c447facda683d92a03c6cb77a Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 11:56:21 +0300 Subject: [PATCH 02/12] RectDrawingMethod enum pushed to cvat-canvas, fixed some code issues --- cvat-canvas/README.md | 8 +++++++- cvat-canvas/src/typescript/canvas.ts | 2 ++ cvat-canvas/src/typescript/canvasModel.ts | 8 ++++++-- cvat-canvas/src/typescript/drawHandler.ts | 13 +++++++------ cvat-ui/src/actions/annotation-actions.ts | 3 ++- .../controls-side-bar/draw-shape-popover.tsx | 13 ++++++------- .../controls-side-bar/draw-shape-popover.tsx | 19 +++++++++---------- cvat-ui/src/cvat-canvas.ts | 2 ++ cvat-ui/src/reducers/interfaces.ts | 7 +------ 9 files changed, 42 insertions(+), 33 deletions(-) diff --git a/cvat-canvas/README.md b/cvat-canvas/README.md index 38806d245e14..fe216817f139 100644 --- a/cvat-canvas/README.md +++ b/cvat-canvas/README.md @@ -37,10 +37,15 @@ Canvas itself handles: CLOCKWISE90, } + enum RectDrawingMethod { + CLASSIC = 'By 2 points', + EXTREME_POINTS = 'By 4 points' + } + interface DrawData { enabled: boolean; shapeType?: string; - rectDrawingMethod?: string; + rectDrawingMethod?: RectDrawingMethod; numberOfPoints?: number; initialState?: any; crosshair?: boolean; @@ -147,6 +152,7 @@ Standard JS events are used. enabled: true, shapeType: 'rectangle', crosshair: true, + rectDrawingMethod: window.Canvas.RectDrawingMethod.CLASSIC, }); ``` diff --git a/cvat-canvas/src/typescript/canvas.ts b/cvat-canvas/src/typescript/canvas.ts index 4ddb2deb4a81..66af0ce8848d 100644 --- a/cvat-canvas/src/typescript/canvas.ts +++ b/cvat-canvas/src/typescript/canvas.ts @@ -10,6 +10,7 @@ import { GroupData, CanvasModel, CanvasModelImpl, + RectDrawingMethod, } from './canvasModel'; import { @@ -141,4 +142,5 @@ export { CanvasImpl as Canvas, Rotation, CanvasVersion, + RectDrawingMethod, }; diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts index 28a0a48f41e2..1fc273a6811c 100644 --- a/cvat-canvas/src/typescript/canvasModel.ts +++ b/cvat-canvas/src/typescript/canvasModel.ts @@ -4,7 +4,6 @@ import { MasterImpl } from './master'; - export interface Size { width: number; height: number; @@ -36,10 +35,15 @@ export interface ActiveElement { attributeID: number | null; } +export enum RectDrawingMethod { + CLASSIC = 'By 2 points', + EXTREME_POINTS = 'By 4 points' +} + export interface DrawData { enabled: boolean; shapeType?: string; - rectDrawingMethod?: string; + rectDrawingMethod?: RectDrawingMethod; numberOfPoints?: number; initialState?: any; crosshair?: boolean; diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index 2a17b0a4ba65..54ce1cfdf52a 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -10,6 +10,7 @@ import './svg.patch'; import { DrawData, Geometry, + RectDrawingMethod, } from './canvasModel'; import { @@ -160,7 +161,7 @@ export class DrawHandlerImpl implements DrawHandler { const { drawInstance } = this; this.drawInstance = null; if (this.drawData.shapeType === 'rectangle' - && this.drawData.rectDrawingMethod !== 'by_four_points') { + && this.drawData.rectDrawingMethod !== RectDrawingMethod.EXTREME_POINTS) { drawInstance.draw('cancel'); } else { drawInstance.draw('done'); @@ -206,10 +207,10 @@ export class DrawHandlerImpl implements DrawHandler { .addClass('cvat_canvas_shape_drawing').attr({ 'stroke-width': 0, opacity: 0, - }).on('drawstart', () => { + }).on('drawstart', (): void => { // init numberOfPoints as one on drawstart numberOfPoints = 1; - }).on('drawpoint', (e: CustomEvent) => { + }).on('drawpoint', (e: CustomEvent): void => { // increase numberOfPoints by one on drawpoint numberOfPoints += 1; @@ -227,11 +228,11 @@ export class DrawHandlerImpl implements DrawHandler { this.onDrawDone(null); } } - }).on('undopoint', () => { + }).on('undopoint', (): void => { if (numberOfPoints > 0) { numberOfPoints -= 1; } - }).off('drawdone').on('drawdone', () => { + }).on('drawdone', (): void => { // close drawing mode without drawing rect this.onDrawDone(null); }); @@ -578,7 +579,7 @@ export class DrawHandlerImpl implements DrawHandler { this.setupPasteEvents(); } else { if (this.drawData.shapeType === 'rectangle') { - if (this.drawData.rectDrawingMethod === 'by_four_points') { + if (this.drawData.rectDrawingMethod === RectDrawingMethod.EXTREME_POINTS) { // draw box by extreme clicking this.drawBoxBy4Points(); } else { diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index 759d92be64dc..62c95586afc4 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -20,6 +20,7 @@ import { } from 'reducers/interfaces'; import getCore from 'cvat-core'; +import { RectDrawingMethod } from 'cvat-canvas'; import { getCVATStore } from 'cvat-store'; const cvat = getCore(); @@ -807,7 +808,7 @@ export function drawShape( labelID: number, objectType: ObjectType, points?: number, - rectDrawingMethod?: string, + rectDrawingMethod?: RectDrawingMethod, ): AnyAction { let activeControl = ActiveControl.DRAW_RECTANGLE; if (shapeType === ShapeType.POLYGON) { diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index 138d05761b04..d504c597175e 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -16,10 +16,8 @@ import { import { RadioChangeEvent } from 'antd/lib/radio'; import Text from 'antd/lib/typography/Text'; -import { - ShapeType, - RectDrawingMethod, -} from 'reducers/interfaces'; +import { RectDrawingMethod } from 'cvat-canvas'; +import { ShapeType } from 'reducers/interfaces'; interface Props { shapeType: ShapeType; @@ -42,6 +40,7 @@ function DrawShapePopoverComponent(props: Props): JSX.Element { minimumPoints, selectedLabeID, numberOfPoints, + rectDrawingMethod, onDrawTrack, onDrawShape, onChangeLabel, @@ -92,17 +91,17 @@ function DrawShapePopoverComponent(props: Props): JSX.Element { By 2 Points By 4 Points diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index edea8b3ebf2a..61a67820a764 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -10,13 +10,12 @@ import { CombinedState, ShapeType, ObjectType, - RectDrawingMethod, } from 'reducers/interfaces'; import { drawShape, } from 'actions/annotation-actions'; -import { Canvas } from 'cvat-canvas'; +import { Canvas, RectDrawingMethod } from 'cvat-canvas'; import DrawShapePopoverComponent from 'components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover'; interface OwnProps { @@ -29,7 +28,7 @@ interface DispatchToProps { labelID: number, objectType: ObjectType, points?: number, - rectDrawingMethod?: string, + rectDrawingMethod?: RectDrawingMethod, ): void; } @@ -46,7 +45,7 @@ function mapDispatchToProps(dispatch: any): DispatchToProps { labelID: number, objectType: ObjectType, points?: number, - rectDrawingMethod?: string, + rectDrawingMethod?: RectDrawingMethod, ): void { dispatch(drawShape(shapeType, labelID, objectType, points, rectDrawingMethod)); }, @@ -75,7 +74,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps { type Props = StateToProps & DispatchToProps; interface State { - rectDrawingMethod?: string; + rectDrawingMethod: RectDrawingMethod; numberOfPoints?: number; selectedLabelID: number; } @@ -85,13 +84,14 @@ class DrawShapePopoverContainer extends React.PureComponent { constructor(props: Props) { super(props); + const { shapeType } = props; const defaultLabelID = props.labels[0].id; - const defaultRectDrawingMethod = RectDrawingMethod.BY_TWO_POINTS; + const defaultRectDrawingMethod = RectDrawingMethod.CLASSIC; this.state = { selectedLabelID: defaultLabelID, + rectDrawingMethod: defaultRectDrawingMethod, }; - const { shapeType } = props; if (shapeType === ShapeType.POLYGON) { this.minimumPoints = 3; } @@ -101,9 +101,6 @@ class DrawShapePopoverContainer extends React.PureComponent { if (shapeType === ShapeType.POINTS) { this.minimumPoints = 1; } - if (shapeType === ShapeType.RECTANGLE) { - this.state.rectDrawingMethod = defaultRectDrawingMethod; - } } private onDraw(objectType: ObjectType): void { @@ -166,6 +163,7 @@ class DrawShapePopoverContainer extends React.PureComponent { public render(): JSX.Element { const { + rectDrawingMethod, selectedLabelID, numberOfPoints, } = this.state; @@ -182,6 +180,7 @@ class DrawShapePopoverContainer extends React.PureComponent { minimumPoints={this.minimumPoints} selectedLabeID={selectedLabelID} numberOfPoints={numberOfPoints} + rectDrawingMethod={rectDrawingMethod} onChangeLabel={this.onChangeLabel} onChangePoints={this.onChangePoints} onChangeRectDrawingMethod={this.onChangeRectDrawingMethod} diff --git a/cvat-ui/src/cvat-canvas.ts b/cvat-ui/src/cvat-canvas.ts index 399174d3be89..8ca0cd28ed41 100644 --- a/cvat-ui/src/cvat-canvas.ts +++ b/cvat-ui/src/cvat-canvas.ts @@ -6,10 +6,12 @@ import { Canvas, Rotation, CanvasVersion, + RectDrawingMethod, } from '../../cvat-canvas/src/typescript/canvas'; export { Canvas, Rotation, CanvasVersion, + RectDrawingMethod, }; diff --git a/cvat-ui/src/reducers/interfaces.ts b/cvat-ui/src/reducers/interfaces.ts index dae5a2670d96..caf814b587f3 100644 --- a/cvat-ui/src/reducers/interfaces.ts +++ b/cvat-ui/src/reducers/interfaces.ts @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: MIT -import { Canvas } from 'cvat-canvas'; +import { Canvas, RectDrawingMethod } from 'cvat-canvas'; export type StringObject = { [index: string]: string; @@ -251,11 +251,6 @@ export enum ActiveControl { EDIT = 'edit', } -export enum RectDrawingMethod { - BY_TWO_POINTS = 'by_two_points', - BY_FOUR_POINTS = 'by_four_points' -} - export enum ShapeType { RECTANGLE = 'rectangle', POLYGON = 'polygon', From fb3061594975344646b383b8f791207ef1d5dced Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 12:04:32 +0300 Subject: [PATCH 03/12] Optional arguments --- .../controls-side-bar/draw-shape-popover.tsx | 2 +- .../controls-side-bar/draw-shape-popover.tsx | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index d504c597175e..9ee0f8a95c31 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -21,9 +21,9 @@ import { ShapeType } from 'reducers/interfaces'; interface Props { shapeType: ShapeType; - rectDrawingMethod: RectDrawingMethod; labels: any[]; minimumPoints: number; + rectDrawingMethod?: RectDrawingMethod; numberOfPoints?: number; selectedLabeID: number; onChangeLabel(value: string): void; diff --git a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx index 61a67820a764..8d418e68b71c 100644 --- a/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx +++ b/cvat-ui/src/containers/annotation-page/standard-workspace/controls-side-bar/draw-shape-popover.tsx @@ -74,7 +74,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps { type Props = StateToProps & DispatchToProps; interface State { - rectDrawingMethod: RectDrawingMethod; + rectDrawingMethod?: RectDrawingMethod; numberOfPoints?: number; selectedLabelID: number; } @@ -89,7 +89,8 @@ class DrawShapePopoverContainer extends React.PureComponent { const defaultRectDrawingMethod = RectDrawingMethod.CLASSIC; this.state = { selectedLabelID: defaultLabelID, - rectDrawingMethod: defaultRectDrawingMethod, + rectDrawingMethod: shapeType === ShapeType.RECTANGLE + ? defaultRectDrawingMethod : undefined, }; if (shapeType === ShapeType.POLYGON) { @@ -126,7 +127,7 @@ class DrawShapePopoverContainer extends React.PureComponent { }); onDrawStart(shapeType, selectedLabelID, - objectType, numberOfPoints); + objectType, numberOfPoints, rectDrawingMethod); } private onChangeRectDrawingMethod = (event: RadioChangeEvent): void => { From a08a234f1f8a81f5fed126798124a99c4975fd4a Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 12:17:11 +0300 Subject: [PATCH 04/12] Draw a text for locked shapes, some fixes with not keyframe shapes --- cvat-canvas/src/typescript/canvasView.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 808b8a171fea..2b959c1c25b5 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -1060,22 +1060,17 @@ export class CanvasViewImpl implements CanvasView, Listener { const [state] = this.controller.objects .filter((_state: any): boolean => _state.clientID === clientID); - if (!state) { - return; - } - - if (state.shapeType === 'points') { + if (state && state.shapeType === 'points') { this.svgShapes[clientID].remember('_selectHandler').nested .style('pointer-events', state.lock ? 'none' : ''); } - if (state.hidden || state.lock) { + if (!state || state.hidden || state.outside) { return; } this.activeElement = { ...activeElement }; const shape = this.svgShapes[clientID]; - shape.addClass('cvat_canvas_shape_activated'); let text = this.svgTexts[clientID]; // Draw text if it's hidden by default if (!text) { @@ -1087,7 +1082,11 @@ export class CanvasViewImpl implements CanvasView, Listener { ); } - const self = this; + if (state.lock) { + return; + } + + shape.addClass('cvat_canvas_shape_activated'); if (state.shapeType === 'points') { this.content.append(this.svgShapes[clientID] .remember('_selectHandler').nested.node); @@ -1103,7 +1102,7 @@ export class CanvasViewImpl implements CanvasView, Listener { }).on('dragend', (e: CustomEvent): void => { if (text) { text.removeClass('cvat_canvas_hidden'); - self.updateTextPosition( + this.updateTextPosition( text, shape, ); @@ -1153,7 +1152,7 @@ export class CanvasViewImpl implements CanvasView, Listener { if (text) { text.removeClass('cvat_canvas_hidden'); - self.updateTextPosition( + this.updateTextPosition( text, shape, ); From 50f3c7d0ce23a10bc72743f9cc7345068e0651db Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 12:25:15 +0300 Subject: [PATCH 05/12] Fixed zooming & batch grouping --- cvat-canvas/src/typescript/canvasView.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 2b959c1c25b5..bf5ab5d9b3a8 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -626,7 +626,9 @@ export class CanvasViewImpl implements CanvasView, Listener { this.content.addEventListener('mousedown', (event): void => { if ([1, 2].includes(event.which)) { - self.controller.enableDrag(event.clientX, event.clientY); + if (![Mode.ZOOM_CANVAS, Mode.GROUP].includes(this.mode) || event.which === 2) { + self.controller.enableDrag(event.clientX, event.clientY); + } event.preventDefault(); } }); @@ -1072,7 +1074,6 @@ export class CanvasViewImpl implements CanvasView, Listener { this.activeElement = { ...activeElement }; const shape = this.svgShapes[clientID]; let text = this.svgTexts[clientID]; - // Draw text if it's hidden by default if (!text) { text = this.addText(state); this.svgTexts[state.clientID] = text; From ed59bd5cd45970359affc48e45b7dd883a70f740 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 12:31:03 +0300 Subject: [PATCH 06/12] Reset zoom for tasks with images --- cvat-ui/src/reducers/settings-reducer.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index 90aacf756363..d5dd7516066c 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -4,6 +4,7 @@ import { AnyAction } from 'redux'; import { SettingsActionTypes } from 'actions/settings-actions'; +import { AnnotationActionTypes } from 'actions/annotation-actions'; import { SettingsState, @@ -213,6 +214,17 @@ export default (state = defaultState, action: AnyAction): SettingsState => { }, }; } + case AnnotationActionTypes.GET_JOB_SUCCESS: { + const { job } = action.payload; + + return { + ...state, + player: { + ...state.player, + resetZoom: job && job.task.mode === 'annotation', + }, + }; + } default: { return state; } From 2d7fdb38553dded718f7bea74b84cdb13d6cfd7d Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 12:39:33 +0300 Subject: [PATCH 07/12] Fixed putting shapes out of canvas --- cvat-canvas/src/typescript/canvasView.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index bf5ab5d9b3a8..dfe988773cc2 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -125,6 +125,7 @@ export class CanvasViewImpl implements CanvasView, Listener { }, }); + this.drawnStates[state.clientID].points = points; this.canvas.dispatchEvent(event); } else { const event: CustomEvent = new CustomEvent('canvas.canceled', { From d10b034133cd3c0592e2462dff4b6f4fabbec7f9 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 12:58:22 +0300 Subject: [PATCH 08/12] Fixed grid opacity, little refactoring of componentDidUpdate in canvas-wrapper component --- cvat-canvas/src/typescript/canvasView.ts | 3 +- cvat-canvas/src/typescript/consts.ts | 2 +- .../standard-workspace/canvas-wrapper.tsx | 42 ++++--------------- cvat-ui/src/reducers/settings-reducer.ts | 2 +- 4 files changed, 12 insertions(+), 37 deletions(-) diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index dfe988773cc2..0c470350841d 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -552,7 +552,8 @@ export class CanvasViewImpl implements CanvasView, Listener { this.grid.setAttribute('version', '2'); this.gridPath.setAttribute('d', 'M 1000 0 L 0 0 0 1000'); this.gridPath.setAttribute('fill', 'none'); - this.gridPath.setAttribute('stroke-width', '1.5'); + this.gridPath.setAttribute('stroke-width', `${consts.BASE_GRID_WIDTH}`); + this.gridPath.setAttribute('opacity', 'inherit'); this.gridPattern.setAttribute('id', 'cvat_canvas_grid_pattern'); this.gridPattern.setAttribute('width', '100'); this.gridPattern.setAttribute('height', '100'); diff --git a/cvat-canvas/src/typescript/consts.ts b/cvat-canvas/src/typescript/consts.ts index 6b1ab234a75f..1c36351dddf6 100644 --- a/cvat-canvas/src/typescript/consts.ts +++ b/cvat-canvas/src/typescript/consts.ts @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MIT const BASE_STROKE_WIDTH = 1.75; -const BASE_GRID_WIDTH = 1; +const BASE_GRID_WIDTH = 2; const BASE_POINT_SIZE = 5; const TEXT_MARGIN = 10; const AREA_THRESHOLD = 9; diff --git a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx index fbcb5077d36a..d95b901a0d25 100644 --- a/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx +++ b/cvat-ui/src/components/annotation-page/standard-workspace/canvas-wrapper.tsx @@ -100,10 +100,6 @@ export default class CanvasWrapperComponent extends React.PureComponent { colorBy, selectedOpacity, blackBorders, - grid, - gridSize, - gridColor, - gridOpacity, frameData, annotations, canvasInstance, @@ -122,34 +118,12 @@ export default class CanvasWrapperComponent extends React.PureComponent { } } - if (prevProps.grid !== grid) { - const gridElement = window.document.getElementById('cvat_canvas_grid'); - if (gridElement) { - gridElement.style.display = grid ? 'block' : 'none'; - } - } - - if (prevProps.gridSize !== gridSize) { - canvasInstance.grid(gridSize, gridSize); - } - - if (prevProps.gridColor !== gridColor) { - const gridPattern = window.document.getElementById('cvat_canvas_grid_pattern'); - if (gridPattern) { - gridPattern.style.stroke = gridColor.toLowerCase(); - } - } - - if (prevProps.gridOpacity !== gridOpacity) { - const gridPattern = window.document.getElementById('cvat_canvas_grid_pattern'); - if (gridPattern) { - gridPattern.style.opacity = `${gridOpacity / 100}`; - } - } - if (prevProps.activatedStateID !== null && prevProps.activatedStateID !== activatedStateID) { canvasInstance.activate(null); + } + + if (activatedStateID) { const el = window.document.getElementById(`cvat_canvas_shape_${prevProps.activatedStateID}`); if (el) { (el as any).instance.fill({ opacity: opacity / 100 }); @@ -160,17 +134,17 @@ export default class CanvasWrapperComponent extends React.PureComponent { this.updateCanvas(); } - if (prevProps.opacity !== opacity || prevProps.blackBorders !== blackBorders - || prevProps.selectedOpacity !== selectedOpacity || prevProps.colorBy !== colorBy) { - this.updateShapesView(); - } - if (prevProps.frame !== frameData.number && resetZoom) { canvasInstance.html().addEventListener('canvas.setup', () => { canvasInstance.fit(); }, { once: true }); } + if (prevProps.opacity !== opacity || prevProps.blackBorders !== blackBorders + || prevProps.selectedOpacity !== selectedOpacity || prevProps.colorBy !== colorBy) { + this.updateShapesView(); + } + if (prevProps.curZLayer !== curZLayer) { canvasInstance.setZLayer(curZLayer); } diff --git a/cvat-ui/src/reducers/settings-reducer.ts b/cvat-ui/src/reducers/settings-reducer.ts index d5dd7516066c..c9f82e81d13b 100644 --- a/cvat-ui/src/reducers/settings-reducer.ts +++ b/cvat-ui/src/reducers/settings-reducer.ts @@ -34,7 +34,7 @@ const defaultState: SettingsState = { grid: false, gridSize: 100, gridColor: GridColor.White, - gridOpacity: 0, + gridOpacity: 100, brightnessLevel: 100, contrastLevel: 100, saturationLevel: 100, From 8d88aa713140b04c76445a46f90bce28af886e0c Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 13:27:35 +0300 Subject: [PATCH 09/12] Fixed corner cases for drawing --- cvat-canvas/src/typescript/drawHandler.ts | 30 +++++++++++------------ 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index 54ce1cfdf52a..0d177e59e8da 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -125,14 +125,7 @@ export class DrawHandlerImpl implements DrawHandler { } if (this.drawInstance) { - // Draw plugin isn't activated when draw from initialState - // So, we don't need to use any draw events - if (!this.drawData.initialState) { - this.drawInstance.off('drawdone'); - this.drawInstance.off('drawstop'); - this.drawInstance.draw('stop'); - } - + this.drawInstance.off(); this.drawInstance.remove(); this.drawInstance = null; } @@ -155,27 +148,32 @@ export class DrawHandlerImpl implements DrawHandler { private closeDrawing(): void { if (this.drawInstance) { - // Draw plugin isn't activated when draw from initialState - // So, we don't need to use any draw events - if (!this.drawData.initialState) { + // Draw plugin in some cases isn't activated + // For example when draw from initialState + // Or when no drawn points, but we call cancel() drawing + // We check if it is activated with remember function + if (this.drawInstance.remember('_paintHandler')) { const { drawInstance } = this; + + // set this.drawInstance to null to avoid stackoverflow + // calling closeDrawing recursively + // onDrawDone => controller => model => view => closeDrawing this.drawInstance = null; + if (this.drawData.shapeType === 'rectangle' - && this.drawData.rectDrawingMethod !== RectDrawingMethod.EXTREME_POINTS) { + && this.drawData.rectDrawingMethod !== RectDrawingMethod.EXTREME_POINTS) { drawInstance.draw('cancel'); } else { drawInstance.draw('done'); } + + // Now we assign drawInstance back to right work of release() this.drawInstance = drawInstance; this.release(); } else { this.release(); this.onDrawDone(null); } - - // here is a cycle - // onDrawDone => controller => model => view => closeDrawing - // one call of closeDrawing is unuseful, but it's okey } } From 280e89845e94cfa601a53deb4986128ace0030a8 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 13:31:10 +0300 Subject: [PATCH 10/12] Fixed putting shapes out of canvas --- cvat-canvas/src/typescript/canvasView.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 0c470350841d..f43281ebf1ad 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -125,7 +125,6 @@ export class CanvasViewImpl implements CanvasView, Listener { }, }); - this.drawnStates[state.clientID].points = points; this.canvas.dispatchEvent(event); } else { const event: CustomEvent = new CustomEvent('canvas.canceled', { @@ -1124,6 +1123,7 @@ export class CanvasViewImpl implements CanvasView, Listener { + `${shape.attr('y') + shape.attr('height')}`, ).map((x: number): number => x - offset); + this.drawnStates[state.clientID].points = points; this.onEditDone(state, points); } }); @@ -1172,6 +1172,7 @@ export class CanvasViewImpl implements CanvasView, Listener { + `${shape.attr('y') + shape.attr('height')}`, ).map((x: number): number => x - offset); + this.drawnStates[state.clientID].points = points; this.onEditDone(state, points); } }); From 66248a151fcdce8c0b664bc9530e613d4c3e55bf Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 14:26:18 +0300 Subject: [PATCH 11/12] Improved drawing --- cvat-canvas/src/typescript/canvasView.ts | 10 ++- cvat-canvas/src/typescript/drawHandler.ts | 99 ++++++++++------------- 2 files changed, 47 insertions(+), 62 deletions(-) diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index f43281ebf1ad..4ce4c536f827 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -106,11 +106,10 @@ export class CanvasViewImpl implements CanvasView, Listener { this.geometry, ); } else { + this.mode = Mode.IDLE; this.controller.draw({ enabled: false, }); - - this.mode = Mode.IDLE; } } @@ -763,13 +762,16 @@ export class CanvasViewImpl implements CanvasView, Listener { } } else if (reason === UpdateReasons.DRAW) { const data: DrawData = this.controller.drawData; - if (data.enabled) { + if (data.enabled && this.mode === Mode.IDLE) { this.canvas.style.cursor = 'crosshair'; this.mode = Mode.DRAW; + this.drawHandler.draw(data, this.geometry); } else { this.canvas.style.cursor = ''; + if (this.mode !== Mode.IDLE) { + this.drawHandler.draw(data, this.geometry); + } } - this.drawHandler.draw(data, this.geometry); } else if (reason === UpdateReasons.MERGE) { const data: MergeData = this.controller.mergeData; if (data.enabled) { diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index 0d177e59e8da..873663528569 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -44,6 +44,7 @@ export class DrawHandlerImpl implements DrawHandler { // we should use any instead of SVG.Shape because svg plugins cannot change declared interface // so, methods like draw() just undefined for SVG.Shape, but nevertheless they exist private drawInstance: any; + private initialized: boolean; private pointsGroup: SVG.G | null; private shapeSizeElement: ShapeSizeElement; @@ -114,6 +115,12 @@ export class DrawHandlerImpl implements DrawHandler { } private release(): void { + if (!this.initialized) { + // prevents recursive calls + return; + } + + this.initialized = false; this.canvas.off('mousedown.draw'); this.canvas.off('mouseup.draw'); this.canvas.off('mousemove.draw'); @@ -124,11 +131,21 @@ export class DrawHandlerImpl implements DrawHandler { this.pointsGroup = null; } - if (this.drawInstance) { - this.drawInstance.off(); - this.drawInstance.remove(); - this.drawInstance = null; + // Draw plugin in some cases isn't activated + // For example when draw from initialState + // Or when no drawn points, but we call cancel() drawing + // We check if it is activated with remember function + if (this.drawInstance.remember('_paintHandler')) { + if (this.drawData.shapeType !== 'rectangle') { + // Check for unsaved drawn shapes + this.drawInstance.draw('done'); + } + // Clear drawing + this.drawInstance.draw('stop'); } + this.drawInstance.off(); + this.drawInstance.remove(); + this.drawInstance = null; if (this.shapeSizeElement) { this.shapeSizeElement.rm(); @@ -146,50 +163,19 @@ export class DrawHandlerImpl implements DrawHandler { } } - private closeDrawing(): void { - if (this.drawInstance) { - // Draw plugin in some cases isn't activated - // For example when draw from initialState - // Or when no drawn points, but we call cancel() drawing - // We check if it is activated with remember function - if (this.drawInstance.remember('_paintHandler')) { - const { drawInstance } = this; - - // set this.drawInstance to null to avoid stackoverflow - // calling closeDrawing recursively - // onDrawDone => controller => model => view => closeDrawing - this.drawInstance = null; - - if (this.drawData.shapeType === 'rectangle' - && this.drawData.rectDrawingMethod !== RectDrawingMethod.EXTREME_POINTS) { - drawInstance.draw('cancel'); - } else { - drawInstance.draw('done'); - } - - // Now we assign drawInstance back to right work of release() - this.drawInstance = drawInstance; - this.release(); - } else { - this.release(); - this.onDrawDone(null); - } - } - } - private drawBox(): void { this.drawInstance = this.canvas.rect(); this.drawInstance.on('drawstop', (e: Event): void => { const bbox = (e.target as SVGRectElement).getBBox(); const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox); + const { shapeType } = this.drawData; + this.cancel(); if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) { this.onDrawDone({ - shapeType: this.drawData.shapeType, + shapeType, points: [xtl, ytl, xbr, ybr], }); - } else { - this.onDrawDone(null); } }).on('drawupdate', (): void => { this.shapeSizeElement.update(this.drawInstance); @@ -216,14 +202,14 @@ export class DrawHandlerImpl implements DrawHandler { if (numberOfPoints === 4) { const bbox = (e.target as SVGPolylineElement).getBBox(); const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox); + const { shapeType } = this.drawData; + this.cancel(); if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) { this.onDrawDone({ - shapeType: this.drawData.shapeType, + shapeType, points: [xtl, ytl, xbr, ybr], }); - } else { - this.onDrawDone(null); } } }).on('undopoint', (): void => { @@ -232,7 +218,7 @@ export class DrawHandlerImpl implements DrawHandler { } }).on('drawdone', (): void => { // close drawing mode without drawing rect - this.onDrawDone(null); + this.cancel(); }); this.drawPolyshape(); @@ -307,34 +293,31 @@ export class DrawHandlerImpl implements DrawHandler { this.drawInstance.on('drawdone', (e: CustomEvent): void => { const targetPoints = pointsToArray((e.target as SVGElement).getAttribute('points')); - const { - points, - box, - } = this.getFinalPolyshapeCoordinates(targetPoints); + const { points, box } = this.getFinalPolyshapeCoordinates(targetPoints); + const { shapeType } = this.drawData; + this.cancel(); - if (this.drawData.shapeType === 'polygon' + if (shapeType === 'polygon' && ((box.xbr - box.xtl) * (box.ybr - box.ytl) >= consts.AREA_THRESHOLD) && points.length >= 3 * 2) { this.onDrawDone({ - shapeType: this.drawData.shapeType, + shapeType, points, }); - } else if (this.drawData.shapeType === 'polyline' + } else if (shapeType === 'polyline' && ((box.xbr - box.xtl) >= consts.SIZE_THRESHOLD || (box.ybr - box.ytl) >= consts.SIZE_THRESHOLD) && points.length >= 2 * 2) { this.onDrawDone({ - shapeType: this.drawData.shapeType, + shapeType, points, }); - } else if (this.drawData.shapeType === 'points' + } else if (shapeType === 'points' && (e.target as any).getAttribute('points') !== '0,0') { this.onDrawDone({ - shapeType: this.drawData.shapeType, + shapeType, points, }); - } else { - this.onDrawDone(null); } }); } @@ -595,6 +578,8 @@ export class DrawHandlerImpl implements DrawHandler { } this.setupDrawEvents(); } + + this.initialized = true; } public constructor( @@ -605,6 +590,7 @@ export class DrawHandlerImpl implements DrawHandler { this.onDrawDone = onDrawDone; this.canvas = canvas; this.text = text; + this.initialized = false; this.drawData = null; this.geometry = null; this.crosshair = null; @@ -685,7 +671,7 @@ export class DrawHandlerImpl implements DrawHandler { this.initDrawing(); this.startDraw(); } else { - this.closeDrawing(); + this.cancel(); this.drawData = drawData; } } @@ -693,8 +679,5 @@ export class DrawHandlerImpl implements DrawHandler { public cancel(): void { this.release(); this.onDrawDone(null); - // here is a cycle - // onDrawDone => controller => model => view => closeDrawing - // one call of closeDrawing is unuseful, but it's okey } } From a5fa3062d4dccec4239479c7f34665961a235935 Mon Sep 17 00:00:00 2001 From: Boris Sekachev Date: Fri, 28 Feb 2020 14:28:50 +0300 Subject: [PATCH 12/12] Removed extra event handler --- cvat-canvas/src/typescript/drawHandler.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index 873663528569..2413368f6f45 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -216,9 +216,6 @@ export class DrawHandlerImpl implements DrawHandler { if (numberOfPoints > 0) { numberOfPoints -= 1; } - }).on('drawdone', (): void => { - // close drawing mode without drawing rect - this.cancel(); }); this.drawPolyshape();