Added tag support in new UI (without canvas drawing)

main
Dmitry Kalinin 6 years ago
parent f468c4035f
commit 3199fbbdf9

@ -399,8 +399,11 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.svgTexts[state.clientID].remove(); this.svgTexts[state.clientID].remove();
} }
this.svgShapes[state.clientID].off('click.canvas'); const shape = this.svgShapes[state.clientID];
this.svgShapes[state.clientID].remove(); if (shape) {
shape.off('click.canvas');
shape.remove();
}
delete this.drawnStates[state.clientID]; delete this.drawnStates[state.clientID];
} }
@ -847,7 +850,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
hidden: state.hidden, hidden: state.hidden,
lock: state.lock, lock: state.lock,
shapeType: state.shapeType, shapeType: state.shapeType,
points: [...state.points], points: Array.isArray(state.points) ? [...state.points] : [],
attributes: { ...state.attributes }, attributes: { ...state.attributes },
zOrder: state.zOrder, zOrder: state.zOrder,
pinned: state.pinned, pinned: state.pinned,
@ -892,7 +895,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.activate(activeElement); this.activate(activeElement);
} }
if (state.points if (state.points && state.points
.some((p: number, id: number): boolean => p !== drawnState.points[id]) .some((p: number, id: number): boolean => p !== drawnState.points[id])
) { ) {
const translatedPoints: number[] = translate(state.points); const translatedPoints: number[] = translate(state.points);
@ -1021,22 +1024,24 @@ export class CanvasViewImpl implements CanvasView, Listener {
const drawnState = this.drawnStates[clientID]; const drawnState = this.drawnStates[clientID];
const shape = this.svgShapes[clientID]; const shape = this.svgShapes[clientID];
shape.removeClass('cvat_canvas_shape_activated'); if (shape) {
shape.removeClass('cvat_canvas_shape_activated');
if (!drawnState.pinned) { if (!drawnState.pinned) {
(shape as any).off('dragstart'); (shape as any).off('dragstart');
(shape as any).off('dragend'); (shape as any).off('dragend');
(shape as any).draggable(false); (shape as any).draggable(false);
} }
if (drawnState.shapeType !== 'points') { if (drawnState.shapeType !== 'points') {
this.selectize(false, shape); this.selectize(false, shape);
} }
(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(false);
}
// 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];
@ -1085,6 +1090,11 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.activeElement = { ...activeElement }; this.activeElement = { ...activeElement };
const shape = this.svgShapes[clientID]; const shape = this.svgShapes[clientID];
if (!shape) {
return;
}
let text = this.svgTexts[clientID]; let text = this.svgTexts[clientID];
if (!text) { if (!text) {
text = this.addText(state); text = this.addText(state);

@ -810,11 +810,13 @@
'The object has not been saved yet. Call annotations.put([state]) before', 'The object has not been saved yet. Call annotations.put([state]) before',
); );
} }
if (!(object instanceof Tag)) {
const distance = object.constructor.distance(state.points, x, y); const distance = object.constructor.distance(state.points, x, y);
if (distance !== null && (minimumDistance === null || distance < minimumDistance)) { if (distance !== null && (minimumDistance === null
minimumDistance = distance; || distance < minimumDistance)) {
minimumState = state; minimumDistance = distance;
minimumState = state;
}
} }
} }

@ -85,7 +85,6 @@ export enum AnnotationActionTypes {
EDIT_SHAPE = 'EDIT_SHAPE', EDIT_SHAPE = 'EDIT_SHAPE',
DRAW_SHAPE = 'DRAW_SHAPE', DRAW_SHAPE = 'DRAW_SHAPE',
SHAPE_DRAWN = 'SHAPE_DRAWN', SHAPE_DRAWN = 'SHAPE_DRAWN',
SETUP_TAG = 'SETUP_TAG',
RESET_CANVAS = 'RESET_CANVAS', RESET_CANVAS = 'RESET_CANVAS',
UPDATE_ANNOTATIONS_SUCCESS = 'UPDATE_ANNOTATIONS_SUCCESS', UPDATE_ANNOTATIONS_SUCCESS = 'UPDATE_ANNOTATIONS_SUCCESS',
UPDATE_ANNOTATIONS_FAILED = 'UPDATE_ANNOTATIONS_FAILED', UPDATE_ANNOTATIONS_FAILED = 'UPDATE_ANNOTATIONS_FAILED',
@ -526,10 +525,31 @@ export function editShape(enabled: boolean): AnyAction {
} }
export function copyShape(objectState: any): AnyAction { export function copyShape(objectState: any): AnyAction {
const state = getStore().getState();
state.annotation.canvas.instance.cancel();
if (objectState.objectType !== ObjectType.TAG) {
state.annotation.canvas.instance.draw({
enabled: true,
initialState: objectState,
});
}
let activeControl = ActiveControl.CURSOR;
if (objectState.shapeType === ShapeType.RECTANGLE) {
activeControl = ActiveControl.DRAW_RECTANGLE;
} else if (objectState.shapeType === ShapeType.POINTS) {
activeControl = ActiveControl.DRAW_POINTS;
} else if (objectState.shapeType === ShapeType.POLYGON) {
activeControl = ActiveControl.DRAW_POLYGON;
} else if (objectState.shapeType === ShapeType.POLYLINE) {
activeControl = ActiveControl.DRAW_POLYLINE;
}
return { return {
type: AnnotationActionTypes.COPY_SHAPE, type: AnnotationActionTypes.COPY_SHAPE,
payload: { payload: {
objectState, activeControl,
}, },
}; };
} }
@ -856,20 +876,6 @@ export function drawShape(
}; };
} }
export function setupTag(
labelID: number,
objectType: ObjectType,
): AnyAction {
return {
type: AnnotationActionTypes.SETUP_TAG,
payload: {
labelID,
objectType,
activeControl: ActiveControl.SETUP_TAG,
},
};
}
export function shapeDrawn(): AnyAction { export function shapeDrawn(): AnyAction {
return { return {
type: AnnotationActionTypes.SHAPE_DRAWN, type: AnnotationActionTypes.SHAPE_DRAWN,

@ -43,6 +43,7 @@ import {
function ItemMenu( function ItemMenu(
serverID: number | undefined, serverID: number | undefined,
locked: boolean, locked: boolean,
objectType: ObjectType,
copy: (() => void), copy: (() => void),
remove: (() => void), remove: (() => void),
propagate: (() => void), propagate: (() => void),
@ -68,13 +69,13 @@ function ItemMenu(
</Button> </Button>
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<Button type='link' onClick={toBackground}> <Button disabled={objectType === ObjectType.TAG} type='link' onClick={toBackground}>
<Icon component={BackgroundIcon} /> <Icon component={BackgroundIcon} />
To background To background
</Button> </Button>
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<Button type='link' onClick={toForeground}> <Button disabled={objectType === ObjectType.TAG} type='link' onClick={toForeground}>
<Icon component={ForegroundIcon} /> <Icon component={ForegroundIcon} />
To foreground To foreground
</Button> </Button>
@ -109,6 +110,7 @@ interface ItemTopComponentProps {
serverID: number | undefined; serverID: number | undefined;
labelID: number; labelID: number;
labels: any[]; labels: any[];
objectType: ObjectType;
type: string; type: string;
locked: boolean; locked: boolean;
changeLabel(labelID: string): void; changeLabel(labelID: string): void;
@ -126,6 +128,7 @@ function ItemTopComponent(props: ItemTopComponentProps): JSX.Element {
serverID, serverID,
labelID, labelID,
labels, labels,
objectType,
type, type,
locked, locked,
changeLabel, changeLabel,
@ -159,6 +162,7 @@ function ItemTopComponent(props: ItemTopComponentProps): JSX.Element {
overlay={ItemMenu( overlay={ItemMenu(
serverID, serverID,
locked, locked,
objectType,
copy, copy,
remove, remove,
propagate, propagate,
@ -302,6 +306,22 @@ function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
); );
} }
if (objectType === ObjectType.TAG) {
return (
<Row type='flex' align='middle' justify='space-around'>
<Col span={20} style={{ textAlign: 'center' }}>
<Row type='flex' justify='space-around'>
<Col>
{ locked
? <Icon type='lock' onClick={unlock} />
: <Icon type='unlock' onClick={lock} />}
</Col>
</Row>
</Col>
</Row>
);
}
return ( return (
<Row type='flex' align='middle' justify='space-around'> <Row type='flex' align='middle' justify='space-around'>
<Col span={20} style={{ textAlign: 'center' }}> <Col span={20} style={{ textAlign: 'center' }}>
@ -726,6 +746,7 @@ function ObjectItemComponent(props: Props): JSX.Element {
clientID={clientID} clientID={clientID}
labelID={labelID} labelID={labelID}
labels={labels} labels={labels}
objectType={objectType}
type={type} type={type}
locked={locked} locked={locked}
changeLabel={changeLabel} changeLabel={changeLabel}

@ -11,28 +11,28 @@ import {
} from 'reducers/interfaces'; } from 'reducers/interfaces';
import { import {
setupTag createAnnotationsAsync,
} from 'actions/annotation-actions'; } from 'actions/annotation-actions';
import { Canvas } from 'cvat-canvas'; import { Canvas } from 'cvat-canvas';
import SetupTagPopoverComponent from 'components/annotation-page/standard-workspace/controls-side-bar/setup-tag-popover'; import SetupTagPopoverComponent from 'components/annotation-page/standard-workspace/controls-side-bar/setup-tag-popover';
import getCore from 'cvat-core';
const cvat = getCore();
interface DispatchToProps { interface DispatchToProps {
onTagSetup( onCreateAnnotations(sessionInstance: any, frame: number, states: any[]): void;
labelID: number,
): void;
} }
interface StateToProps { interface StateToProps {
canvasInstance: Canvas; canvasInstance: Canvas;
jobInstance: any;
labels: any[]; labels: any[];
frame: number;
} }
function mapDispatchToProps(dispatch: any): DispatchToProps { function mapDispatchToProps(dispatch: any): DispatchToProps {
return { return {
onTagSetup( onCreateAnnotations(sessionInstance: any, frame: number, states: any[]): void {
labelID: number, dispatch(createAnnotationsAsync(sessionInstance, frame, states));
): void {
dispatch(setupTag(labelID, ObjectType.TAG));
}, },
}; };
} }
@ -45,13 +45,21 @@ function mapStateToProps(state: CombinedState): StateToProps {
}, },
job: { job: {
labels, labels,
instance: jobInstance,
},
player: {
frame: {
number: frame,
},
}, },
}, },
} = state; } = state;
return { return {
canvasInstance, canvasInstance,
jobInstance,
labels, labels,
frame,
}; };
} }
@ -77,11 +85,27 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
}); });
}; };
private onSetup(labelID: number): void { private onSetup(): void {
const { canvasInstance, onTagSetup } = this.props; const {
canvasInstance,
onCreateAnnotations,
jobInstance,
frame,
} = this.props;
const { selectedLabelID } = this.state;
canvasInstance.cancel(); canvasInstance.cancel();
onTagSetup(labelID);
const state = {
objectType: ObjectType.TAG,
label: jobInstance.task.labels
.filter((label: any) => label.id === selectedLabelID)[0],
frame,
};
const objectState = new cvat.classes.ObjectState(state);
onCreateAnnotations(jobInstance, frame, [objectState]);
} }
public render(): JSX.Element { public render(): JSX.Element {

@ -9,10 +9,12 @@ import {
ActiveControl, ActiveControl,
CombinedState, CombinedState,
ColorBy, ColorBy,
ObjectType,
} from 'reducers/interfaces'; } from 'reducers/interfaces';
import { import {
collapseObjectItems, collapseObjectItems,
changeLabelColorAsync, changeLabelColorAsync,
createAnnotationsAsync,
updateAnnotationsAsync, updateAnnotationsAsync,
changeFrameAsync, changeFrameAsync,
removeObjectAsync, removeObjectAsync,
@ -23,6 +25,9 @@ import {
} from 'actions/annotation-actions'; } from 'actions/annotation-actions';
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';
import getCore from 'cvat-core';
const cvat = getCore();
interface OwnProps { interface OwnProps {
clientID: number; clientID: number;
@ -47,6 +52,7 @@ interface StateToProps {
interface DispatchToProps { interface DispatchToProps {
changeFrame(frame: number): void; changeFrame(frame: number): void;
updateState(sessionInstance: any, frameNumber: number, objectState: any): void; updateState(sessionInstance: any, frameNumber: number, objectState: any): void;
createAnnotations(sessionInstance: any, frameNumber: number, state: any): void
collapseOrExpand(objectStates: any[], collapsed: boolean): void; collapseOrExpand(objectStates: any[], collapsed: boolean): void;
activateObject: (activatedStateID: number | null) => void; activateObject: (activatedStateID: number | null) => void;
removeObject: (sessionInstance: any, objectState: any) => void; removeObject: (sessionInstance: any, objectState: any) => void;
@ -123,6 +129,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
updateState(sessionInstance: any, frameNumber: number, state: any): void { updateState(sessionInstance: any, frameNumber: number, state: any): void {
dispatch(updateAnnotationsAsync(sessionInstance, frameNumber, [state])); dispatch(updateAnnotationsAsync(sessionInstance, frameNumber, [state]));
}, },
createAnnotations(sessionInstance: any, frameNumber: number, state: any): void {
dispatch(createAnnotationsAsync(sessionInstance, frameNumber, state));
},
collapseOrExpand(objectStates: any[], collapsed: boolean): void { collapseOrExpand(objectStates: any[], collapsed: boolean): void {
dispatch(collapseObjectItems(objectStates, collapsed)); dispatch(collapseObjectItems(objectStates, collapsed));
}, },
@ -215,9 +224,21 @@ class ObjectItemContainer extends React.PureComponent<Props> {
const { const {
objectState, objectState,
copyShape, copyShape,
jobInstance,
frameNumber,
createAnnotations,
} = this.props; } = this.props;
copyShape(objectState); copyShape(objectState);
if (objectState.objectType === ObjectType.TAG) {
const state = new cvat.classes.ObjectState({
objectType: objectState.objectType,
label: objectState.label,
frame: frameNumber,
});
createAnnotations(jobInstance, frameNumber, [state]);
}
}; };
private propagate = (): void => { private propagate = (): void => {

@ -429,6 +429,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
...state, ...state,
annotations: { annotations: {
...state.annotations, ...state.annotations,
activatedStateID: null,
}, },
canvas: { canvas: {
...state.canvas, ...state.canvas,
@ -678,24 +679,9 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
} }
case AnnotationActionTypes.COPY_SHAPE: { case AnnotationActionTypes.COPY_SHAPE: {
const { const {
objectState, activeControl,
} = action.payload; } = action.payload;
state.canvas.instance.cancel();
state.canvas.instance.draw({
enabled: true,
initialState: objectState,
});
let activeControl = ActiveControl.DRAW_RECTANGLE;
if (objectState.shapeType === ShapeType.POINTS) {
activeControl = ActiveControl.DRAW_POINTS;
} else if (objectState.shapeType === ShapeType.POLYGON) {
activeControl = ActiveControl.DRAW_POLYGON;
} else if (objectState.shapeType === ShapeType.POLYLINE) {
activeControl = ActiveControl.DRAW_POLYLINE;
}
return { return {
...state, ...state,
canvas: { canvas: {

@ -245,7 +245,6 @@ export enum ActiveControl {
DRAW_POLYGON = 'draw_polygon', DRAW_POLYGON = 'draw_polygon',
DRAW_POLYLINE = 'draw_polyline', DRAW_POLYLINE = 'draw_polyline',
DRAW_POINTS = 'draw_points', DRAW_POINTS = 'draw_points',
SETUP_TAG = 'setup_tag',
MERGE = 'merge', MERGE = 'merge',
GROUP = 'group', GROUP = 'group',
SPLIT = 'split', SPLIT = 'split',

Loading…
Cancel
Save