You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

429 lines
12 KiB
TypeScript

import React from 'react';
import copy from 'copy-to-clipboard';
import { connect } from 'react-redux';
import {
ActiveControl,
CombinedState,
ColorBy,
} from 'reducers/interfaces';
import {
collapseObjectItems,
updateAnnotationsAsync,
changeFrameAsync,
removeObjectAsync,
copyShape as copyShapeAction,
activateObject as activateObjectAction,
propagateObject as propagateObjectAction,
} from 'actions/annotation-actions';
import ObjectStateItemComponent from 'components/annotation-page/standard-workspace/objects-side-bar/object-item';
interface OwnProps {
clientID: number;
}
interface StateToProps {
objectState: any;
collapsed: boolean;
labels: any[];
attributes: any[];
jobInstance: any;
frameNumber: number;
activated: boolean;
colorBy: ColorBy;
ready: boolean;
activeControl: ActiveControl;
}
interface DispatchToProps {
changeFrame(frame: number): void;
updateState(sessionInstance: any, frameNumber: number, objectState: any): void;
collapseOrExpand(objectStates: any[], collapsed: boolean): void;
activateObject: (activatedStateID: number | null) => void;
removeObject: (sessionInstance: any, objectState: any) => void;
copyShape: (objectState: any) => void;
propagateObject: (objectState: any) => void;
}
function mapStateToProps(state: CombinedState, own: OwnProps): StateToProps {
const {
annotation: {
annotations: {
states,
collapsed: statesCollapsed,
activatedStateID,
},
job: {
attributes: jobAttributes,
instance: jobInstance,
labels,
},
player: {
frame: {
number: frameNumber,
},
},
canvas: {
ready,
activeControl,
},
},
settings: {
shapes: {
colorBy,
},
},
} = state;
const index = states
.map((_state: any): number => _state.clientID)
.indexOf(own.clientID);
const collapsedState = typeof (statesCollapsed[own.clientID]) === 'undefined'
? true : statesCollapsed[own.clientID];
return {
objectState: states[index],
collapsed: collapsedState,
attributes: jobAttributes[states[index].label.id],
labels,
ready,
activeControl,
colorBy,
jobInstance,
frameNumber,
activated: activatedStateID === own.clientID,
};
}
function mapDispatchToProps(dispatch: any): DispatchToProps {
return {
changeFrame(frame: number): void {
dispatch(changeFrameAsync(frame));
},
updateState(sessionInstance: any, frameNumber: number, state: any): void {
dispatch(updateAnnotationsAsync(sessionInstance, frameNumber, [state]));
},
collapseOrExpand(objectStates: any[], collapsed: boolean): void {
dispatch(collapseObjectItems(objectStates, collapsed));
},
activateObject(activatedStateID: number | null): void {
dispatch(activateObjectAction(activatedStateID));
},
removeObject(sessionInstance: any, objectState: any): void {
dispatch(removeObjectAsync(sessionInstance, objectState, true));
},
copyShape(objectState: any): void {
dispatch(copyShapeAction(objectState));
},
propagateObject(objectState: any): void {
dispatch(propagateObjectAction(objectState));
},
};
}
type Props = StateToProps & DispatchToProps;
class ObjectItemContainer extends React.PureComponent<Props> {
private navigateFirstKeyframe = (): void => {
const {
objectState,
changeFrame,
frameNumber,
} = this.props;
const { first } = objectState.keyframes;
if (first !== frameNumber) {
changeFrame(first);
}
};
private navigatePrevKeyframe = (): void => {
const {
objectState,
changeFrame,
frameNumber,
} = this.props;
const { prev } = objectState.keyframes;
if (prev !== null && prev !== frameNumber) {
changeFrame(prev);
}
};
private navigateNextKeyframe = (): void => {
const {
objectState,
changeFrame,
frameNumber,
} = this.props;
const { next } = objectState.keyframes;
if (next !== null && next !== frameNumber) {
changeFrame(next);
}
};
private navigateLastKeyframe = (): void => {
const {
objectState,
changeFrame,
frameNumber,
} = this.props;
const { last } = objectState.keyframes;
if (last !== frameNumber) {
changeFrame(last);
}
};
private copy = (): void => {
const {
objectState,
copyShape,
} = this.props;
copyShape(objectState);
};
private propagate = (): void => {
const {
objectState,
propagateObject,
} = this.props;
propagateObject(objectState);
};
private remove = (): void => {
const {
objectState,
removeObject,
jobInstance,
} = this.props;
removeObject(jobInstance, objectState);
};
private createURL = (): void => {
const {
objectState,
frameNumber,
} = this.props;
const {
origin,
pathname,
} = window.location;
const search = `frame=${frameNumber}&object=${objectState.serverID}`;
const url = `${origin}${pathname}?${search}`;
copy(url);
};
private activate = (): void => {
const {
activateObject,
objectState,
ready,
activeControl,
} = this.props;
if (ready && activeControl === ActiveControl.CURSOR) {
activateObject(objectState.clientID);
}
};
private lock = (): void => {
const { objectState } = this.props;
objectState.lock = true;
this.commit();
};
private unlock = (): void => {
const { objectState } = this.props;
objectState.lock = false;
this.commit();
};
private show = (): void => {
const { objectState } = this.props;
objectState.hidden = false;
this.commit();
};
private hide = (): void => {
const { objectState } = this.props;
objectState.hidden = true;
this.commit();
};
private setOccluded = (): void => {
const { objectState } = this.props;
objectState.occluded = true;
this.commit();
};
private unsetOccluded = (): void => {
const { objectState } = this.props;
objectState.occluded = false;
this.commit();
};
private setOutside = (): void => {
const { objectState } = this.props;
objectState.outside = true;
this.commit();
};
private unsetOutside = (): void => {
const { objectState } = this.props;
objectState.outside = false;
this.commit();
};
private setKeyframe = (): void => {
const { objectState } = this.props;
objectState.keyframe = true;
this.commit();
};
private unsetKeyframe = (): void => {
const { objectState } = this.props;
objectState.keyframe = false;
this.commit();
};
private collapse = (): void => {
const {
collapseOrExpand,
objectState,
collapsed,
} = this.props;
collapseOrExpand([objectState], !collapsed);
};
private changeLabel = (labelID: string): void => {
const {
objectState,
labels,
} = this.props;
const [label] = labels.filter((_label: any): boolean => _label.id === +labelID);
objectState.label = label;
this.commit();
};
private changeAttribute = (id: number, value: string): void => {
const { objectState } = this.props;
const attr: Record<number, string> = {};
attr[id] = value;
objectState.attributes = attr;
this.commit();
};
private commit(): void {
const {
objectState,
updateState,
jobInstance,
frameNumber,
} = this.props;
updateState(jobInstance, frameNumber, objectState);
}
public render(): JSX.Element {
const {
objectState,
collapsed,
labels,
attributes,
frameNumber,
activated,
colorBy,
} = this.props;
const {
first,
prev,
next,
last,
} = objectState.keyframes || {
first: null, // shapes don't have keyframes, so we use null
prev: null,
next: null,
last: null,
};
let stateColor = '';
if (colorBy === ColorBy.INSTANCE) {
stateColor = objectState.color;
} else if (colorBy === ColorBy.GROUP) {
stateColor = objectState.group.color;
} else if (colorBy === ColorBy.LABEL) {
stateColor = objectState.label.color;
}
return (
<ObjectStateItemComponent
activated={activated}
objectType={objectState.objectType}
shapeType={objectState.shapeType}
clientID={objectState.clientID}
serverID={objectState.serverID}
occluded={objectState.occluded}
outside={objectState.outside}
locked={objectState.lock}
hidden={objectState.hidden}
keyframe={objectState.keyframe}
attrValues={{ ...objectState.attributes }}
labelID={objectState.label.id}
color={stateColor}
attributes={attributes}
labels={labels}
collapsed={collapsed}
navigateFirstKeyframe={
first >= frameNumber || first === null
? null : this.navigateFirstKeyframe
}
navigatePrevKeyframe={
prev === frameNumber || prev === null
? null : this.navigatePrevKeyframe
}
navigateNextKeyframe={
next === frameNumber || next === null
? null : this.navigateNextKeyframe
}
navigateLastKeyframe={
last <= frameNumber || last === null
? null : this.navigateLastKeyframe
}
activate={this.activate}
remove={this.remove}
copy={this.copy}
propagate={this.propagate}
createURL={this.createURL}
setOccluded={this.setOccluded}
unsetOccluded={this.unsetOccluded}
setOutside={this.setOutside}
unsetOutside={this.unsetOutside}
setKeyframe={this.setKeyframe}
unsetKeyframe={this.unsetKeyframe}
lock={this.lock}
unlock={this.unlock}
hide={this.hide}
show={this.show}
changeLabel={this.changeLabel}
changeAttribute={this.changeAttribute}
collapse={this.collapse}
/>
);
}
}
export default connect<StateToProps, DispatchToProps, OwnProps, CombinedState>(
mapStateToProps,
mapDispatchToProps,
)(ObjectItemContainer);