diff --git a/CHANGELOG.md b/CHANGELOG.md index 624aa37476a6..a23ab6e2cca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - TDB ### Fixed -- TDB +- Fixed Interaction handler keyboard handlers () ### Security - TDB diff --git a/cvat-canvas/README.md b/cvat-canvas/README.md index ee0a0fb3df9e..c4334ad490fa 100644 --- a/cvat-canvas/README.md +++ b/cvat-canvas/README.md @@ -137,6 +137,7 @@ Canvas itself handles: cancel(): void; configure(configuration: Configuration): void; isAbleToChangeFrame(): boolean; + destroy(): void; readonly geometry: Geometry; } @@ -189,6 +190,7 @@ Standard JS events are used. - canvas.resizeshape => {id: number} - canvas.contextmenu => { mouseEvent: MouseEvent, objectState: ObjectState, pointID: number } - canvas.error => { exception: Error } + - canvas.destroy ``` ### WEB @@ -239,6 +241,7 @@ canvas.draw({ | bitmap() | + | + | + | + | + | + | + | + | + | + | + | | setZLayer() | + | + | + | + | + | + | + | + | + | + | + | | setupReviewROIs() | + | + | + | + | + | + | + | + | + | + | + | +| destroy() | + | + | + | + | + | + | + | + | + | + | + | diff --git a/cvat-canvas/package-lock.json b/cvat-canvas/package-lock.json index 11a15189a95a..864351ae390e 100644 --- a/cvat-canvas/package-lock.json +++ b/cvat-canvas/package-lock.json @@ -1,12 +1,12 @@ { "name": "cvat-canvas", - "version": "2.8.0", + "version": "2.9.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cvat-canvas", - "version": "2.8.0", + "version": "2.9.0", "license": "MIT", "dependencies": { "svg.draggable.js": "2.2.2", diff --git a/cvat-canvas/package.json b/cvat-canvas/package.json index 21fda6f0c2b9..caf30170e4f1 100644 --- a/cvat-canvas/package.json +++ b/cvat-canvas/package.json @@ -1,6 +1,6 @@ { "name": "cvat-canvas", - "version": "2.8.0", + "version": "2.9.0", "description": "Part of Computer Vision Annotation Tool which presents its canvas library", "main": "src/canvas.ts", "scripts": { diff --git a/cvat-canvas/src/typescript/canvas.ts b/cvat-canvas/src/typescript/canvas.ts index 4170e1d90a2d..3ccbbaa1d0fc 100644 --- a/cvat-canvas/src/typescript/canvas.ts +++ b/cvat-canvas/src/typescript/canvas.ts @@ -53,6 +53,7 @@ interface Canvas { cancel(): void; configure(configuration: Configuration): void; isAbleToChangeFrame(): boolean; + destroy(): void; readonly geometry: Geometry; } @@ -163,6 +164,10 @@ class CanvasImpl implements Canvas { public get geometry(): Geometry { return this.model.geometry; } + + public destroy(): void { + this.model.destroy(); + } } export type InteractionData = _InteractionData; diff --git a/cvat-canvas/src/typescript/canvasModel.ts b/cvat-canvas/src/typescript/canvasModel.ts index 27e23cae45f2..22f571d3ad89 100644 --- a/cvat-canvas/src/typescript/canvasModel.ts +++ b/cvat-canvas/src/typescript/canvasModel.ts @@ -146,6 +146,7 @@ export enum UpdateReasons { ZOOM_CANVAS = 'zoom_canvas', CONFIG_UPDATED = 'config_updated', DATA_FAILED = 'data_failed', + DESTROY = 'destroy', } export enum Mode { @@ -210,6 +211,7 @@ export interface CanvasModel { isAbleToChangeFrame(): boolean; configure(configuration: Configuration): void; cancel(): void; + destroy(): void; } export class CanvasModelImpl extends MasterImpl implements CanvasModel { @@ -685,6 +687,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel { this.notify(UpdateReasons.CANCEL); } + public destroy(): void { + this.notify(UpdateReasons.DESTROY); + } + public get configuration(): Configuration { return { ...this.data.configuration }; } diff --git a/cvat-canvas/src/typescript/canvasView.ts b/cvat-canvas/src/typescript/canvasView.ts index af91f7cdebdd..a4af1149e7d9 100644 --- a/cvat-canvas/src/typescript/canvasView.ts +++ b/cvat-canvas/src/typescript/canvasView.ts @@ -1358,6 +1358,16 @@ export class CanvasViewImpl implements CanvasView, Listener { }, }); this.canvas.dispatchEvent(event); + } else if (reason === UpdateReasons.DESTROY) { + this.canvas.dispatchEvent( + new CustomEvent('canvas.destroy', { + bubbles: false, + cancelable: true, + }), + ); + // We can't call namespaced svgjs event + // see - https://svgjs.dev/docs/2.7/events/ + this.adoptedContent.fire('destroy'); } if (model.imageBitmap && [UpdateReasons.IMAGE_CHANGED, UpdateReasons.OBJECTS_UPDATED].includes(reason)) { diff --git a/cvat-canvas/src/typescript/interactionHandler.ts b/cvat-canvas/src/typescript/interactionHandler.ts index c6bc18d6e38c..0a4a3209f163 100644 --- a/cvat-canvas/src/typescript/interactionHandler.ts +++ b/cvat-canvas/src/typescript/interactionHandler.ts @@ -375,6 +375,27 @@ export class InteractionHandlerImpl implements InteractionHandler { return false; } + private onKeyUp = (e: KeyboardEvent): void => { + if (this.interactionData.enabled && e.keyCode === 17) { + if (this.interactionData.onChangeToolsBlockerState && !this.thresholdWasModified) { + this.interactionData.onChangeToolsBlockerState('keyup'); + } + if (this.shouldRaiseEvent(false)) { + // 17 is ctrl + this.onInteraction(this.prepareResult(), true, false); + } + } + }; + + private onKeyDown = (e: KeyboardEvent): void => { + if (!e.repeat && this.interactionData.enabled && e.keyCode === 17) { + if (this.interactionData.onChangeToolsBlockerState && !this.thresholdWasModified) { + this.interactionData.onChangeToolsBlockerState('keydown'); + } + this.thresholdWasModified = false; + } + }; + public constructor( onInteraction: ( shapes: InteractionResult[] | null, @@ -452,25 +473,12 @@ export class InteractionHandlerImpl implements InteractionHandler { } }); - window.addEventListener('keyup', (e: KeyboardEvent): void => { - if (this.interactionData.enabled && e.keyCode === 17) { - if (this.interactionData.onChangeToolsBlockerState && !this.thresholdWasModified) { - this.interactionData.onChangeToolsBlockerState('keyup'); - } - if (this.shouldRaiseEvent(false)) { - // 17 is ctrl - this.onInteraction(this.prepareResult(), true, false); - } - } - }); + window.addEventListener('keyup', this.onKeyUp); + window.addEventListener('keydown', this.onKeyDown); - window.addEventListener('keydown', (e: KeyboardEvent): void => { - if (!e.repeat && this.interactionData.enabled && e.keyCode === 17) { - if (this.interactionData.onChangeToolsBlockerState && !this.thresholdWasModified) { - this.interactionData.onChangeToolsBlockerState('keydown'); - } - this.thresholdWasModified = false; - } + this.canvas.on('destroy.canvas', ():void => { + window.removeEventListener('keyup', this.onKeyUp); + window.removeEventListener('keydown', this.onKeyDown); }); } diff --git a/cvat-canvas3d/src/typescript/canvas3d.ts b/cvat-canvas3d/src/typescript/canvas3d.ts index 02a375cd0d61..ef6e1ff131bc 100644 --- a/cvat-canvas3d/src/typescript/canvas3d.ts +++ b/cvat-canvas3d/src/typescript/canvas3d.ts @@ -36,6 +36,7 @@ interface Canvas3d { fitCanvas(): void; fit(): void; group(groupData: GroupData): void; + destroy(): void; } class Canvas3dImpl implements Canvas3d { @@ -104,6 +105,10 @@ class Canvas3dImpl implements Canvas3d { public fitCanvas(): void { this.model.fit(); } + + public destroy(): void { + this.model.destroy(); + } } export { diff --git a/cvat-canvas3d/src/typescript/canvas3dModel.ts b/cvat-canvas3d/src/typescript/canvas3dModel.ts index 41c566cf8d74..928e16c4d4e3 100644 --- a/cvat-canvas3d/src/typescript/canvas3dModel.ts +++ b/cvat-canvas3d/src/typescript/canvas3dModel.ts @@ -126,6 +126,7 @@ export interface Canvas3dModel { configureShapes(shapeProperties: any): void; fit(): void; group(groupData: GroupData): void; + destroy(): void; } export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel { @@ -234,8 +235,8 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel { } public isAbleToChangeFrame(): boolean { - const isUnable = [Mode.DRAG, Mode.EDIT, Mode.RESIZE, Mode.INTERACT, Mode.BUSY].includes(this.data.mode) - || (this.data.mode === Mode.DRAW && typeof this.data.drawData.redraw === 'number'); + const isUnable = [Mode.DRAG, Mode.EDIT, Mode.RESIZE, Mode.INTERACT, Mode.BUSY].includes(this.data.mode) || + (this.data.mode === Mode.DRAW && typeof this.data.drawData.redraw === 'number'); return !isUnable; } @@ -340,4 +341,6 @@ export class Canvas3dModelImpl extends MasterImpl implements Canvas3dModel { public get groupData(): GroupData { return { ...this.data.groupData }; } + + public destroy(): void {} } diff --git a/cvat-canvas3d/src/typescript/canvas3dView.ts b/cvat-canvas3d/src/typescript/canvas3dView.ts index 5f450ac57dbc..229d22c3de22 100644 --- a/cvat-canvas3d/src/typescript/canvas3dView.ts +++ b/cvat-canvas3d/src/typescript/canvas3dView.ts @@ -287,6 +287,7 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { (_state: any): boolean => _state.clientID === Number(intersects[0].object.name), ); if (item.length !== 0) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.model.data.groupData.grouped = this.model.data.groupData.grouped.filter( (_state: any): boolean => _state.clientID !== Number(intersects[0].object.name), @@ -543,9 +544,9 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { this.action.rotation.screenInit = { x: diffX, y: diffY }; this.action.rotation.screenMove = { x: diffX, y: diffY }; if ( - this.model.data.selected - && !this.model.data.selected.perspective.userData.lock - && !this.model.data.selected.perspective.userData.hidden + this.model.data.selected && + !this.model.data.selected.perspective.userData.lock && + !this.model.data.selected.perspective.userData.hidden ) { this.action.scan = view; this.model.mode = Mode.EDIT; @@ -698,8 +699,8 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { cuboid.setOpacity(opacity); if ( - this.model.data.activeElement.clientID === clientID - && ![Mode.DRAG_CANVAS, Mode.GROUP].includes(this.mode) + this.model.data.activeElement.clientID === clientID && + ![Mode.DRAG_CANVAS, Mode.GROUP].includes(this.mode) ) { cuboid.setOpacity(selectedOpacity); if (!object.lock) { @@ -964,12 +965,12 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { const sphereCenter = points.geometry.boundingSphere.center; const { radius } = points.geometry.boundingSphere; if (!this.views.perspective.camera) return; - const xRange = -radius / 2 < this.views.perspective.camera.position.x - sphereCenter.x - && radius / 2 > this.views.perspective.camera.position.x - sphereCenter.x; - const yRange = -radius / 2 < this.views.perspective.camera.position.y - sphereCenter.y - && radius / 2 > this.views.perspective.camera.position.y - sphereCenter.y; - const zRange = -radius / 2 < this.views.perspective.camera.position.z - sphereCenter.z - && radius / 2 > this.views.perspective.camera.position.z - sphereCenter.z; + const xRange = -radius / 2 < this.views.perspective.camera.position.x - sphereCenter.x && + radius / 2 > this.views.perspective.camera.position.x - sphereCenter.x; + const yRange = -radius / 2 < this.views.perspective.camera.position.y - sphereCenter.y && + radius / 2 > this.views.perspective.camera.position.y - sphereCenter.y; + const zRange = -radius / 2 < this.views.perspective.camera.position.z - sphereCenter.z && + radius / 2 > this.views.perspective.camera.position.z - sphereCenter.z; let newX = 0; let newY = 0; let newZ = 0; @@ -1085,10 +1086,10 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { private positionAllViews(x: number, y: number, z: number, animation: boolean): void { if ( - this.views.perspective.controls - && this.views.top.controls - && this.views.side.controls - && this.views.front.controls + this.views.perspective.controls && + this.views.top.controls && + this.views.side.controls && + this.views.front.controls ) { this.views.perspective.controls.setLookAt(x - 8, y - 8, z + 3, x, y, z, animation); this.views.top.camera.position.set(x, y, z + 8); @@ -1266,8 +1267,8 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { private renderTranslateAction(view: ViewType, viewType: any): void { if ( - this.action.translation.helper.x === this.views[view].rayCaster.mouseVector.x - && this.action.translation.helper.y === this.views[view].rayCaster.mouseVector.y + this.action.translation.helper.x === this.views[view].rayCaster.mouseVector.x && + this.action.translation.helper.y === this.views[view].rayCaster.mouseVector.y ) { return; } @@ -1332,8 +1333,8 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { } if ( - this.action.resize.recentMouseVector.x === currentPosX - && this.action.resize.recentMouseVector.y === currentPosY + this.action.resize.recentMouseVector.x === currentPosX && + this.action.resize.recentMouseVector.y === currentPosY ) { return; } @@ -1736,15 +1737,15 @@ export class Canvas3dViewImpl implements Canvas3dView, Listener { y: canvas.offsetTop + canvas.offsetHeight / 2, }; if ( - this.action.rotation.screenInit.x === this.action.rotation.screenMove.x - && this.action.rotation.screenInit.y === this.action.rotation.screenMove.y + this.action.rotation.screenInit.x === this.action.rotation.screenMove.x && + this.action.rotation.screenInit.y === this.action.rotation.screenMove.y ) { return; } if ( - this.action.rotation.recentMouseVector.x === this.views[view].rayCaster.mouseVector.x - && this.action.rotation.recentMouseVector.y === this.views[view].rayCaster.mouseVector.y + this.action.rotation.recentMouseVector.x === this.views[view].rayCaster.mouseVector.x && + this.action.rotation.recentMouseVector.y === this.views[view].rayCaster.mouseVector.y ) { return; } diff --git a/cvat-ui/package-lock.json b/cvat-ui/package-lock.json index 6c676a570aa3..b1187a9b6cbf 100644 --- a/cvat-ui/package-lock.json +++ b/cvat-ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "cvat-ui", - "version": "1.25.0", + "version": "1.25.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cvat-ui", - "version": "1.25.0", + "version": "1.25.1", "license": "MIT", "dependencies": { "@ant-design/icons": "^4.6.3", diff --git a/cvat-ui/package.json b/cvat-ui/package.json index a7a9ef5c1d89..62fddfc2185a 100644 --- a/cvat-ui/package.json +++ b/cvat-ui/package.json @@ -1,6 +1,6 @@ { "name": "cvat-ui", - "version": "1.25.0", + "version": "1.25.1", "description": "CVAT single-page application", "main": "src/index.tsx", "scripts": { diff --git a/cvat-ui/src/reducers/annotation-reducer.ts b/cvat-ui/src/reducers/annotation-reducer.ts index 72d84616350d..e99cfa634fcb 100644 --- a/cvat-ui/src/reducers/annotation-reducer.ts +++ b/cvat-ui/src/reducers/annotation-reducer.ts @@ -166,6 +166,8 @@ export default (state = defaultState, action: AnyAction): AnnotationState => { activeShapeType = ShapeType.CUBOID; } + state.canvas.instance.destroy(); + return { ...state, job: {