未验证 提交 1d084c48 编写于 作者: B Boris Sekachev 提交者: GitHub

Fixed bug: canvas is busy (at least one reproducing way) (#4151)

* Fixed bug: canvas is busy (at least one reproducing way)

* Updated version & changelog

* Fixed license headers
上级 c83d1700
......@@ -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>)
......
{
"name": "cvat-canvas",
"version": "2.12.0",
"version": "2.12.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cvat-canvas",
"version": "2.12.0",
"version": "2.12.1",
"license": "MIT",
"dependencies": {
"@types/polylabel": "^1.0.5",
......
{
"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": {
......
// Copyright (C) 2019-2021 Intel Corporation
// Copyright (C) 2019-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT
......@@ -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();
......@@ -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) {
......@@ -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;
......@@ -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,
......@@ -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;
......@@ -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;
......
{
"name": "cvat-ui",
"version": "1.33.0",
"version": "1.33.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cvat-ui",
"version": "1.33.0",
"version": "1.33.1",
"license": "MIT",
"dependencies": {
"@ant-design/icons": "^4.6.3",
......
{
"name": "cvat-ui",
"version": "1.33.0",
"version": "1.33.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
......
// Copyright (C) 2020-2021 Intel Corporation
// Copyright (C) 2020-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT
......@@ -6,10 +6,12 @@ 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,
......@@ -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();
......@@ -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;
......
// Copyright (C) 2020-2021 Intel Corporation
// Copyright (C) 2020-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT
......@@ -308,14 +308,16 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}
}
if (frameFetching !== prevProps.frameFetching) {
const loadingAnimation = window.document.getElementById('cvat_canvas_loading_animation');
if (loadingAnimation && frameFetching !== prevProps.frameFetching) {
if (loadingAnimation) {
if (frameFetching) {
loadingAnimation.classList.remove('cvat_canvas_hidden');
} else {
loadingAnimation.classList.add('cvat_canvas_hidden');
}
}
}
if (prevProps.canvasBackgroundColor !== canvasBackgroundColor) {
const canvasWrapperElement = window.document
......
// Copyright (C) 2021 Intel Corporation
// Copyright (C) 2021-2022 Intel Corporation
//
// SPDX-License-Identifier: MIT
......@@ -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;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册