Batch of fixes (#1370)

* Some margins were change to paddings

* Removed extra selected

* Fix: added outside shapes when merge polyshapes

* Fixed double scroll bars

* Updated canvas table

* Fixed setup methodf

* Disabled change frame during drag, resize and editing

* Fixed: hidden points are visible

* Fixed: Merge is allowed for points, but clicks on points conflict with frame dragging logic

* Fixed: do not filter removed objects

* Updated CHANGELOG.md

* Couple of headers updated
main
Boris Sekachev 6 years ago committed by GitHub
parent 76fc8e442d
commit 1d78c54029
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Increase preview size of a task till 256, 256 on the server - Increase preview size of a task till 256, 256 on the server
- Minor style updates
### Deprecated ### Deprecated
- -
@ -23,8 +24,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- New shape is added when press ``esc`` when drawing instead of cancellation - New shape is added when press ``esc`` when drawing instead of cancellation
- Fixed dextr segmentation. - Dextr segmentation doesn't work.
- Fixed `FileNotFoundError` during dump after moving format files - `FileNotFoundError` during dump after moving format files
- CVAT doesn't append outside shapes when merge polyshapes in old UI
- Layout sometimes shows double scroll bars on create task, dashboard and settings pages
- UI fails after trying to change frame during resizing, dragging, editing
- Hidden points (or outsided) are visible after changing a frame
- Merge is allowed for points, but clicks on points conflict with frame dragging logic
- Removed objects are visible for search
### Security ### Security
- -

@ -179,23 +179,23 @@ Standard JS events are used.
## API Reaction ## API Reaction
| | IDLE | GROUPING | SPLITTING | DRAWING | MERGING | EDITING | DRAG | ZOOM | | | IDLE | GROUP | SPLIT | DRAW | MERGE | EDIT | DRAG | RESIZE | ZOOM_CANVAS | DRAG_CANVAS |
|--------------|------|----------|-----------|---------|---------|---------|------|------| |--------------|------|-------|-------|------|-------|------|------|--------|-------------|-------------|
| html() | + | + | + | + | + | + | + | + | | html() | + | + | + | + | + | + | + | + | + | + |
| setup() | + | + | + | + | + | - | + | + | | setup() | + | + | + | + | + | - | - | - | + | + |
| activate() | + | - | - | - | - | - | - | - | | activate() | + | - | - | - | - | - | - | - | - | - |
| rotate() | + | + | + | + | + | + | + | + | | rotate() | + | + | + | + | + | + | + | + | + | + |
| focus() | + | + | + | + | + | + | + | + | | focus() | + | + | + | + | + | + | + | + | + | + |
| fit() | + | + | + | + | + | + | + | + | | fit() | + | + | + | + | + | + | + | + | + | + |
| grid() | + | + | + | + | + | + | + | + | | grid() | + | + | + | + | + | + | + | + | + | + |
| draw() | + | - | - | - | - | - | - | - | | draw() | + | - | - | - | - | - | - | - | - | - |
| split() | + | - | + | - | - | - | - | - | | split() | + | - | + | - | - | - | - | - | - | - |
| group() | + | + | - | - | - | - | - | - | | group() | + | + | - | - | - | - | - | - | - | - |
| merge() | + | - | - | - | + | - | - | - | | merge() | + | - | - | - | + | - | - | - | - | - |
| fitCanvas() | + | + | + | + | + | + | + | + | | fitCanvas() | + | + | + | + | + | + | + | + | + | + |
| dragCanvas() | + | - | - | - | - | - | + | - | | dragCanvas() | + | - | - | - | - | - | + | - | - | + |
| zoomCanvas() | + | - | - | - | - | - | - | + | | zoomCanvas() | + | - | - | - | - | - | - | + | + | - |
| cancel() | - | + | + | + | + | + | + | + | | cancel() | - | + | + | + | + | + | + | + | + | + |
| configure() | + | - | - | - | - | - | - | - | | configure() | + | - | - | - | - | - | - | - | - | - |
| bitmap() | + | + | + | + | + | + | + | + | | bitmap() | + | + | + | + | + | + | + | + | + | + |
| setZLayer() | + | + | + | + | + | + | + | + | | setZLayer() | + | + | + | + | + | + | + | + | + | + |

@ -327,6 +327,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
} }
public setup(frameData: any, objectStates: any[]): void { public setup(frameData: any, objectStates: any[]): void {
if ([Mode.EDIT, Mode.DRAG, Mode.RESIZE].includes(this.data.mode)) {
throw Error(`Canvas is busy. Action: ${this.data.mode}`);
}
if (frameData.number === this.data.imageID) { if (frameData.number === this.data.imageID) {
this.data.objects = objectStates; this.data.objects = objectStates;
this.notify(UpdateReasons.OBJECTS_UPDATED); this.notify(UpdateReasons.OBJECTS_UPDATED);

@ -1041,7 +1041,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
(shape as any).clear(); (shape as any).clear();
shape.attr('points', stringified); shape.attr('points', stringified);
if (state.shapeType === 'points') { if (state.shapeType === 'points' && !state.hidden) {
this.selectize(false, shape); this.selectize(false, shape);
this.setupPoints(shape as SVG.PolyLine, state); this.setupPoints(shape as SVG.PolyLine, state);
} }
@ -1187,7 +1187,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
(shape as any).off('resizestart'); (shape as any).off('resizestart');
(shape as any).off('resizing'); (shape as any).off('resizing');
(shape as any).off('resizedone'); (shape as any).off('resizedone');
(shape as any).resize(false); (shape as any).resize('stop');
// TODO: Hide text only if it is hidden by settings // TODO: Hide text only if it is hidden by settings
const text = this.svgTexts[clientID]; const text = this.svgTexts[clientID];
@ -1543,6 +1543,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
group.on('click.canvas', (event: MouseEvent): void => { group.on('click.canvas', (event: MouseEvent): void => {
// Need to redispatch the event on another element // Need to redispatch the event on another element
basicPolyline.fire(new MouseEvent('click', event)); basicPolyline.fire(new MouseEvent('click', event));
// redispatch event to canvas to be able merge points clicking them
this.content.dispatchEvent(new MouseEvent('click', event));
}); });
group.bbox = basicPolyline.bbox.bind(basicPolyline); group.bbox = basicPolyline.bbox.bind(basicPolyline);

@ -871,8 +871,10 @@
// In particular consider first and last frame as keyframes for all frames // In particular consider first and last frame as keyframes for all frames
const statesData = [].concat( const statesData = [].concat(
(frame in this.shapes ? this.shapes[frame] : []) (frame in this.shapes ? this.shapes[frame] : [])
.filter((shape) => !shape.removed)
.map((shape) => shape.get(frame)), .map((shape) => shape.get(frame)),
(frame in this.tags ? this.tags[frame] : []) (frame in this.tags ? this.tags[frame] : [])
.filter((tag) => !tag.removed)
.map((tag) => tag.get(frame)), .map((tag) => tag.get(frame)),
); );
const tracks = Object.values(this.tracks) const tracks = Object.values(this.tracks)
@ -880,7 +882,7 @@
frame in track.shapes frame in track.shapes
|| frame === frameFrom || frame === frameFrom
|| frame === frameTo || frame === frameTo
)); )).filter((track) => !track.removed);
statesData.push( statesData.push(
...tracks.map((track) => track.get(frame)) ...tracks.map((track) => track.get(frame))
.filter((state) => !state.outside), .filter((state) => !state.outside),

@ -36,7 +36,17 @@ export default function AnnotationPageComponent(props: Props): JSX.Element {
useEffect(() => { useEffect(() => {
saveLogs(); saveLogs();
return saveLogs; const root = window.document.getElementById('root');
if (root) {
root.style.minHeight = '768px';
}
return () => {
saveLogs();
if (root) {
root.style.minHeight = '';
}
};
}, []); }, []);
if (job === null) { if (job === null) {

@ -6,7 +6,7 @@
.cvat-create-task-form-wrapper { .cvat-create-task-form-wrapper {
text-align: center; text-align: center;
margin-top: 40px; padding-top: 40px;
overflow-y: auto; overflow-y: auto;
height: 90%; height: 90%;

@ -9,7 +9,7 @@
height: 100%; height: 100%;
> div:nth-child(1) { > div:nth-child(1) {
margin-bottom: 10px; padding-bottom: 10px;
div > { div > {
span { span {
@ -36,11 +36,11 @@
> div:nth-child(3) { > div:nth-child(3) {
height: 83%; height: 83%;
margin-top: 10px; padding-top: 10px;
} }
> div:nth-child(4) { > div:nth-child(4) {
margin-top: 10px; padding-top: 10px;
} }
} }

@ -7,6 +7,7 @@ import copy from 'copy-to-clipboard';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { LogType } from 'cvat-logger'; import { LogType } from 'cvat-logger';
import { Canvas, isAbleToChangeFrame } from 'cvat-canvas';
import { ActiveControl, CombinedState, ColorBy } from 'reducers/interfaces'; import { ActiveControl, CombinedState, ColorBy } from 'reducers/interfaces';
import { import {
collapseObjectItems, collapseObjectItems,
@ -24,7 +25,6 @@ import {
import ObjectStateItemComponent from 'components/annotation-page/standard-workspace/objects-side-bar/object-item'; import ObjectStateItemComponent from 'components/annotation-page/standard-workspace/objects-side-bar/object-item';
interface OwnProps { interface OwnProps {
clientID: number; clientID: number;
} }
@ -44,6 +44,7 @@ interface StateToProps {
minZLayer: number; minZLayer: number;
maxZLayer: number; maxZLayer: number;
normalizedKeyMap: Record<string, string>; normalizedKeyMap: Record<string, string>;
canvasInstance: Canvas;
} }
interface DispatchToProps { interface DispatchToProps {
@ -84,6 +85,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
canvas: { canvas: {
ready, ready,
activeControl, activeControl,
instance: canvasInstance,
}, },
colors, colors,
}, },
@ -119,6 +121,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
minZLayer, minZLayer,
maxZLayer, maxZLayer,
normalizedKeyMap, normalizedKeyMap,
canvasInstance,
}; };
} }
@ -166,72 +169,44 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
type Props = StateToProps & DispatchToProps; type Props = StateToProps & DispatchToProps;
class ObjectItemContainer extends React.PureComponent<Props> { class ObjectItemContainer extends React.PureComponent<Props> {
private navigateFirstKeyframe = (): void => { private navigateFirstKeyframe = (): void => {
const { const { objectState, frameNumber } = this.props;
objectState,
changeFrame,
frameNumber,
} = this.props;
const { first } = objectState.keyframes; const { first } = objectState.keyframes;
if (first !== frameNumber) { if (first !== frameNumber) {
changeFrame(first); this.changeFrame(first);
} }
}; };
private navigatePrevKeyframe = (): void => { private navigatePrevKeyframe = (): void => {
const { const { objectState, frameNumber } = this.props;
objectState,
changeFrame,
frameNumber,
} = this.props;
const { prev } = objectState.keyframes; const { prev } = objectState.keyframes;
if (prev !== null && prev !== frameNumber) { if (prev !== null && prev !== frameNumber) {
changeFrame(prev); this.changeFrame(prev);
} }
}; };
private navigateNextKeyframe = (): void => { private navigateNextKeyframe = (): void => {
const { const { objectState, frameNumber } = this.props;
objectState,
changeFrame,
frameNumber,
} = this.props;
const { next } = objectState.keyframes; const { next } = objectState.keyframes;
if (next !== null && next !== frameNumber) { if (next !== null && next !== frameNumber) {
changeFrame(next); this.changeFrame(next);
} }
}; };
private navigateLastKeyframe = (): void => { private navigateLastKeyframe = (): void => {
const { const { objectState, frameNumber } = this.props;
objectState,
changeFrame,
frameNumber,
} = this.props;
const { last } = objectState.keyframes; const { last } = objectState.keyframes;
if (last !== frameNumber) { if (last !== frameNumber) {
changeFrame(last); this.changeFrame(last);
} }
}; };
private copy = (): void => { private copy = (): void => {
const { const { objectState, copyShape } = this.props;
objectState,
copyShape,
} = this.props;
copyShape(objectState); copyShape(objectState);
}; };
private propagate = (): void => { private propagate = (): void => {
const { const { objectState, propagateObject } = this.props;
objectState,
propagateObject,
} = this.props;
propagateObject(objectState); propagateObject(objectState);
}; };
@ -422,6 +397,13 @@ class ObjectItemContainer extends React.PureComponent<Props> {
this.commit(); this.commit();
}; };
private changeFrame(frame: number): void {
const { changeFrame, canvasInstance } = this.props;
if (isAbleToChangeFrame(canvasInstance)) {
changeFrame(frame);
}
}
private commit(): void { private commit(): void {
const { const {
objectState, objectState,

@ -15,6 +15,7 @@ import {
copyShape as copyShapeAction, copyShape as copyShapeAction,
propagateObject as propagateObjectAction, propagateObject as propagateObjectAction,
} from 'actions/annotation-actions'; } from 'actions/annotation-actions';
import { Canvas, isAbleToChangeFrame } from 'cvat-canvas';
import { CombinedState, StatesOrdering, ObjectType } from 'reducers/interfaces'; import { CombinedState, StatesOrdering, ObjectType } from 'reducers/interfaces';
interface StateToProps { interface StateToProps {
@ -32,6 +33,7 @@ interface StateToProps {
annotationsFiltersHistory: string[]; annotationsFiltersHistory: string[];
keyMap: Record<string, ExtendedKeyMapOptions>; keyMap: Record<string, ExtendedKeyMapOptions>;
normalizedKeyMap: Record<string, string>; normalizedKeyMap: Record<string, string>;
canvasInstance: Canvas;
} }
interface DispatchToProps { interface DispatchToProps {
@ -65,6 +67,9 @@ function mapStateToProps(state: CombinedState): StateToProps {
number: frameNumber, number: frameNumber,
}, },
}, },
canvas: {
instance: canvasInstance,
},
tabContentHeight: listHeight, tabContentHeight: listHeight,
}, },
shortcuts: { shortcuts: {
@ -104,6 +109,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
annotationsFiltersHistory, annotationsFiltersHistory,
keyMap, keyMap,
normalizedKeyMap, normalizedKeyMap,
canvasInstance,
}; };
} }
@ -254,6 +260,7 @@ class ObjectsListContainer extends React.PureComponent<Props, State> {
minZLayer, minZLayer,
keyMap, keyMap,
normalizedKeyMap, normalizedKeyMap,
canvasInstance,
} = this.props; } = this.props;
const { const {
sortedStatesID, sortedStatesID,
@ -388,7 +395,7 @@ class ObjectsListContainer extends React.PureComponent<Props, State> {
if (state && state.objectType === ObjectType.TRACK) { if (state && state.objectType === ObjectType.TRACK) {
const frame = typeof (state.keyframes.next) === 'number' const frame = typeof (state.keyframes.next) === 'number'
? state.keyframes.next : null; ? state.keyframes.next : null;
if (frame !== null) { if (frame !== null && isAbleToChangeFrame(canvasInstance)) {
changeFrame(frame); changeFrame(frame);
} }
} }
@ -399,7 +406,7 @@ class ObjectsListContainer extends React.PureComponent<Props, State> {
if (state && state.objectType === ObjectType.TRACK) { if (state && state.objectType === ObjectType.TRACK) {
const frame = typeof (state.keyframes.prev) === 'number' const frame = typeof (state.keyframes.prev) === 'number'
? state.keyframes.prev : null; ? state.keyframes.prev : null;
if (frame !== null) { if (frame !== null && isAbleToChangeFrame(canvasInstance)) {
changeFrame(frame); changeFrame(frame);
} }
} }

@ -23,6 +23,7 @@ import {
changeWorkspace as changeWorkspaceAction, changeWorkspace as changeWorkspaceAction,
activateObject, activateObject,
} from 'actions/annotation-actions'; } from 'actions/annotation-actions';
import { Canvas, isAbleToChangeFrame } from 'cvat-canvas';
import AnnotationTopBarComponent from 'components/annotation-page/top-bar/top-bar'; import AnnotationTopBarComponent from 'components/annotation-page/top-bar/top-bar';
import { CombinedState, FrameSpeed, Workspace } from 'reducers/interfaces'; import { CombinedState, FrameSpeed, Workspace } from 'reducers/interfaces';
@ -45,6 +46,7 @@ interface StateToProps {
workspace: Workspace; workspace: Workspace;
keyMap: Record<string, ExtendedKeyMapOptions>; keyMap: Record<string, ExtendedKeyMapOptions>;
normalizedKeyMap: Record<string, string>; normalizedKeyMap: Record<string, string>;
canvasInstance: Canvas;
} }
interface DispatchToProps { interface DispatchToProps {
@ -81,6 +83,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
}, },
canvas: { canvas: {
ready: canvasIsReady, ready: canvasIsReady,
instance: canvasInstance,
}, },
workspace, workspace,
}, },
@ -118,6 +121,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
workspace, workspace,
keyMap, keyMap,
normalizedKeyMap, normalizedKeyMap,
canvasInstance,
}; };
} }
@ -197,6 +201,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
frameDelay, frameDelay,
playing, playing,
canvasIsReady, canvasIsReady,
canvasInstance,
onSwitchPlay, onSwitchPlay,
onChangeFrame, onChangeFrame,
} = this.props; } = this.props;
@ -217,10 +222,14 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
setTimeout(() => { setTimeout(() => {
const { playing: stillPlaying } = this.props; const { playing: stillPlaying } = this.props;
if (stillPlaying) { if (stillPlaying) {
onChangeFrame( if (isAbleToChangeFrame(canvasInstance)) {
frameNumber + 1 + framesSkiped, onChangeFrame(
stillPlaying, framesSkiped + 1, frameNumber + 1 + framesSkiped,
); stillPlaying, framesSkiped + 1,
);
} else {
onSwitchPlay(false);
}
} }
}, frameDelay); }, frameDelay);
} else { } else {
@ -240,9 +249,12 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
undo, undo,
jobInstance, jobInstance,
frameNumber, frameNumber,
canvasInstance,
} = this.props; } = this.props;
undo(jobInstance, frameNumber); if (isAbleToChangeFrame(canvasInstance)) {
undo(jobInstance, frameNumber);
}
}; };
private redo = (): void => { private redo = (): void => {
@ -250,9 +262,12 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
redo, redo,
jobInstance, jobInstance,
frameNumber, frameNumber,
canvasInstance,
} = this.props; } = this.props;
redo(jobInstance, frameNumber); if (isAbleToChangeFrame(canvasInstance)) {
redo(jobInstance, frameNumber);
}
}; };
private showStatistics = (): void => { private showStatistics = (): void => {
@ -285,7 +300,6 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
jobInstance, jobInstance,
playing, playing,
onSwitchPlay, onSwitchPlay,
onChangeFrame,
} = this.props; } = this.props;
const newFrame = jobInstance.startFrame; const newFrame = jobInstance.startFrame;
@ -293,7 +307,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(newFrame); this.changeFrame(newFrame);
} }
}; };
@ -304,7 +318,6 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
jobInstance, jobInstance,
playing, playing,
onSwitchPlay, onSwitchPlay,
onChangeFrame,
} = this.props; } = this.props;
const newFrame = Math const newFrame = Math
@ -313,7 +326,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(newFrame); this.changeFrame(newFrame);
} }
}; };
@ -323,7 +336,6 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
jobInstance, jobInstance,
playing, playing,
onSwitchPlay, onSwitchPlay,
onChangeFrame,
} = this.props; } = this.props;
const newFrame = Math const newFrame = Math
@ -332,7 +344,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(newFrame); this.changeFrame(newFrame);
} }
}; };
@ -342,7 +354,6 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
jobInstance, jobInstance,
playing, playing,
onSwitchPlay, onSwitchPlay,
onChangeFrame,
} = this.props; } = this.props;
const newFrame = Math const newFrame = Math
@ -351,7 +362,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(newFrame); this.changeFrame(newFrame);
} }
}; };
@ -362,7 +373,6 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
jobInstance, jobInstance,
playing, playing,
onSwitchPlay, onSwitchPlay,
onChangeFrame,
} = this.props; } = this.props;
const newFrame = Math const newFrame = Math
@ -371,7 +381,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(newFrame); this.changeFrame(newFrame);
} }
}; };
@ -381,7 +391,6 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
jobInstance, jobInstance,
playing, playing,
onSwitchPlay, onSwitchPlay,
onChangeFrame,
} = this.props; } = this.props;
const newFrame = jobInstance.stopFrame; const newFrame = jobInstance.stopFrame;
@ -389,7 +398,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(newFrame); this.changeFrame(newFrame);
} }
}; };
@ -403,22 +412,16 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
}; };
private onChangePlayerSliderValue = (value: SliderValue): void => { private onChangePlayerSliderValue = (value: SliderValue): void => {
const { const { playing, onSwitchPlay } = this.props;
playing,
onSwitchPlay,
onChangeFrame,
} = this.props;
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(value as number); this.changeFrame(value as number);
}; };
private onChangePlayerInputValue = (value: number): void => { private onChangePlayerInputValue = (value: number): void => {
const { const {
onSwitchPlay, onSwitchPlay,
onChangeFrame,
playing, playing,
frameNumber, frameNumber,
} = this.props; } = this.props;
@ -427,7 +430,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
if (playing) { if (playing) {
onSwitchPlay(false); onSwitchPlay(false);
} }
onChangeFrame(value); this.changeFrame(value);
} }
}; };
@ -441,6 +444,13 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
copy(url); copy(url);
}; };
private changeFrame(frame: number): void {
const { onChangeFrame, canvasInstance } = this.props;
if (isAbleToChangeFrame(canvasInstance)) {
onChangeFrame(frame);
}
}
private beforeUnloadCallback(event: BeforeUnloadEvent): any { private beforeUnloadCallback(event: BeforeUnloadEvent): any {
const { jobInstance } = this.props; const { jobInstance } = this.props;
if (jobInstance.annotations.hasUnsavedChanges()) { if (jobInstance.annotations.hasUnsavedChanges()) {
@ -472,6 +482,7 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
changeWorkspace, changeWorkspace,
keyMap, keyMap,
normalizedKeyMap, normalizedKeyMap,
canvasInstance,
} = this.props; } = this.props;
const preventDefault = (event: KeyboardEvent | undefined): void => { const preventDefault = (event: KeyboardEvent | undefined): void => {
@ -537,13 +548,17 @@ class AnnotationTopBarContainer extends React.PureComponent<Props> {
}, },
SEARCH_FORWARD: (event: KeyboardEvent | undefined) => { SEARCH_FORWARD: (event: KeyboardEvent | undefined) => {
preventDefault(event); preventDefault(event);
if (frameNumber + 1 <= stopFrame && canvasIsReady) { if (frameNumber + 1 <= stopFrame && canvasIsReady
&& isAbleToChangeFrame(canvasInstance)
) {
searchAnnotations(jobInstance, frameNumber + 1, stopFrame); searchAnnotations(jobInstance, frameNumber + 1, stopFrame);
} }
}, },
SEARCH_BACKWARD: (event: KeyboardEvent | undefined) => { SEARCH_BACKWARD: (event: KeyboardEvent | undefined) => {
preventDefault(event); preventDefault(event);
if (frameNumber - 1 >= startFrame && canvasIsReady) { if (frameNumber - 1 >= startFrame && canvasIsReady
&& isAbleToChangeFrame(canvasInstance)
) {
searchAnnotations(jobInstance, frameNumber - 1, startFrame); searchAnnotations(jobInstance, frameNumber - 1, startFrame);
} }
}, },

@ -9,9 +9,15 @@ import {
RectDrawingMethod, RectDrawingMethod,
} from '../../cvat-canvas/src/typescript/canvas'; } from '../../cvat-canvas/src/typescript/canvas';
function isAbleToChangeFrame(canvas: Canvas): boolean {
return ![CanvasMode.DRAG, CanvasMode.EDIT, CanvasMode.RESIZE]
.includes(canvas.mode());
}
export { export {
Canvas, Canvas,
CanvasMode, CanvasMode,
CanvasVersion, CanvasVersion,
RectDrawingMethod, RectDrawingMethod,
isAbleToChangeFrame,
}; };

@ -48,5 +48,4 @@ hr {
height: 100%; height: 100%;
display: grid; display: grid;
min-width: 1280px; min-width: 1280px;
min-height: 768px;
} }

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2018 Intel Corporation * Copyright (C) 2018-2020 Intel Corporation
* *
* SPDX-License-Identifier: MIT * SPDX-License-Identifier: MIT
*/ */
@ -145,7 +145,7 @@ class ShapeMergerModel extends Listener {
let nextFrame = frame + 1; let nextFrame = frame + 1;
let stopFrame = window.cvat.player.frames.stop; let stopFrame = window.cvat.player.frames.stop;
let type = shapeDict[frame].shape.type; let type = shapeDict[frame].shape.type;
if (type === 'annotation_box' && !(nextFrame in shapeDict) && nextFrame <= stopFrame) { if (type.startsWith('annotation_') && !(nextFrame in shapeDict) && nextFrame <= stopFrame) {
let copy = Object.assign({}, object.shapes[object.shapes.length - 1]); let copy = Object.assign({}, object.shapes[object.shapes.length - 1]);
copy.outside = true; copy.outside = true;
copy.frame += 1; copy.frame += 1;

@ -1,5 +1,5 @@
<!-- <!--
Copyright (C) 2018-2019 Intel Corporation Copyright (C) 2018-2020 Intel Corporation
SPDX-License-Identifier: MIT SPDX-License-Identifier: MIT
--> -->
@ -451,7 +451,7 @@
</select> </select>
<select id="shapeTypeSelector" class="regular h2"> <select id="shapeTypeSelector" class="regular h2">
<option value="box" class="regular" selected> Box </option> <option value="box" class="regular" selected> Box </option>
<option value="box_by_4_points" class="regular" selected> Box by 4 points </option> <option value="box_by_4_points" class="regular"> Box by 4 points </option>
<option value="polygon" class="regular"> Polygon </option> <option value="polygon" class="regular"> Polygon </option>
<option value="polyline" class="regular"> Polyline </option> <option value="polyline" class="regular"> Polyline </option>
<option value="points" class="regular"> Points </option> <option value="points" class="regular"> Points </option>

Loading…
Cancel
Save