diff --git a/CHANGELOG.md b/CHANGELOG.md index 22dde342d329..cce2bb85fd61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Permission error occured when accessing the JobCommits () - job assignee can remove or update any issue created by the task owner () +- Bug: Incorrect point deletion with keyboard shortcut () ### Security - TDB diff --git a/cvat-canvas/package-lock.json b/cvat-canvas/package-lock.json index 0ab129552269..4c915d045a79 100644 --- a/cvat-canvas/package-lock.json +++ b/cvat-canvas/package-lock.json @@ -1,12 +1,12 @@ { "name": "cvat-canvas", - "version": "2.13.1", + "version": "2.13.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cvat-canvas", - "version": "2.13.1", + "version": "2.13.2", "license": "MIT", "dependencies": { "@types/polylabel": "^1.0.5", diff --git a/cvat-canvas/package.json b/cvat-canvas/package.json index 776dd7ca4c11..4c5d7da82d56 100644 --- a/cvat-canvas/package.json +++ b/cvat-canvas/package.json @@ -1,6 +1,6 @@ { "name": "cvat-canvas", - "version": "2.13.1", + "version": "2.13.2", "description": "Part of Computer Vision Annotation Tool which presents its canvas library", "main": "src/canvas.ts", "scripts": { diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index 6a4348a34725..4cc1377f54b0 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -792,6 +792,13 @@ export class CanvasViewImpl implements CanvasView, Listener { ); if (['polygon', 'polyline', 'points'].includes(state.shapeType)) { + if (state.shapeType === 'points' && (e.altKey || e.ctrlKey)) { + const selectedClientID = +((e.target as HTMLElement).parentElement as HTMLElement).getAttribute('clientID'); + + if (state.clientID !== selectedClientID) { + return; + } + } if (e.altKey) { const { points } = state; this.onEditDone(state, points.slice(0, pointID * 2).concat(points.slice(pointID * 2 + 2))); @@ -860,6 +867,8 @@ export class CanvasViewImpl implements CanvasView, Listener { if (value) { const getGeometry = (): Geometry => this.geometry; + const getController = (): CanvasController => this.controller; + const getActiveElement = (): ActiveElement => this.activeElement; (shape as any).selectize(value, { deepSelect: true, pointSize: (2 * consts.BASE_POINT_SIZE) / this.geometry.scale, @@ -875,7 +884,20 @@ export class CanvasViewImpl implements CanvasView, Listener { 'stroke-width': consts.POINTS_STROKE_WIDTH / getGeometry().scale, }); - circle.on('mouseenter', (): void => { + circle.on('mouseenter', (e: MouseEvent): void => { + const activeElement = getActiveElement(); + if (activeElement !== null && (e.altKey || e.ctrlKey)) { + const [state] = getController().objects.filter( + (_state: any): boolean => _state.clientID === activeElement.clientID, + ); + if (state?.shapeType === 'points') { + const selectedClientID = +((e.target as HTMLElement).parentElement as HTMLElement).getAttribute('clientID'); + if (state.clientID !== selectedClientID) { + return; + } + } + } + circle.attr({ 'stroke-width': consts.POINTS_SELECTED_STROKE_WIDTH / getGeometry().scale, }); diff --git a/tests/cypress/integration/issues_prs2/issue_3821_delete_point.js b/tests/cypress/integration/issues_prs2/issue_3821_delete_point.js new file mode 100644 index 000000000000..e1fbd5b023e9 --- /dev/null +++ b/tests/cypress/integration/issues_prs2/issue_3821_delete_point.js @@ -0,0 +1,93 @@ +// Copyright (C) 2022 Intel Corporation +// +// SPDX-License-Identifier: MIT + +/// + +import { taskName, labelName } from '../../support/const'; + +context('When delete a point, the required point is deleted.', () => { + const issueId = '3821'; + + const pointsShapes = []; + for (let i = 0; i < 4; i++) { + pointsShapes.push({ + labelName, + type: 'Shape', + pointsMap: [ + { x: 300 + i * 50, y: 250 }, + { x: 300 + i * 50, y: 350 }, + { x: 300 + i * 50, y: 450 }, + ], + }); + } + + before(() => { + cy.openTaskJob(taskName); + pointsShapes.forEach((shape) => { + cy.createPoint(shape); + }); + }); + + describe(`Testing issue "${issueId}"`, () => { + it('Remove point holding Alt key from each shape. Point must be removed from first shape, second one should stay the same', () => { + cy.get('#cvat_canvas_shape_1').trigger('mousemove', { force: true }).trigger('mouseover', { force: true }); + cy.get('body').type('{alt}', { release: false }); + cy.get('#cvat_canvas_shape_1') + .children() + .then((children) => { + cy.get(children) + .eq(1) + .then((point) => { + cy.get(point).click(); + }); + }); + cy.get('#cvat_canvas_shape_2') + .children() + .then((children) => { + cy.get(children) + .eq(1) + .then((point) => { + cy.get(point).click(); + }); + }); + cy.get('#cvat_canvas_shape_1') + .children() + .should('have.length', 2); + cy.get('#cvat_canvas_shape_2') + .children() + .should('have.length', 3); + }); + + it('Remove point holding Ctrl key from each shape. Point must be removed from first shape, second one should stay the same', () => { + cy.get('#cvat_canvas_shape_3').trigger('mousemove', { force: true }).trigger('mouseover', { force: true }); + cy.get('body').type('{ctrl}', { release: false }); + cy.get('#cvat_canvas_shape_3') + .children() + .then((children) => { + cy.get(children) + .eq(1) + .then((point) => { + cy.get(point).rightclick(); + }); + }); + cy.contains('Delete point').click(); + cy.get('#cvat_canvas_shape_4') + .children() + .then((children) => { + cy.get(children) + .eq(1) + .then((point) => { + cy.get(point).rightclick(); + }); + }); + cy.contains('Delete point').should('not.exist'); + cy.get('#cvat_canvas_shape_3') + .children() + .should('have.length', 2); + cy.get('#cvat_canvas_shape_4') + .children() + .should('have.length', 3); + }); + }); +});