Skip to content

Commit

Permalink
Fixed bug: canvas is busy (at least one reproducing way) (#4151)
Browse files Browse the repository at this point in the history
* Fixed bug: canvas is busy (at least one reproducing way)

* Updated version & changelog

* Fixed license headers
  • Loading branch information
Boris Sekachev authored Jan 13, 2022
1 parent c83d170 commit 1d084c4
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 55 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Order in an annotation file(<https://github.com/openvinotoolkit/cvat/pull/4087>)
- Fixed task data upload progressbar (<https://github.com/openvinotoolkit/cvat/pull/4134>)
- Email in org invitations is case sensitive (<https://github.com/openvinotoolkit/cvat/pull/4153>)
- Bug: canvas is busy when start playing, start resizing a shape and do not release the mouse cursor (<https://github.com/openvinotoolkit/cvat/pull/4151>)

### Security
- Updated ELK to 6.8.22 which uses log4j 2.17.0 (<https://github.com/openvinotoolkit/cvat/pull/4052>)
Expand Down
4 changes: 2 additions & 2 deletions cvat-canvas/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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.12.0",
"version": "2.12.1",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
"scripts": {
Expand Down
57 changes: 35 additions & 22 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2019-2021 Intel Corporation
// Copyright (C) 2019-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -684,18 +684,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.deactivate();
}

for (const state of deleted) {
if (state.clientID in this.svgTexts) {
this.svgTexts[state.clientID].remove();
delete this.svgTexts[state.clientID];
}

this.svgShapes[state.clientID].off('click.canvas');
this.svgShapes[state.clientID].remove();
delete this.drawnStates[state.clientID];
delete this.svgShapes[state.clientID];
}

this.deleteObjects(deleted);
this.addObjects(created);
this.updateObjects(updated);
this.sortObjects();
Expand Down Expand Up @@ -1727,6 +1716,22 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
}

private deleteObjects(states: any[]): void {
for (const state of states) {
if (state.clientID in this.svgTexts) {
this.svgTexts[state.clientID].remove();
delete this.svgTexts[state.clientID];
}

this.svgShapes[state.clientID].fire('remove');
this.svgShapes[state.clientID].off('click');
this.svgShapes[state.clientID].off('remove');
this.svgShapes[state.clientID].remove();
delete this.drawnStates[state.clientID];
delete this.svgShapes[state.clientID];
}
}

private addObjects(states: any[]): void {
const { displayAllText } = this.configuration;
for (const state of states) {
Expand Down Expand Up @@ -1940,10 +1945,14 @@ export class CanvasViewImpl implements CanvasView, Listener {
.on('dragstart', (): void => {
this.mode = Mode.DRAG;
hideText();
(shape as any).on('remove.drag', (): void => {
this.mode = Mode.IDLE;
});
})
.on('dragend', (e: CustomEvent): void => {
showText();
(shape as any).off('remove.drag');
this.mode = Mode.IDLE;
showText();
const p1 = e.detail.handler.startPoints.point;
const p2 = e.detail.p;
const delta = 1;
Expand Down Expand Up @@ -1997,6 +2006,15 @@ export class CanvasViewImpl implements CanvasView, Listener {

let shapeSizeElement: ShapeSizeElement | null = null;
let resized = false;

const resizeFinally = (): void => {
if (shapeSizeElement) {
shapeSizeElement.rm();
shapeSizeElement = null;
}
this.mode = Mode.IDLE;
};

(shape as any)
.resize({
snapToGrid: 0.1,
Expand All @@ -2010,6 +2028,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (state.shapeType === 'rectangle') {
shapeSizeElement = displayShapeSize(this.adoptedContent, this.adoptedText);
}
(shape as any).on('remove.resize', resizeFinally);
})
.on('resizing', (): void => {
resized = true;
Expand All @@ -2018,16 +2037,10 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
})
.on('resizedone', (): void => {
if (shapeSizeElement) {
shapeSizeElement.rm();
shapeSizeElement = null;
}

(shape as any).off('remove.resize');
resizeFinally();
showDirection();
showText();

this.mode = Mode.IDLE;

if (resized) {
let rotation = shape.transform().rotation || 0;

Expand Down
4 changes: 2 additions & 2 deletions cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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.33.0",
"version": "1.33.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
51 changes: 33 additions & 18 deletions cvat-ui/src/actions/annotation-actions.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// Copyright (C) 2020-2021 Intel Corporation
// Copyright (C) 2020-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT

import {
ActionCreator, AnyAction, Dispatch, Store,
} from 'redux';
import { ThunkAction } from 'utils/redux';
import isAbleToChangeFrame from 'utils/is-able-to-change-frame';
import { RectDrawingMethod, CuboidDrawingMethod, Canvas } from 'cvat-canvas-wrapper';
import getCore from 'cvat-core-wrapper';
import logger, { LogType } from 'cvat-logger';
import { getCVATStore } from 'cvat-store';

import {
ActiveControl,
CombinedState,
Expand Down Expand Up @@ -691,8 +693,8 @@ export function changeFrameAsync(
frameStep?: number,
forceUpdate?: boolean,
): ThunkAction {
return async (dispatch: ActionCreator<Dispatch>): Promise<void> => {
const state: CombinedState = getStore().getState();
return async (dispatch: ActionCreator<Dispatch>, getState: () => CombinedState): Promise<void> => {
const state: CombinedState = getState();
const { instance: job } = state.annotation.job;
const { filters, frame, showAllInterpolationTracks } = receiveAnnotationsParameters();

Expand All @@ -701,37 +703,50 @@ export function changeFrameAsync(
throw Error(`Required frame ${toFrame} is out of the current job`);
}

if (toFrame === frame && !forceUpdate) {
dispatch({
const abortAction = (): AnyAction => {
const currentState = getState();
return ({
type: AnnotationActionTypes.CHANGE_FRAME_SUCCESS,
payload: {
number: state.annotation.player.frame.number,
data: state.annotation.player.frame.data,
filename: state.annotation.player.frame.filename,
hasRelatedContext: state.annotation.player.frame.hasRelatedContext,
delay: state.annotation.player.frame.delay,
changeTime: state.annotation.player.frame.changeTime,
states: state.annotation.annotations.states,
minZ: state.annotation.annotations.zLayer.min,
maxZ: state.annotation.annotations.zLayer.max,
curZ: state.annotation.annotations.zLayer.cur,
number: currentState.annotation.player.frame.number,
data: currentState.annotation.player.frame.data,
filename: currentState.annotation.player.frame.filename,
hasRelatedContext: currentState.annotation.player.frame.hasRelatedContext,
delay: currentState.annotation.player.frame.delay,
changeTime: currentState.annotation.player.frame.changeTime,
states: currentState.annotation.annotations.states,
minZ: currentState.annotation.annotations.zLayer.min,
maxZ: currentState.annotation.annotations.zLayer.max,
curZ: currentState.annotation.annotations.zLayer.cur,
},
});
};

return;
}
// Start async requests
dispatch({
type: AnnotationActionTypes.CHANGE_FRAME,
payload: {},
});

if (toFrame === frame && !forceUpdate) {
dispatch(abortAction());
return;
}

// Start async requests
await job.logger.log(LogType.changeFrame, {
from: frame,
to: toFrame,
});
const data = await job.frames.get(toFrame, fillBuffer, frameStep);
const states = await job.annotations.get(toFrame, showAllInterpolationTracks, filters);

if (!isAbleToChangeFrame()) {
// while doing async actions above, canvas can become used by user in another way
// so, we need additional check and if it is used, we do not update state
dispatch(abortAction());
return;
}

const [minZ, maxZ] = computeZRange(states);
const currentTime = new Date().getTime();
let frameSpeed;
Expand Down
16 changes: 9 additions & 7 deletions cvat-ui/src/components/annotation-page/canvas/canvas-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2020-2021 Intel Corporation
// Copyright (C) 2020-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand Down Expand Up @@ -308,12 +308,14 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}
}

const loadingAnimation = window.document.getElementById('cvat_canvas_loading_animation');
if (loadingAnimation && frameFetching !== prevProps.frameFetching) {
if (frameFetching) {
loadingAnimation.classList.remove('cvat_canvas_hidden');
} else {
loadingAnimation.classList.add('cvat_canvas_hidden');
if (frameFetching !== prevProps.frameFetching) {
const loadingAnimation = window.document.getElementById('cvat_canvas_loading_animation');
if (loadingAnimation) {
if (frameFetching) {
loadingAnimation.classList.remove('cvat_canvas_hidden');
} else {
loadingAnimation.classList.add('cvat_canvas_hidden');
}
}
}

Expand Down
6 changes: 4 additions & 2 deletions cvat-ui/src/utils/is-able-to-change-frame.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2021 Intel Corporation
// Copyright (C) 2021-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT

Expand All @@ -9,5 +9,7 @@ export default function isAbleToChangeFrame(): boolean {
const store = getCVATStore();

const state: CombinedState = store.getState();
return state.annotation.canvas.instance.isAbleToChangeFrame() && !state.annotation.player.navigationBlocked;
const { instance } = state.annotation.canvas;
return !!instance && instance.isAbleToChangeFrame() &&
!state.annotation.player.navigationBlocked;
}

0 comments on commit 1d084c4

Please sign in to comment.