diff --git a/CHANGELOG.md b/CHANGELOG.md index ffb4ca4928a8..6d6f5a9aaa8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Auto annotation, TF annotation and Auto segmentation apps (https://github.com/opencv/cvat/pull/1409) - Import works with truncated images now: "OSError:broken data stream" on corrupt images (https://github.com/opencv/cvat/pull/1430) +- Hide functionality (H) doesn't work () +- The highlighted attribute doesn't correspond to the chosen attribute in AAM () +- Inconvinient image shaking while drawing a polygon (hold Alt key during drawing/editing/grouping to drag an image) () +- Filter property "shape" doesn't work and extra operator in description () +- Block of text information doesn't disappear after deactivating for locked shapes () +- Annotation uploading fails in annotation view () +- UI freezes after canceling pasting with escape () - Duplicating keypoints in COCO export (https://github.com/opencv/cvat/pull/1435) ### Security diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts index f7f095ea3501..d07526c91bdf 100644 --- a/cvat-canvas/src/typescript/canvasModel.ts +++ b/cvat-canvas/src/typescript/canvasModel.ts @@ -368,7 +368,9 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { } public activate(clientID: number | null, attributeID: number | null): void { - if (this.data.activeElement.clientID === clientID) { + if (this.data.activeElement.clientID === clientID + && this.data.activeElement.attributeID === attributeID + ) { return; } diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 801dde519b50..4fbdadeb41db 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -98,7 +98,7 @@ export class CanvasViewImpl implements CanvasView, Listener { }); this.canvas.dispatchEvent(event); - } else { + } else if (!continueDraw) { const event: CustomEvent = new CustomEvent('canvas.canceled', { bubbles: false, cancelable: true, @@ -107,12 +107,7 @@ export class CanvasViewImpl implements CanvasView, Listener { this.canvas.dispatchEvent(event); } - if (continueDraw) { - this.drawHandler.draw( - this.controller.drawData, - this.geometry, - ); - } else { + if (!continueDraw) { this.mode = Mode.IDLE; this.controller.draw({ enabled: false, @@ -672,8 +667,10 @@ export class CanvasViewImpl implements CanvasView, Listener { }); this.content.addEventListener('mousedown', (event): void => { - if ([1, 2].includes(event.which)) { - if (![Mode.ZOOM_CANVAS, Mode.GROUP].includes(this.mode) || event.which === 2) { + if ([0, 1].includes(event.button)) { + if ([Mode.IDLE, Mode.DRAG, Mode.MERGE, Mode.SPLIT].includes(this.mode) + || event.button === 1 || event.altKey + ) { self.controller.enableDrag(event.clientX, event.clientY); } } @@ -1379,11 +1376,6 @@ export class CanvasViewImpl implements CanvasView, Listener { } }); - this.activeElement = { - ...this.activeElement, - clientID, - }; - this.canvas.dispatchEvent(new CustomEvent('canvas.activated', { bubbles: false, cancelable: true, @@ -1407,6 +1399,10 @@ export class CanvasViewImpl implements CanvasView, Listener { const { clientID, attributeID } = activeElement; if (clientID !== null && this.activeElement.clientID !== clientID) { this.activateShape(clientID); + this.activeElement = { + ...this.activeElement, + clientID, + }; } if (clientID !== null diff --git a/cvat-canvas/src/typescript/drawHandler.ts b/cvat-canvas/src/typescript/drawHandler.ts index 5878c8847cf6..327d845fa7f5 100644 --- a/cvat-canvas/src/typescript/drawHandler.ts +++ b/cvat-canvas/src/typescript/drawHandler.ts @@ -3,12 +3,10 @@ // SPDX-License-Identifier: MIT import * as SVG from 'svg.js'; -import consts from './consts'; import 'svg.draw.js'; import './svg.patch'; import { AutoborderHandler } from './autoborderHandler'; - import { translateToSVG, displayShapeSize, @@ -18,7 +16,7 @@ import { BBox, Box, } from './shared'; - +import consts from './consts'; import { DrawData, Geometry, @@ -136,7 +134,6 @@ export class DrawHandlerImpl implements DrawHandler { this.autoborderHandler.autoborder(false); this.initialized = false; this.canvas.off('mousedown.draw'); - this.canvas.off('mouseup.draw'); this.canvas.off('mousemove.draw'); this.canvas.off('click.draw'); @@ -171,9 +168,7 @@ export class DrawHandlerImpl implements DrawHandler { this.removeCrosshair(); } - if (!this.drawData.initialState) { - this.onDrawDone(null); - } + this.onDrawDone(null); } private initDrawing(): void { @@ -256,7 +251,7 @@ export class DrawHandlerImpl implements DrawHandler { // Add ability to cancel the latest drawn point this.canvas.on('mousedown.draw', (e: MouseEvent): void => { - if (e.which === 3) { + if (e.button === 2) { e.stopPropagation(); e.preventDefault(); this.drawInstance.draw('undo'); @@ -377,7 +372,10 @@ export class DrawHandlerImpl implements DrawHandler { .map((coord: string): number => +coord); const { points } = this.getFinalPolyshapeCoordinates(targetPoints); - this.release(); + if (!e.detail.originalEvent.ctrlKey) { + this.release(); + } + this.onDrawDone({ shapeType: this.drawData.initialState.shapeType, objectType: this.drawData.initialState.objectType, @@ -417,7 +415,10 @@ export class DrawHandlerImpl implements DrawHandler { this.drawInstance.on('done', (e: CustomEvent): void => { const bbox = this.drawInstance.node.getBBox(); const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox); - this.release(); + if (!e.detail.originalEvent.ctrlKey) { + this.release(); + } + this.onDrawDone({ shapeType: this.drawData.initialState.shapeType, objectType: this.drawData.initialState.objectType, @@ -502,54 +503,23 @@ export class DrawHandlerImpl implements DrawHandler { } private setupPasteEvents(): void { - let mouseX: number | null = null; - let mouseY: number | null = null; - this.canvas.on('mousedown.draw', (e: MouseEvent): void => { - if (e.which === 1) { - mouseX = e.clientX; - mouseY = e.clientY; - } - }); - - this.canvas.on('mouseup.draw', (e: MouseEvent): void => { - const threshold = 10; // px - if (e.which === 1) { - if (Math.sqrt( // l2 distance < threshold - ((mouseX - e.clientX) ** 2) - + ((mouseY - e.clientY) ** 2), - ) < threshold) { - this.drawInstance.fire('done', { originalEvent: e }); - } + if (e.button === 0 && !e.altKey) { + this.drawInstance.fire('done', { originalEvent: e }); } }); } private setupDrawEvents(): void { let initialized = false; - let mouseX: number | null = null; - let mouseY: number | null = null; this.canvas.on('mousedown.draw', (e: MouseEvent): void => { - if (e.which === 1) { - mouseX = e.clientX; - mouseY = e.clientY; - } - }); - - this.canvas.on('mouseup.draw', (e: MouseEvent): void => { - const threshold = 10; // px - if (e.which === 1) { - if (Math.sqrt( // l2 distance < threshold - ((mouseX - e.clientX) ** 2) - + ((mouseY - e.clientY) ** 2), - ) < threshold) { - if (!initialized) { - this.drawInstance.draw(e, { snapToGrid: 0.1 }); - initialized = true; - } else { - this.drawInstance.draw(e); - } + if (e.button === 0 && !e.altKey) { + if (!initialized) { + this.drawInstance.draw(e, { snapToGrid: 0.1 }); + initialized = true; + } else { + this.drawInstance.draw(e); } } }); diff --git a/cvat-canvas/src/typescript/editHandler.ts b/cvat-canvas/src/typescript/editHandler.ts index 41d03edcc028..74446096b542 100644 --- a/cvat-canvas/src/typescript/editHandler.ts +++ b/cvat-canvas/src/typescript/editHandler.ts @@ -95,13 +95,9 @@ export class EditHandlerImpl implements EditHandler { } private setupEditEvents(): void { - let mouseX: number | null = null; - let mouseY: number | null = null; - this.canvas.on('mousedown.edit', (e: MouseEvent): void => { - if (e.button === 0) { - mouseX = e.clientX; - mouseY = e.clientY; + if (e.button === 0 && !e.altKey) { + (this.editLine as any).draw('point', e); } else if (e.button === 2 && this.editLine) { if (this.editData.state.shapeType === 'points' || this.editLine.attr('points').split(' ').length > 2 @@ -110,18 +106,6 @@ export class EditHandlerImpl implements EditHandler { } } }); - - this.canvas.on('mouseup.edit', (e: MouseEvent): void => { - const threshold = 10; // px - if (e.button === 0) { - if (Math.sqrt( // l2 distance < threshold - ((mouseX - e.clientX) ** 2) - + ((mouseY - e.clientY) ** 2), - ) < threshold) { - (this.editLine as any).draw('point', e); - } - } - }); } private selectPolygon(shape: SVG.Polygon): void { @@ -192,7 +176,6 @@ export class EditHandlerImpl implements EditHandler { // We do not need these events any more this.canvas.off('mousedown.edit'); - this.canvas.off('mouseup.edit'); this.canvas.off('mousemove.edit'); (this.editLine as any).draw('stop'); @@ -274,7 +257,6 @@ export class EditHandlerImpl implements EditHandler { private release(): void { this.canvas.off('mousedown.edit'); - this.canvas.off('mouseup.edit'); this.canvas.off('mousemove.edit'); this.autoborderHandler.autoborder(false); diff --git a/cvat-core/src/annotations-filter.js b/cvat-core/src/annotations-filter.js index 8a00cab28c09..6fc0b377aa19 100644 --- a/cvat-core/src/annotations-filter.js +++ b/cvat-core/src/annotations-filter.js @@ -18,7 +18,7 @@ const { ArgumentError } = require('./exceptions'); class AnnotationsFilter { constructor() { // eslint-disable-next-line security/detect-unsafe-regex - this.operatorRegex = /(==|!=|<=|>=|>|<|~=)(?=(?:[^"]*(["])[^"]*\2)*[^"]*$)/g; + this.operatorRegex = /(==|!=|<=|>=|>|<)(?=(?:[^"]*(["])[^"]*\2)*[^"]*$)/g; } // Method splits expression by operators that are outside of any brackets @@ -204,7 +204,7 @@ class AnnotationsFilter { serverID: state.serverID, clientID: state.clientID, type: state.objectType, - shape: state.objectShape, + shape: state.shapeType, occluded: state.occluded, }; }); diff --git a/cvat-core/src/annotations-objects.js b/cvat-core/src/annotations-objects.js index 9620d2c4b554..a6192dc03a7d 100644 --- a/cvat-core/src/annotations-objects.js +++ b/cvat-core/src/annotations-objects.js @@ -371,7 +371,7 @@ updateTimestamp(updated) { const anyChanges = updated.label || updated.attributes || updated.points || updated.outside || updated.occluded || updated.keyframe - || updated.zOrder; + || updated.zOrder || updated.hidden || updated.lock || updated.pinned; if (anyChanges) { this.updated = Date.now(); diff --git a/cvat-ui/src/actions/annotation-actions.ts b/cvat-ui/src/actions/annotation-actions.ts index 8f24bb65ac2f..19e9649d388f 100644 --- a/cvat-ui/src/actions/annotation-actions.ts +++ b/cvat-ui/src/actions/annotation-actions.ts @@ -362,6 +362,10 @@ ThunkAction, {}, {}, AnyAction> { }, ); + await job.annotations.clear(true); + await job.actions.clear(); + const history = await job.actions.get(); + // One more update to escape some problems // in canvas when shape with the same // clientID has different type (polygon, rectangle) for example @@ -370,12 +374,10 @@ ThunkAction, {}, {}, AnyAction> { payload: { job, states: [], + history, }, }); - await job.annotations.clear(true); - await job.actions.clear(); - const history = await job.actions.get(); const states = await job.annotations.get(frame, showAllInterpolationTracks, filters); setTimeout(() => { diff --git a/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx b/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx index b6e98198a035..f2ddbac945b3 100644 --- a/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx +++ b/cvat-ui/src/components/annotation-page/annotations-filters-input.tsx @@ -93,7 +93,7 @@ function filtersHelpModalContent( width, height, label, serverID, clientID, type, shape, occluded
Supported operators: - ==, !=, >, >=, <, <=, ~=, (), & and | + ==, !=, >, >=, <, <=, (), & and |
If you have double quotes in your query string, @@ -107,6 +107,7 @@ function filtersHelpModalContent( Examples
  • label=="car" | label==["road sign"]
  • +
  • shape == "polygon"
  • width >= height
  • attr["Attribute 1"] == attr["Attribute 2"]
  • clientID == 50