Skip to content

Commit

Permalink
Refactoring: tools blocker state outside of canvas (#8293)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsekachev committed Aug 12, 2024
1 parent 10a5f66 commit 53bcbf3
Show file tree
Hide file tree
Showing 11 changed files with 83 additions and 85 deletions.
2 changes: 1 addition & 1 deletion cvat-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
"version": "2.20.7",
"version": "2.20.8",
"type": "module",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
Expand Down
1 change: 0 additions & 1 deletion cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ export interface InteractionData {
shapeType: string;
points: number[];
};
onChangeToolsBlockerState?: (event: string) => void;
}

export interface InteractionResult {
Expand Down
55 changes: 15 additions & 40 deletions cvat-canvas/src/typescript/interactionHandler.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2020-2022 Intel Corporation
// Copyright (C) 2023 CVAT.ai Corporation
// Copyright (C) 2023-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -36,7 +36,6 @@ export class InteractionHandlerImpl implements InteractionHandler {
private thresholdRectSize: number;
private intermediateShape: PropType<InteractionData, 'intermediateShape'>;
private drawnIntermediateShape: SVG.Shape;
private thresholdWasModified: boolean;
private controlPointsSize: number;
private selectedShapeOpacity: number;
private cancelled: boolean;
Expand Down Expand Up @@ -64,7 +63,7 @@ export class InteractionHandlerImpl implements InteractionHandler {
);
}

private shouldRaiseEvent(ctrlKey: boolean): boolean {
private shouldRaiseEvent(): boolean {
const { interactionData, interactionShapes, shapesWereUpdated } = this;
const { minPosVertices, minNegVertices, enabled } = interactionData;

Expand All @@ -75,16 +74,17 @@ export class InteractionHandlerImpl implements InteractionHandler {
(shape: SVG.Shape): boolean => (shape as any).attr('stroke') !== 'green',
);

const somethingWasDrawn = interactionShapes.some((shape) => shape.type === 'rect') || positiveShapes.length;
if (interactionData.shapeType === 'rectangle') {
return enabled && !ctrlKey && !!interactionShapes.length;
return enabled && !!interactionShapes.length;
}

const minPosVerticesDefined = Number.isInteger(minPosVertices);
const minNegVerticesDefined = Number.isInteger(minNegVertices) && minNegVertices >= 0;
const minPosVerticesAchieved = !minPosVerticesDefined || minPosVertices <= positiveShapes.length;
const minNegVerticesAchieved = !minNegVerticesDefined || minNegVertices <= negativeShapes.length;
const minimumVerticesAchieved = minPosVerticesAchieved && minNegVerticesAchieved;
return enabled && !ctrlKey && minimumVerticesAchieved && shapesWereUpdated;
return enabled && somethingWasDrawn && minimumVerticesAchieved && shapesWereUpdated;
}

private addThreshold(): void {
Expand Down Expand Up @@ -125,7 +125,7 @@ export class InteractionHandlerImpl implements InteractionHandler {

this.interactionShapes.push(this.currentInteractionShape);
this.shapesWereUpdated = true;
if (this.shouldRaiseEvent(e.ctrlKey)) {
if (this.shouldRaiseEvent()) {
this.onInteraction(this.prepareResult(), true, false);
}

Expand Down Expand Up @@ -154,7 +154,7 @@ export class InteractionHandlerImpl implements InteractionHandler {
if (this.interactionData.startWithBox && this.interactionShapes.length === 1) {
this.interactionShapes[0].style({ visibility: '' });
}
const shouldRaiseEvent = this.shouldRaiseEvent(_e.ctrlKey);
const shouldRaiseEvent = this.shouldRaiseEvent();
if (shouldRaiseEvent) {
this.onInteraction(this.prepareResult(), true, false);
}
Expand Down Expand Up @@ -193,7 +193,7 @@ export class InteractionHandlerImpl implements InteractionHandler {
this.currentInteractionShape = this.canvas.rect();
this.canvas.on('mousedown.interaction', eventListener);
this.currentInteractionShape
.on('drawstop', (e): void => {
.on('drawstop', (): void => {
if (this.cancelled) {
return;
}
Expand All @@ -204,7 +204,7 @@ export class InteractionHandlerImpl implements InteractionHandler {

if (shouldFinish) {
this.interact({ enabled: false });
} else if (this.shouldRaiseEvent(e.ctrlKey)) {
} else if (this.shouldRaiseEvent()) {
this.onInteraction(this.prepareResult(), true, false);
}

Expand Down Expand Up @@ -391,7 +391,7 @@ export class InteractionHandlerImpl implements InteractionHandler {
}

private visualComponentsChanged(interactionData: InteractionData): boolean {
const allowedKeys = ['enabled', 'crosshair', 'enableThreshold', 'onChangeToolsBlockerState'];
const allowedKeys = ['enabled', 'crosshair', 'enableThreshold'];
if (Object.keys(interactionData).every((key: string): boolean => allowedKeys.includes(key))) {
if (this.interactionData.enableThreshold !== undefined && interactionData.enableThreshold !== undefined &&
this.interactionData.enableThreshold !== interactionData.enableThreshold) {
Expand All @@ -405,27 +405,6 @@ 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,
Expand Down Expand Up @@ -488,11 +467,11 @@ export class InteractionHandlerImpl implements InteractionHandler {
});

this.canvas.on('wheel.interaction', (e: WheelEvent): void => {
if (e.ctrlKey) {
if (e.altKey) {
e.stopPropagation();
e.preventDefault();
if (this.threshold) {
this.thresholdWasModified = true;
const { x, y } = this.cursorPosition;
e.preventDefault();
if (e.deltaY > 0) {
this.thresholdRectSize *= 6 / 5;
} else {
Expand All @@ -503,9 +482,6 @@ export class InteractionHandlerImpl implements InteractionHandler {
}
}
});

window.document.addEventListener('keyup', this.onKeyUp);
window.document.addEventListener('keydown', this.onKeyDown);
}

public transform(geometry: Geometry): void {
Expand Down Expand Up @@ -565,7 +541,7 @@ export class InteractionHandlerImpl implements InteractionHandler {
(this.currentInteractionShape as any).draw('stop');
}

this.onInteraction(this.prepareResult(), this.shouldRaiseEvent(false), true);
this.onInteraction(this.prepareResult(), this.shouldRaiseEvent(), true);
this.release();
this.interactionData = interactionData;
}
Expand Down Expand Up @@ -599,7 +575,6 @@ export class InteractionHandlerImpl implements InteractionHandler {
}

public destroy(): void {
window.document.removeEventListener('keyup', this.onKeyUp);
window.document.removeEventListener('keydown', this.onKeyDown);
// nothing to release
}
}
2 changes: 1 addition & 1 deletion cvat-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-core",
"version": "15.1.0",
"version": "15.1.1",
"type": "module",
"description": "Part of Computer Vision Tool which presents an interface for client-side integration",
"main": "src/api.ts",
Expand Down
3 changes: 1 addition & 2 deletions cvat-core/src/core-types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2023 CVAT.ai Corporation
// Copyright (C) 2023-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -16,7 +16,6 @@ export interface ModelParams {
minNegVertices?: number;
startWithBox?: boolean;
startWithBoxOptional?: boolean;
onChangeToolsBlockerState?: (event: string) => void;
};
}

Expand Down
12 changes: 1 addition & 11 deletions cvat-core/src/ml-model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// Copyright (C) 2019-2022 Intel Corporation
// Copyright (C) 2022-2023 CVAT.ai Corporation
// Copyright (C) 2022-2024 CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -13,7 +13,6 @@ import {

export default class MLModel {
private serialized: SerializedModel;
private changeToolsBlockerStateCallback?: (event: string) => void;

constructor(serialized: SerializedModel) {
this.serialized = { ...serialized };
Expand Down Expand Up @@ -61,10 +60,6 @@ export default class MLModel {
},
};

if (this.changeToolsBlockerStateCallback) {
result.canvas.onChangeToolsBlockerState = this.changeToolsBlockerStateCallback;
}

return result;
}

Expand Down Expand Up @@ -103,11 +98,6 @@ export default class MLModel {
return this.serialized?.return_type;
}

// Used to set a callback when the tool is blocked in UI
public set onChangeToolsBlockerState(onChangeToolsBlockerState: (event: string) => void) {
this.changeToolsBlockerStateCallback = onChangeToolsBlockerState;
}

public async preview(): Promise<string> {
const result = await PluginRegistry.apiWrapper.call(this, MLModel.prototype.preview);
return result;
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.64.4",
"version": "1.64.5",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ class OpenCVControlComponent extends React.PureComponent<Props & DispatchToProps

public componentDidMount(): void {
const { canvasInstance } = this.props;

window.document.addEventListener('keyup', this.onKeyUp);
canvasInstance.html().addEventListener('canvas.interacted', this.interactionListener);
}

Expand Down Expand Up @@ -208,6 +210,8 @@ class OpenCVControlComponent extends React.PureComponent<Props & DispatchToProps
public componentWillUnmount(): void {
const { canvasInstance } = this.props;
const { trackedShapes } = this.state;

window.document.removeEventListener('keyup', this.onKeyUp);
canvasInstance.html().removeEventListener('canvas.interacted', this.interactionListener);
openCVWrapper.removeProgressCallback();
trackedShapes.forEach((shape: TrackedShape) => shape.trackerModel.delete());
Expand Down Expand Up @@ -368,21 +372,29 @@ class OpenCVControlComponent extends React.PureComponent<Props & DispatchToProps
return context.getImageData(0, 0, width, height);
};

private onChangeToolsBlockerState = (event:string):void => {
private onChangeToolsBlockerState = (): void => {
const {
isActivated, toolsBlockerState, onSwitchToolsBlockerState, canvasInstance,
toolsBlockerState, canvasInstance,
isActivated, onSwitchToolsBlockerState,
} = this.props;
if (isActivated && event === 'keyup') {
onSwitchToolsBlockerState({ algorithmsLocked: !toolsBlockerState.algorithmsLocked });

if (isActivated) {
const isLocked = !toolsBlockerState.algorithmsLocked;
onSwitchToolsBlockerState({ algorithmsLocked: isLocked });
canvasInstance.interact({
enabled: true,
crosshair: toolsBlockerState.algorithmsLocked,
enableThreshold: toolsBlockerState.algorithmsLocked,
onChangeToolsBlockerState: this.onChangeToolsBlockerState,
crosshair: !isLocked,
enableThreshold: !isLocked,
});
}
};

private onKeyUp = (e: KeyboardEvent): void => {
if (e.key === 'Control') {
this.onChangeToolsBlockerState();
}
};

private applyTracking = (imageData: ImageData, shape: TrackedShape,
objectState: any): Promise<void> => new Promise((resolve, reject) => {
setTimeout(() => {
Expand Down Expand Up @@ -580,8 +592,7 @@ class OpenCVControlComponent extends React.PureComponent<Props & DispatchToProps
className='cvat-opencv-scissors-tool-button'
onClick={() => {
this.setState({ mode: 'interaction' });
this.activeTool = openCVWrapper.segmentation
.intelligentScissorsFactory(this.onChangeToolsBlockerState);
this.activeTool = openCVWrapper.segmentation.intelligentScissorsFactory();
canvasInstance.cancel();

const interactorParameters = this.activeTool.params.canvas;
Expand Down
Loading

0 comments on commit 53bcbf3

Please sign in to comment.