Add extreme clicking method in cvat-canvas and cvat-ui (#1127)

* Add extreme clicking method in cvat-canvas and cvat-ui

* Fix bugs and issues, update readme

* Fix error after rebasing develop
main
Jijoong Kim 6 years ago committed by GitHub
parent 20ed049111
commit d9fe71260b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -40,6 +40,7 @@ Canvas itself handles:
interface DrawData { interface DrawData {
enabled: boolean; enabled: boolean;
shapeType?: string; shapeType?: string;
rectDrawingMethod?: string;
numberOfPoints?: number; numberOfPoints?: number;
initialState?: any; initialState?: any;
crosshair?: boolean; crosshair?: boolean;

@ -40,6 +40,7 @@ export interface ActiveElement {
export interface DrawData { export interface DrawData {
enabled: boolean; enabled: boolean;
shapeType?: string; shapeType?: string;
rectDrawingMethod?: string;
numberOfPoints?: number; numberOfPoints?: number;
initialState?: any; initialState?: any;
crosshair?: boolean; crosshair?: boolean;

@ -160,7 +160,8 @@ export class DrawHandlerImpl implements DrawHandler {
if (!this.drawData.initialState) { if (!this.drawData.initialState) {
const { drawInstance } = this; const { drawInstance } = this;
this.drawInstance = null; this.drawInstance = null;
if (this.drawData.shapeType === 'rectangle') { if (this.drawData.shapeType === 'rectangle'
&& this.drawData.rectDrawingMethod !== 'by_four_points') {
drawInstance.draw('cancel'); drawInstance.draw('cancel');
} else { } else {
drawInstance.draw('done'); drawInstance.draw('done');
@ -200,6 +201,45 @@ export class DrawHandlerImpl implements DrawHandler {
}); });
} }
private drawBoxBy4Points(): void {
let numberOfPoints = 0;
this.drawInstance = (this.canvas as any).polygon()
.addClass('cvat_canvas_shape_drawing').attr({
'stroke-width': 0,
opacity: 0,
}).on('drawstart', () => {
// init numberOfPoints as one on drawstart
numberOfPoints = 1;
}).on('drawpoint', (e: CustomEvent) => {
// increase numberOfPoints by one on drawpoint
numberOfPoints += 1;
// finish if numberOfPoints are exactly four
if (numberOfPoints === 4) {
const bbox = (e.target as SVGPolylineElement).getBBox();
const [xtl, ytl, xbr, ybr] = this.getFinalRectCoordinates(bbox);
if ((xbr - xtl) * (ybr - ytl) >= consts.AREA_THRESHOLD) {
this.onDrawDone({
shapeType: this.drawData.shapeType,
points: [xtl, ytl, xbr, ybr],
});
} else {
this.onDrawDone(null);
}
}
}).on('undopoint', () => {
if (numberOfPoints > 0) {
numberOfPoints -= 1;
}
}).off('drawdone').on('drawdone', () => {
// close drawing mode without drawing rect
this.onDrawDone(null);
});
this.drawPolyshape();
}
private drawPolyshape(): void { private drawPolyshape(): void {
this.drawInstance.attr({ this.drawInstance.attr({
z_order: Number.MAX_SAFE_INTEGER, z_order: Number.MAX_SAFE_INTEGER,
@ -536,13 +576,18 @@ export class DrawHandlerImpl implements DrawHandler {
this.pastePoints(stringifiedPoints); this.pastePoints(stringifiedPoints);
} }
} }
this.setupPasteEvents(); this.setupPasteEvents();
} else { } else {
if (this.drawData.shapeType === 'rectangle') { if (this.drawData.shapeType === 'rectangle') {
this.drawBox(); if (this.drawData.rectDrawingMethod === 'by_four_points') {
// Draw instance was initialized after drawBox(); // draw box by extreme clicking
this.shapeSizeElement = displayShapeSize(this.canvas, this.text); this.drawBoxBy4Points();
} else {
// default box drawing
this.drawBox();
// Draw instance was initialized after drawBox();
this.shapeSizeElement = displayShapeSize(this.canvas, this.text);
}
} else if (this.drawData.shapeType === 'polygon') { } else if (this.drawData.shapeType === 'polygon') {
this.drawPolygon(); this.drawPolygon();
} else if (this.drawData.shapeType === 'polyline') { } else if (this.drawData.shapeType === 'polyline') {
@ -550,7 +595,6 @@ export class DrawHandlerImpl implements DrawHandler {
} else if (this.drawData.shapeType === 'points') { } else if (this.drawData.shapeType === 'points') {
this.drawPoints(); this.drawPoints();
} }
this.setupDrawEvents(); this.setupDrawEvents();
} }
} }

@ -583,6 +583,7 @@ export function drawShape(
labelID: number, labelID: number,
objectType: ObjectType, objectType: ObjectType,
points?: number, points?: number,
rectDrawingMethod?: string,
): AnyAction { ): AnyAction {
let activeControl = ActiveControl.DRAW_RECTANGLE; let activeControl = ActiveControl.DRAW_RECTANGLE;
if (shapeType === ShapeType.POLYGON) { if (shapeType === ShapeType.POLYGON) {
@ -601,6 +602,7 @@ export function drawShape(
objectType, objectType,
points, points,
activeControl, activeControl,
rectDrawingMethod,
}, },
}; };
} }

@ -6,22 +6,27 @@ import {
Select, Select,
Button, Button,
InputNumber, InputNumber,
Radio,
} from 'antd'; } from 'antd';
import { RadioChangeEvent } from 'antd/lib/radio';
import Text from 'antd/lib/typography/Text'; import Text from 'antd/lib/typography/Text';
import { import {
ShapeType, ShapeType,
RectDrawingMethod,
} from 'reducers/interfaces'; } from 'reducers/interfaces';
interface Props { interface Props {
shapeType: ShapeType; shapeType: ShapeType;
rectDrawingMethod: RectDrawingMethod;
labels: any[]; labels: any[];
minimumPoints: number; minimumPoints: number;
numberOfPoints?: number; numberOfPoints?: number;
selectedLabeID: number; selectedLabeID: number;
onChangeLabel(value: string): void; onChangeLabel(value: string): void;
onChangePoints(value: number | undefined): void; onChangePoints(value: number | undefined): void;
onChangeRectDrawingMethod(event: RadioChangeEvent): void;
onDrawTrack(): void; onDrawTrack(): void;
onDrawShape(): void; onDrawShape(): void;
} }
@ -37,6 +42,7 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
onDrawShape, onDrawShape,
onChangeLabel, onChangeLabel,
onChangePoints, onChangePoints,
onChangeRectDrawingMethod,
} = props; } = props;
return ( return (
@ -71,7 +77,37 @@ function DrawShapePopoverComponent(props: Props): JSX.Element {
</Col> </Col>
</Row> </Row>
{ {
shapeType !== ShapeType.RECTANGLE && ( shapeType === ShapeType.RECTANGLE ? (
<>
<Row>
<Col>
<Text className='cvat-text-color'> Drawing method </Text>
</Col>
</Row>
<Row type='flex' justify='space-around'>
<Col>
<Radio.Group
style={{ display: 'flex' }}
defaultValue={RectDrawingMethod.BY_TWO_POINTS}
onChange={onChangeRectDrawingMethod}
>
<Radio
value={RectDrawingMethod.BY_TWO_POINTS}
style={{ width: 'auto' }}
>
By 2 Points
</Radio>
<Radio
value={RectDrawingMethod.BY_FOUR_POINTS}
style={{ width: 'auto' }}
>
By 4 Points
</Radio>
</Radio.Group>
</Col>
</Row>
</>
) : (
<Row type='flex' justify='space-around' align='middle'> <Row type='flex' justify='space-around' align='middle'>
<Col span={14}> <Col span={14}>
<Text className='cvat-text-color'> Number of points: </Text> <Text className='cvat-text-color'> Number of points: </Text>

@ -1,10 +1,12 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { RadioChangeEvent } from 'antd/lib/radio';
import { import {
CombinedState, CombinedState,
ShapeType, ShapeType,
ObjectType, ObjectType,
RectDrawingMethod,
} from 'reducers/interfaces'; } from 'reducers/interfaces';
import { import {
@ -23,6 +25,7 @@ interface DispatchToProps {
labelID: number, labelID: number,
objectType: ObjectType, objectType: ObjectType,
points?: number, points?: number,
rectDrawingMethod?: string,
): void; ): void;
} }
@ -39,8 +42,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
labelID: number, labelID: number,
objectType: ObjectType, objectType: ObjectType,
points?: number, points?: number,
rectDrawingMethod?: string,
): void { ): void {
dispatch(drawShape(shapeType, labelID, objectType, points)); dispatch(drawShape(shapeType, labelID, objectType, points, rectDrawingMethod));
}, },
}; };
} }
@ -67,6 +71,7 @@ function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
type Props = StateToProps & DispatchToProps; type Props = StateToProps & DispatchToProps;
interface State { interface State {
rectDrawingMethod?: string;
numberOfPoints?: number; numberOfPoints?: number;
selectedLabelID: number; selectedLabelID: number;
} }
@ -77,6 +82,7 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
super(props); super(props);
const defaultLabelID = props.labels[0].id; const defaultLabelID = props.labels[0].id;
const defaultRectDrawingMethod = RectDrawingMethod.BY_TWO_POINTS;
this.state = { this.state = {
selectedLabelID: defaultLabelID, selectedLabelID: defaultLabelID,
}; };
@ -91,6 +97,9 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
if (shapeType === ShapeType.POINTS) { if (shapeType === ShapeType.POINTS) {
this.minimumPoints = 1; this.minimumPoints = 1;
} }
if (shapeType === ShapeType.RECTANGLE) {
this.state.rectDrawingMethod = defaultRectDrawingMethod;
}
} }
private onDraw(objectType: ObjectType): void { private onDraw(objectType: ObjectType): void {
@ -101,6 +110,7 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
} = this.props; } = this.props;
const { const {
rectDrawingMethod,
numberOfPoints, numberOfPoints,
selectedLabelID, selectedLabelID,
} = this.state; } = this.state;
@ -108,6 +118,7 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
canvasInstance.cancel(); canvasInstance.cancel();
canvasInstance.draw({ canvasInstance.draw({
enabled: true, enabled: true,
rectDrawingMethod,
numberOfPoints, numberOfPoints,
shapeType, shapeType,
crosshair: shapeType === ShapeType.RECTANGLE, crosshair: shapeType === ShapeType.RECTANGLE,
@ -117,6 +128,12 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
objectType, numberOfPoints); objectType, numberOfPoints);
} }
private onChangeRectDrawingMethod = (event: RadioChangeEvent): void => {
this.setState({
rectDrawingMethod: event.target.value,
});
};
private onDrawShape = (): void => { private onDrawShape = (): void => {
this.onDraw(ObjectType.SHAPE); this.onDraw(ObjectType.SHAPE);
}; };
@ -163,6 +180,7 @@ class DrawShapePopoverContainer extends React.PureComponent<Props, State> {
numberOfPoints={numberOfPoints} numberOfPoints={numberOfPoints}
onChangeLabel={this.onChangeLabel} onChangeLabel={this.onChangeLabel}
onChangePoints={this.onChangePoints} onChangePoints={this.onChangePoints}
onChangeRectDrawingMethod={this.onChangeRectDrawingMethod}
onDrawTrack={this.onDrawTrack} onDrawTrack={this.onDrawTrack}
onDrawShape={this.onDrawShape} onDrawShape={this.onDrawShape}
/> />

@ -338,6 +338,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
objectType, objectType,
points, points,
activeControl, activeControl,
rectDrawingMethod,
} = action.payload; } = action.payload;
return { return {
@ -355,6 +356,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
activeNumOfPoints: points, activeNumOfPoints: points,
activeObjectType: objectType, activeObjectType: objectType,
activeShapeType: shapeType, activeShapeType: shapeType,
activeRectDrawingMethod: rectDrawingMethod,
}, },
}; };
} }

@ -239,6 +239,11 @@ export enum ActiveControl {
EDIT = 'edit', EDIT = 'edit',
} }
export enum RectDrawingMethod {
BY_TWO_POINTS = 'by_two_points',
BY_FOUR_POINTS = 'by_four_points'
}
export enum ShapeType { export enum ShapeType {
RECTANGLE = 'rectangle', RECTANGLE = 'rectangle',
POLYGON = 'polygon', POLYGON = 'polygon',
@ -297,6 +302,7 @@ export interface AnnotationState {
}; };
drawing: { drawing: {
activeShapeType: ShapeType; activeShapeType: ShapeType;
activeRectDrawingMethod?: RectDrawingMethod;
activeNumOfPoints?: number; activeNumOfPoints?: number;
activeLabelID: number; activeLabelID: number;
activeObjectType: ObjectType; activeObjectType: ObjectType;

Loading…
Cancel
Save