React UI: Pinned option was added (#1202)

main
Boris Sekachev 6 years ago committed by GitHub
parent a058765d29
commit 97195238b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -850,6 +850,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
points: [...state.points],
attributes: { ...state.attributes },
zOrder: state.zOrder,
pinned: state.pinned,
};
}
@ -885,6 +886,12 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
}
if (drawnState.pinned !== state.pinned && this.activeElement.clientID !== null) {
const activeElement = { ...this.activeElement };
this.deactivate();
this.activate(activeElement);
}
if (state.points
.some((p: number, id: number): boolean => p !== drawnState.points[id])
) {
@ -1016,9 +1023,11 @@ export class CanvasViewImpl implements CanvasView, Listener {
shape.removeClass('cvat_canvas_shape_activated');
(shape as any).off('dragstart');
(shape as any).off('dragend');
(shape as any).draggable(false);
if (!drawnState.pinned) {
(shape as any).off('dragstart');
(shape as any).off('dragend');
(shape as any).draggable(false);
}
if (drawnState.shapeType !== 'points') {
this.selectize(false, shape);
@ -1098,37 +1107,38 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.content.append(shape.node);
}
(shape as any).draggable().on('dragstart', (): void => {
this.mode = Mode.DRAG;
if (text) {
text.addClass('cvat_canvas_hidden');
}
}).on('dragend', (e: CustomEvent): void => {
if (text) {
text.removeClass('cvat_canvas_hidden');
this.updateTextPosition(
text,
shape,
);
}
this.mode = Mode.IDLE;
const p1 = e.detail.handler.startPoints.point;
const p2 = e.detail.p;
const delta = 1;
const { offset } = this.controller.geometry;
if (Math.sqrt(((p1.x - p2.x) ** 2) + ((p1.y - p2.y) ** 2)) >= delta) {
const points = pointsToArray(
shape.attr('points') || `${shape.attr('x')},${shape.attr('y')} `
+ `${shape.attr('x') + shape.attr('width')},`
+ `${shape.attr('y') + shape.attr('height')}`,
).map((x: number): number => x - offset);
if (!state.pinned) {
(shape as any).draggable().on('dragstart', (): void => {
this.mode = Mode.DRAG;
if (text) {
text.addClass('cvat_canvas_hidden');
}
}).on('dragend', (e: CustomEvent): void => {
if (text) {
text.removeClass('cvat_canvas_hidden');
this.updateTextPosition(
text,
shape,
);
}
this.drawnStates[state.clientID].points = points;
this.onEditDone(state, points);
}
});
this.mode = Mode.IDLE;
const p1 = e.detail.handler.startPoints.point;
const p2 = e.detail.p;
const delta = 1;
const { offset } = this.controller.geometry;
if (Math.sqrt(((p1.x - p2.x) ** 2) + ((p1.y - p2.y) ** 2)) >= delta) {
const points = pointsToArray(
shape.attr('points') || `${shape.attr('x')},${shape.attr('y')} `
+ `${shape.attr('x') + shape.attr('width')},`
+ `${shape.attr('y') + shape.attr('height')}`,
).map((x: number): number => x - offset);
this.drawnStates[state.clientID].points = points;
this.onEditDone(state, points);
}
});
}
if (state.shapeType !== 'points') {
this.selectize(true, shape);

@ -320,6 +320,10 @@
checkObjectType('lock', data.lock, 'boolean', null);
}
if (updated.pinned) {
checkObjectType('pinned', data.pinned, 'boolean', null);
}
if (updated.color) {
checkObjectType('color', data.color, 'string', null);
if (!/^#[0-9A-F]{6}$/i.test(data.color)) {
@ -379,9 +383,23 @@
super(data, clientID, color, injection);
this.frameMeta = injection.frameMeta;
this.hidden = false;
this.pinned = true;
this.shapeType = null;
}
_savePinned(pinned) {
const undoPinned = this.pinned;
const redoPinned = pinned;
this.history.do(HistoryActions.CHANGED_PINNED, () => {
this.pinned = undoPinned;
}, () => {
this.pinned = redoPinned;
}, [this.clientID]);
this.pinned = pinned;
}
save() {
throw new ScriptingError(
'Is not implemented',
@ -455,6 +473,7 @@
color: this.color,
hidden: this.hidden,
updated: this.updated,
pinned: this.pinned,
frame,
};
}
@ -537,6 +556,10 @@
this._saveLock(data.lock);
}
if (updated.pinned) {
this._savePinned(data.pinned);
}
if (updated.color) {
this._saveColor(data.color);
}
@ -644,6 +667,7 @@
hidden: this.hidden,
updated: this.updated,
label: this.label,
pinned: this.pinned,
keyframes: {
prev,
next,
@ -984,6 +1008,10 @@
this._saveLock(data.lock);
}
if (updated.pinned) {
this._savePinned(data.pinned);
}
if (updated.color) {
this._saveColor(data.color);
}
@ -1148,6 +1176,7 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = ObjectShape.RECTANGLE;
this.pinned = false;
checkNumberOfPoints(this.shapeType, this.points);
}
@ -1315,6 +1344,7 @@
constructor(data, clientID, color, injection) {
super(data, clientID, color, injection);
this.shapeType = ObjectShape.RECTANGLE;
this.pinned = false;
for (const shape of Object.values(this.shapes)) {
checkNumberOfPoints(this.shapeType, shape.points);
}

@ -196,6 +196,7 @@
CHANGED_ZORDER: 'Changed z-order',
CHANGED_KEYFRAME: 'Changed keyframe',
CHANGED_LOCK: 'Changed lock',
CHANGED_PINNED: 'Changed pinned',
CHANGED_COLOR: 'Changed color',
CHANGED_HIDDEN: 'Changed hidden',
MERGED_OBJECTS: 'Merged objects',

@ -19,10 +19,10 @@
/**
* @param {Object} serialized - is an dictionary which contains
* initial information about an ObjectState;
* Necessary fields: objectType, shapeType, frame, updated
* Optional fields: points, group, zOrder, outside, occluded, hidden,
* attributes, lock, label, mode, color, keyframe, keyframes, clientID, serverID
* These fields can be set later via setters
* </br> Necessary fields: objectType, shapeType, frame, updated, group
* </br> Optional fields: keyframes, clientID, serverID
* </br> Optional fields which can be set later: points, zOrder, outside,
* occluded, hidden, attributes, lock, label, color, keyframe
*/
constructor(serialized) {
const data = {
@ -34,12 +34,13 @@
occluded: null,
keyframe: null,
zOrder: undefined,
zOrder: null,
lock: null,
color: null,
hidden: null,
pinned: null,
keyframes: null,
group: serialized.group,
keyframes: serialized.keyframes,
updated: serialized.updated,
clientID: serialized.clientID,
@ -63,6 +64,7 @@
this.keyframe = false;
this.zOrder = false;
this.pinned = false;
this.lock = false;
this.color = false;
this.hidden = false;
@ -202,7 +204,7 @@
zOrder: {
/**
* @name zOrder
* @type {integer}
* @type {integer | null}
* @memberof module:API.cvat.classes.ObjectState
* @instance
*/
@ -242,15 +244,16 @@
/**
* Object of keyframes { first, prev, next, last }
* @name keyframes
* @type {object}
* @type {object | null}
* @memberof module:API.cvat.classes.ObjectState
* @readonly
* @instance
*/
get: () => {
if (data.keyframes) {
if (typeof (data.keyframes) === 'object') {
return { ...data.keyframes };
}
return null;
},
},
@ -280,6 +283,25 @@
data.lock = lock;
},
},
pinned: {
/**
* @name pinned
* @type {boolean | null}
* @memberof module:API.cvat.classes.ObjectState
* @instance
*/
get: () => {
if (typeof (data.pinned) === 'boolean') {
return data.pinned;
}
return null;
},
set: (pinned) => {
data.updateFlags.pinned = true;
data.pinned = pinned;
},
},
updated: {
/**
* Timestamp of the latest updated of the object
@ -320,19 +342,33 @@
}));
this.label = serialized.label;
this.zOrder = serialized.zOrder;
this.outside = serialized.outside;
this.keyframe = serialized.keyframe;
this.occluded = serialized.occluded;
this.color = serialized.color;
this.lock = serialized.lock;
this.hidden = serialized.hidden;
// It can be undefined in a constructor and it can be defined later
if (typeof (serialized.points) !== 'undefined') {
if (typeof (serialized.zOrder) === 'number') {
this.zOrder = serialized.zOrder;
}
if (typeof (serialized.occluded) === 'boolean') {
this.occluded = serialized.occluded;
}
if (typeof (serialized.outside) === 'boolean') {
this.outside = serialized.outside;
}
if (typeof (serialized.keyframe) === 'boolean') {
this.keyframe = serialized.keyframe;
}
if (typeof (serialized.pinned) === 'boolean') {
this.pinned = serialized.pinned;
}
if (typeof (serialized.hidden) === 'boolean') {
this.hidden = serialized.hidden;
}
if (typeof (serialized.color) === 'string') {
this.color = serialized.color;
}
if (Array.isArray(serialized.points)) {
this.points = serialized.points;
}
if (typeof (serialized.attributes) !== 'undefined') {
if (typeof (serialized.attributes) === 'object') {
this.attributes = serialized.attributes;
}

@ -178,9 +178,11 @@ const ItemTop = React.memo(ItemTopComponent);
interface ItemButtonsComponentProps {
objectType: ObjectType;
shapeType: ShapeType;
occluded: boolean;
outside: boolean | undefined;
locked: boolean;
pinned: boolean;
hidden: boolean;
keyframe: boolean | undefined;
@ -197,6 +199,8 @@ interface ItemButtonsComponentProps {
unsetKeyframe(): void;
lock(): void;
unlock(): void;
pin(): void;
unpin(): void;
hide(): void;
show(): void;
}
@ -204,9 +208,11 @@ interface ItemButtonsComponentProps {
function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
const {
objectType,
shapeType,
occluded,
outside,
locked,
pinned,
hidden,
keyframe,
@ -223,6 +229,8 @@ function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
unsetKeyframe,
lock,
unlock,
pin,
unpin,
hide,
show,
} = props;
@ -232,53 +240,62 @@ function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
<Row type='flex' align='middle' justify='space-around'>
<Col span={20} style={{ textAlign: 'center' }}>
<Row type='flex' justify='space-around'>
<Col span={6}>
<Col>
{ navigateFirstKeyframe
? <Icon component={FirstIcon} onClick={navigateFirstKeyframe} />
: <Icon component={FirstIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
</Col>
<Col span={6}>
<Col>
{ navigatePrevKeyframe
? <Icon component={PreviousIcon} onClick={navigatePrevKeyframe} />
: <Icon component={PreviousIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
</Col>
<Col span={6}>
<Col>
{ navigateNextKeyframe
? <Icon component={NextIcon} onClick={navigateNextKeyframe} />
: <Icon component={NextIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
</Col>
<Col span={6}>
<Col>
{ navigateLastKeyframe
? <Icon component={LastIcon} onClick={navigateLastKeyframe} />
: <Icon component={LastIcon} style={{ opacity: 0.5, pointerEvents: 'none' }} />}
</Col>
</Row>
<Row type='flex' justify='space-around'>
<Col span={4}>
<Col>
{ outside
? <Icon component={ObjectOutsideIcon} onClick={unsetOutside} />
: <Icon type='select' onClick={setOutside} />}
</Col>
<Col span={4}>
<Col>
{ locked
? <Icon type='lock' onClick={unlock} />
: <Icon type='unlock' onClick={lock} />}
</Col>
<Col span={4}>
<Col>
{ occluded
? <Icon type='team' onClick={unsetOccluded} />
: <Icon type='user' onClick={setOccluded} />}
</Col>
<Col span={4}>
<Col>
{ hidden
? <Icon type='eye-invisible' onClick={show} />
: <Icon type='eye' onClick={hide} />}
</Col>
<Col span={4}>
<Col>
{ keyframe
? <Icon type='star' theme='filled' onClick={unsetKeyframe} />
: <Icon type='star' onClick={setKeyframe} />}
</Col>
{
shapeType !== ShapeType.POINTS && (
<Col>
{ pinned
? <Icon type='pushpin' theme='filled' onClick={unpin} />
: <Icon type='pushpin' onClick={pin} />}
</Col>
)
}
</Row>
</Col>
</Row>
@ -289,21 +306,30 @@ function ItemButtonsComponent(props: ItemButtonsComponentProps): JSX.Element {
<Row type='flex' align='middle' justify='space-around'>
<Col span={20} style={{ textAlign: 'center' }}>
<Row type='flex' justify='space-around'>
<Col span={8}>
<Col>
{ locked
? <Icon type='lock' onClick={unlock} />
: <Icon type='unlock' onClick={lock} />}
</Col>
<Col span={8}>
<Col>
{ occluded
? <Icon type='team' onClick={unsetOccluded} />
: <Icon type='user' onClick={setOccluded} />}
</Col>
<Col span={8}>
<Col>
{ hidden
? <Icon type='eye-invisible' onClick={show} />
: <Icon type='eye' onClick={hide} />}
</Col>
{
shapeType !== ShapeType.POINTS && (
<Col>
{ pinned
? <Icon type='pushpin' theme='filled' onClick={unpin} />
: <Icon type='pushpin' onClick={pin} />}
</Col>
)
}
</Row>
</Col>
</Row>
@ -550,6 +576,7 @@ interface Props {
occluded: boolean;
outside: boolean | undefined;
locked: boolean;
pinned: boolean;
hidden: boolean;
keyframe: boolean | undefined;
attrValues: Record<number, string>;
@ -579,6 +606,8 @@ interface Props {
unsetKeyframe(): void;
lock(): void;
unlock(): void;
pin(): void;
unpin(): void;
hide(): void;
show(): void;
changeLabel(labelID: string): void;
@ -590,6 +619,7 @@ interface Props {
function objectItemsAreEqual(prevProps: Props, nextProps: Props): boolean {
return nextProps.activated === prevProps.activated
&& nextProps.locked === prevProps.locked
&& nextProps.pinned === prevProps.pinned
&& nextProps.occluded === prevProps.occluded
&& nextProps.outside === prevProps.outside
&& nextProps.hidden === prevProps.hidden
@ -620,6 +650,7 @@ function ObjectItemComponent(props: Props): JSX.Element {
occluded,
outside,
locked,
pinned,
hidden,
keyframe,
attrValues,
@ -650,6 +681,8 @@ function ObjectItemComponent(props: Props): JSX.Element {
unsetKeyframe,
lock,
unlock,
pin,
unpin,
hide,
show,
changeLabel,
@ -704,10 +737,12 @@ function ObjectItemComponent(props: Props): JSX.Element {
toForeground={toForeground}
/>
<ItemButtons
shapeType={shapeType}
objectType={objectType}
occluded={occluded}
outside={outside}
locked={locked}
pinned={pinned}
hidden={hidden}
keyframe={keyframe}
navigateFirstKeyframe={navigateFirstKeyframe}
@ -722,6 +757,8 @@ function ObjectItemComponent(props: Props): JSX.Element {
unsetKeyframe={unsetKeyframe}
lock={lock}
unlock={unlock}
pin={pin}
unpin={unpin}
hide={hide}
show={show}
/>

@ -300,6 +300,18 @@ class ObjectItemContainer extends React.PureComponent<Props> {
this.commit();
};
private pin = (): void => {
const { objectState } = this.props;
objectState.pinned = true;
this.commit();
};
private unpin = (): void => {
const { objectState } = this.props;
objectState.pinned = false;
this.commit();
};
private show = (): void => {
const { objectState } = this.props;
objectState.hidden = false;
@ -451,6 +463,7 @@ class ObjectItemContainer extends React.PureComponent<Props> {
occluded={objectState.occluded}
outside={objectState.outside}
locked={objectState.lock}
pinned={objectState.pinned}
hidden={objectState.hidden}
keyframe={objectState.keyframe}
attrValues={{ ...objectState.attributes }}
@ -491,6 +504,8 @@ class ObjectItemContainer extends React.PureComponent<Props> {
unsetKeyframe={this.unsetKeyframe}
lock={this.lock}
unlock={this.unlock}
pin={this.pin}
unpin={this.unpin}
hide={this.hide}
show={this.show}
changeColor={this.changeColor}

Loading…
Cancel
Save