Added point deletion context menu

main
Dmitry Kalinin 6 years ago
parent b0dbbb3faa
commit 845be3b486

@ -318,6 +318,7 @@ export function updateCanvasContextMenu(
left: number, left: number,
top: number, top: number,
type?: ContextMenuType, type?: ContextMenuType,
pointID?: number,
): AnyAction { ): AnyAction {
return { return {
type: AnnotationActionTypes.UPDATE_CANVAS_CONTEXT_MENU, type: AnnotationActionTypes.UPDATE_CANVAS_CONTEXT_MENU,
@ -326,6 +327,7 @@ export function updateCanvasContextMenu(
left, left,
top, top,
type, type,
pointID,
}, },
}; };
} }

@ -5,16 +5,21 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import {
Button,
} from 'antd';
interface Props { interface Props {
activatedStateID: number | null; activatedStateID: number | null;
visible: boolean; visible: boolean;
left: number; left: number;
top: number; top: number;
onPointDelete(): void;
} }
export default function CanvasPointContextMenu(props: Props): JSX.Element | null { export default function CanvasPointContextMenu(props: Props): JSX.Element | null {
const { const {
onPointDelete,
activatedStateID, activatedStateID,
visible, visible,
left, left,
@ -27,7 +32,9 @@ export default function CanvasPointContextMenu(props: Props): JSX.Element | null
return ReactDOM.createPortal( return ReactDOM.createPortal(
<div className='cvat-canvas-point-context-menu' style={{ top, left }}> <div className='cvat-canvas-point-context-menu' style={{ top, left }}>
<span>Haha</span> <Button type='link' icon='delete' onClick={onPointDelete}>
Delete point
</Button>
</div>, </div>,
window.document.body, window.document.body,
); );

@ -18,16 +18,10 @@ import {
GridColor, GridColor,
ObjectType, ObjectType,
ContextMenuType, ContextMenuType,
Workspace Workspace,
} from 'reducers/interfaces'; } from 'reducers/interfaces';
import { Canvas } from 'cvat-canvas'; import { Canvas } from 'cvat-canvas';
import getCore from 'cvat-core'; import getCore from 'cvat-core';
import {
ColorBy,
GridColor,
ObjectType,
Workspace,
} from 'reducers/interfaces';
const cvat = getCore(); const cvat = getCore();
@ -81,7 +75,8 @@ interface Props {
onSplitAnnotations(sessionInstance: any, frame: number, state: any): void; onSplitAnnotations(sessionInstance: any, frame: number, state: any): void;
onActivateObject(activatedStateID: number | null): void; onActivateObject(activatedStateID: number | null): void;
onSelectObjects(selectedStatesID: number[]): void; onSelectObjects(selectedStatesID: number[]): void;
onUpdateContextMenu(visible: boolean, left: number, top: number, type: ContextMenuType): void; onUpdateContextMenu(visible: boolean, left: number, top: number, type: ContextMenuType,
pointID?: number): void;
onAddZLayer(): void; onAddZLayer(): void;
onSwitchZLayer(cur: number): void; onSwitchZLayer(cur: number): void;
onChangeBrightnessLevel(level: number): void; onChangeBrightnessLevel(level: number): void;
@ -333,8 +328,17 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
}; };
private onCanvasContextMenu = (e: MouseEvent): void => { private onCanvasContextMenu = (e: MouseEvent): void => {
const { activatedStateID, onUpdateContextMenu } = this.props; const {
onUpdateContextMenu(activatedStateID !== null, e.clientX, e.clientY); activatedStateID,
onUpdateContextMenu,
contextVisible,
contextType,
} = this.props;
if (!contextVisible && contextType !== ContextMenuType.CANVAS_SHAPE_POINT) {
onUpdateContextMenu(activatedStateID !== null, e.clientX, e.clientY,
ContextMenuType.CANVAS_SHAPE);
}
}; };
private onCanvasShapeClicked = (e: any): void => { private onCanvasShapeClicked = (e: any): void => {
@ -460,6 +464,16 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
} }
}; };
private onCanvasPointContextMenu = (e: any): void => {
const {
activatedStateID,
onUpdateContextMenu,
} = this.props;
onUpdateContextMenu(activatedStateID !== null, e.detail.mouseEvent.clientX,
e.detail.mouseEvent.clientY, ContextMenuType.CANVAS_SHAPE_POINT, e.detail.pointID);
};
private activateOnCanvas(): void { private activateOnCanvas(): void {
const { const {
activatedStateID, activatedStateID,
@ -599,6 +613,8 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
canvasInstance.html().addEventListener('canvas.merged', this.onCanvasObjectsMerged); canvasInstance.html().addEventListener('canvas.merged', this.onCanvasObjectsMerged);
canvasInstance.html().addEventListener('canvas.groupped', this.onCanvasObjectsGroupped); canvasInstance.html().addEventListener('canvas.groupped', this.onCanvasObjectsGroupped);
canvasInstance.html().addEventListener('canvas.splitted', this.onCanvasTrackSplitted); canvasInstance.html().addEventListener('canvas.splitted', this.onCanvasTrackSplitted);
canvasInstance.html().addEventListener('point.contextmenu', this.onCanvasPointContextMenu);
} }
public render(): JSX.Element { public render(): JSX.Element {

@ -14,6 +14,7 @@ import ControlsSideBarContainer from 'containers/annotation-page/standard-worksp
import ObjectSideBarContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar'; import ObjectSideBarContainer from 'containers/annotation-page/standard-workspace/objects-side-bar/objects-side-bar';
import PropagateConfirmContainer from 'containers/annotation-page/standard-workspace/propagate-confirm'; import PropagateConfirmContainer from 'containers/annotation-page/standard-workspace/propagate-confirm';
import CanvasContextMenuContainer from 'containers/annotation-page/standard-workspace/canvas-context-menu'; import CanvasContextMenuContainer from 'containers/annotation-page/standard-workspace/canvas-context-menu';
import CanvasPointContextMenuContainer from 'containers/annotation-page/standard-workspace/canvas-point-context-menu';
export default function StandardWorkspaceComponent(): JSX.Element { export default function StandardWorkspaceComponent(): JSX.Element {
return ( return (
@ -23,6 +24,7 @@ export default function StandardWorkspaceComponent(): JSX.Element {
<ObjectSideBarContainer /> <ObjectSideBarContainer />
<PropagateConfirmContainer /> <PropagateConfirmContainer />
<CanvasContextMenuContainer /> <CanvasContextMenuContainer />
<CanvasPointContextMenuContainer />
</Layout> </Layout>
); );
} }

@ -136,10 +136,12 @@
.cvat-canvas-point-context-menu { .cvat-canvas-point-context-menu {
opacity: 0.6; opacity: 0.6;
position: fixed; position: fixed;
width: 100px; width: 135px;
z-index: 10; z-index: 10;
max-height: 50%; max-height: 50%;
overflow-y: auto; overflow-y: auto;
background-color: #ffffff;
border-radius: 4px;
&:hover { &:hover {
opacity: 1; opacity: 1;

@ -8,7 +8,6 @@ import { connect } from 'react-redux';
import { CombinedState, ContextMenuType } from 'reducers/interfaces'; import { CombinedState, ContextMenuType } from 'reducers/interfaces';
import CanvasContextMenuComponent from 'components/annotation-page/standard-workspace/canvas-context-menu'; import CanvasContextMenuComponent from 'components/annotation-page/standard-workspace/canvas-context-menu';
import CanvasPointContextMenuComponent from 'components/annotation-page/standard-workspace/canvas-point-context-menu';
interface StateToProps { interface StateToProps {
activatedStateID: number | null; activatedStateID: number | null;
@ -183,12 +182,16 @@ class CanvasContextMenuContainer extends React.PureComponent<Props, State> {
} = this.props; } = this.props;
return ( return (
<CanvasContextMenuComponent <>
left={left} { type === ContextMenuType.CANVAS_SHAPE && (
top={top} <CanvasContextMenuComponent
visible={visible} left={left}
activatedStateID={activatedStateID} top={top}
/> visible={visible}
activatedStateID={activatedStateID}
/>
)}
</>
); );
} }
} }

@ -0,0 +1,180 @@
// Copyright (C) 2020 Intel Corporation
//
// SPDX-License-Identifier: MIT
import React from 'react';
import { connect } from 'react-redux';
import { CombinedState, ContextMenuType } from 'reducers/interfaces';
import { updateAnnotationsAsync, updateCanvasContextMenu } from 'actions/annotation-actions';
import CanvasPointContextMenuComponent from 'components/annotation-page/standard-workspace/canvas-point-context-menu';
interface StateToProps {
activatedStateID: number | null;
activetedPointID: number | null | undefined;
states: any[];
visible: boolean;
top: number;
left: number;
type: ContextMenuType;
}
function mapStateToProps(state: CombinedState): StateToProps {
const {
annotation: {
annotations: {
states,
activatedStateID,
},
canvas: {
contextMenu: {
visible,
top,
left,
type,
pointID: activetedPointID,
},
},
},
} = state;
return {
activatedStateID,
activetedPointID,
states,
visible,
left,
top,
type,
};
}
interface DispatchToProps {
onUpdateAnnotations(states: any[]): void;
onCloseContextMenu(): void;
}
function mapDispatchToProps(dispatch: any): DispatchToProps {
return {
onUpdateAnnotations(states: any[]): void {
dispatch(updateAnnotationsAsync(states));
},
onCloseContextMenu(): void {
dispatch(updateCanvasContextMenu(false, 0, 0));
},
};
}
type Props = StateToProps & DispatchToProps;
interface State {
latestLeft: number;
latestTop: number;
left: number;
top: number;
}
class CanvasContextMenuContainer extends React.PureComponent<Props, State> {
public constructor(props: Props) {
super(props);
this.state = {
latestLeft: 0,
latestTop: 0,
left: 0,
top: 0,
};
}
static getDerivedStateFromProps(props: Props, state: State): State | null {
if (props.left === state.latestLeft
&& props.top === state.latestTop) {
return null;
}
return {
...state,
latestLeft: props.left,
latestTop: props.top,
top: props.top,
left: props.left,
};
}
public componentDidUpdate(): void {
const {
top,
left,
} = this.state;
const {
innerWidth,
innerHeight,
} = window;
const [element] = window.document.getElementsByClassName('cvat-canvas-point-context-menu');
if (element) {
const height = element.clientHeight;
const width = element.clientWidth;
if (top + height > innerHeight || left + width > innerWidth) {
this.setState({
top: top - Math.max(top + height - innerHeight, 0),
left: left - Math.max(left + width - innerWidth, 0),
});
}
}
}
private deletePoint(): void {
const {
activetedPointID,
activatedStateID,
states,
onUpdateAnnotations,
onCloseContextMenu,
} = this.props;
const [objectState] = states.filter((e) => (e.clientID === activatedStateID));
if (activetedPointID) {
objectState.points = objectState.points.slice(0, activetedPointID * 2)
.concat(objectState.points.slice(activetedPointID * 2 + 2));
onUpdateAnnotations([objectState]);
onCloseContextMenu();
}
}
public render(): JSX.Element {
const {
visible,
activatedStateID,
type,
} = this.props;
const {
top,
left,
} = this.state;
return (
<>
{type === ContextMenuType.CANVAS_SHAPE_POINT && (
<CanvasPointContextMenuComponent
left={left}
top={top}
visible={visible}
activatedStateID={activatedStateID}
onPointDelete={() => this.deletePoint()}
/>
)}
</>
);
}
}
export default connect(
mapStateToProps,
mapDispatchToProps,
)(CanvasContextMenuContainer);

@ -96,7 +96,8 @@ interface DispatchToProps {
onSplitAnnotations(sessionInstance: any, frame: number, state: any): void; onSplitAnnotations(sessionInstance: any, frame: number, state: any): void;
onActivateObject: (activatedStateID: number | null) => void; onActivateObject: (activatedStateID: number | null) => void;
onSelectObjects: (selectedStatesID: number[]) => void; onSelectObjects: (selectedStatesID: number[]) => void;
onUpdateContextMenu(visible: boolean, left: number, top: number, type: ContextMenuType): void; onUpdateContextMenu(visible: boolean, left: number, top: number, type: ContextMenuType,
pointID?: number): void;
onAddZLayer(): void; onAddZLayer(): void;
onSwitchZLayer(cur: number): void; onSwitchZLayer(cur: number): void;
onChangeBrightnessLevel(level: number): void; onChangeBrightnessLevel(level: number): void;
@ -257,13 +258,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onSelectObjects(selectedStatesID: number[]): void { onSelectObjects(selectedStatesID: number[]): void {
dispatch(selectObjects(selectedStatesID)); dispatch(selectObjects(selectedStatesID));
}, },
onUpdateContextMenu( onUpdateContextMenu(visible: boolean, left: number, top: number,
visible: boolean, type: ContextMenuType, pointID?: number): void {
left: number, dispatch(updateCanvasContextMenu(visible, left, top, type, pointID));
top: number,
type: ContextMenuType,
): void {
dispatch(updateCanvasContextMenu(visible, left, top, type));
}, },
onAddZLayer(): void { onAddZLayer(): void {
dispatch(addZLayer()); dispatch(addZLayer());

@ -26,6 +26,7 @@ const defaultState: AnnotationState = {
left: 0, left: 0,
top: 0, top: 0,
type: ContextMenuType.CANVAS_SHAPE, type: ContextMenuType.CANVAS_SHAPE,
pointID: null,
}, },
instance: new Canvas(), instance: new Canvas(),
ready: false, ready: false,
@ -934,6 +935,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
left, left,
top, top,
type, type,
pointID,
} = action.payload; } = action.payload;
return { return {
@ -946,6 +948,7 @@ export default (state = defaultState, action: AnyAction): AnnotationState => {
left, left,
top, top,
type, type,
pointID,
}, },
}, },
}; };

@ -303,6 +303,7 @@ export interface AnnotationState {
top: number; top: number;
left: number; left: number;
type: ContextMenuType; type: ContextMenuType;
pointID: number | null | undefined;
}; };
instance: Canvas; instance: Canvas;
ready: boolean; ready: boolean;

Loading…
Cancel
Save