Added option to display shape text always

main
Boris Sekachev 6 years ago
parent 361679dc76
commit 7d986d599e

@ -50,6 +50,11 @@ Canvas itself handles:
ZOOM_CANVAS = 'zoom_canvas',
}
interface Configuration {
displayAllText?: boolean;
undefinedAttrValue?: string;
}
interface DrawData {
enabled: boolean;
shapeType?: string;
@ -83,7 +88,6 @@ Canvas itself handles:
}
interface Canvas {
mode(): Mode;
html(): HTMLDivElement;
setZLayer(zLayer: number | null): void;
setup(frameData: any, objectStates: any[]): void;
@ -103,7 +107,9 @@ Canvas itself handles:
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;
mode(): void;
cancel(): void;
configure(configuration: Configuration): void;
}
```
@ -189,4 +195,5 @@ Standard JS events are used.
| dragCanvas() | + | - | - | - | - | - | + | - |
| zoomCanvas() | + | - | - | - | - | - | - | + |
| cancel() | - | + | + | + | + | + | + | + |
| configure() | + | - | - | - | - | - | - | - |
| setZLayer() | + | + | + | + | + | + | + | + |

@ -11,6 +11,7 @@ import {
CanvasModel,
CanvasModelImpl,
RectDrawingMethod,
Configuration,
} from './canvasModel';
import {
@ -54,6 +55,7 @@ interface Canvas {
mode(): void;
cancel(): void;
configure(configuration: Configuration): void;
}
class CanvasImpl implements Canvas {
@ -141,11 +143,16 @@ class CanvasImpl implements Canvas {
public cancel(): void {
this.model.cancel();
}
public configure(configuration: Configuration): void {
this.model.configure(configuration);
}
}
export {
CanvasImpl as Canvas,
CanvasVersion,
Configuration,
RectDrawingMethod,
Mode as CanvasMode,
};

@ -36,7 +36,6 @@ export interface CanvasController {
enableDrag(x: number, y: number): void;
drag(x: number, y: number): void;
disableDrag(): void;
fit(): void;
}

@ -46,6 +46,11 @@ export enum RectDrawingMethod {
EXTREME_POINTS = 'By 4 points'
}
export interface Configuration {
displayAllText?: boolean;
undefinedAttrValue?: string;
}
export interface DrawData {
enabled: boolean;
shapeType?: string;
@ -100,6 +105,7 @@ export enum UpdateReasons {
CANCEL = 'cancel',
DRAG_CANVAS = 'drag_canvas',
ZOOM_CANVAS = 'ZOOM_CANVAS',
CONFIG_UPDATED = 'config_updated',
}
export enum Mode {
@ -126,6 +132,7 @@ export interface CanvasModel {
readonly mergeData: MergeData;
readonly splitData: SplitData;
readonly groupData: GroupData;
readonly configuration: Configuration;
readonly selected: any;
geometry: Geometry;
mode: Mode;
@ -151,6 +158,7 @@ export interface CanvasModel {
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;
configure(configuration: Configuration): void;
cancel(): void;
}
@ -159,6 +167,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
activeElement: ActiveElement;
angle: number;
canvasSize: Size;
configuration: Configuration;
image: Image | null;
imageID: number | null;
imageOffset: number;
@ -191,6 +200,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
height: 0,
width: 0,
},
configuration: {
displayAllText: false,
undefinedAttrValue: '',
},
image: null,
imageID: null,
imageOffset: 0,
@ -485,10 +498,30 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.data.selected = null;
}
public configure(configuration: Configuration): void {
if (this.data.mode !== Mode.IDLE) {
throw Error(`Canvas is busy. Action: ${this.data.mode}`);
}
if (typeof (configuration.displayAllText) !== 'undefined') {
this.data.configuration.displayAllText = configuration.displayAllText;
}
if (typeof (configuration.undefinedAttrValue) !== 'undefined') {
this.data.configuration.undefinedAttrValue = configuration.undefinedAttrValue;
}
this.notify(UpdateReasons.CONFIG_UPDATED);
}
public cancel(): void {
this.notify(UpdateReasons.CANCEL);
}
public get configuration(): Configuration {
return { ...this.data.configuration };
}
public get geometry(): Geometry {
return {
angle: this.data.angle,

@ -36,6 +36,7 @@ import {
GroupData,
Mode,
Size,
Configuration,
} from './canvasModel';
export interface CanvasView {
@ -65,6 +66,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
private groupHandler: GroupHandler;
private zoomHandler: ZoomHandler;
private activeElement: ActiveElement;
private configuration: Configuration;
private set mode(value: Mode) {
this.controller.mode = value;
@ -538,6 +540,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
clientID: null,
attributeID: null,
};
this.configuration = model.configuration;
this.mode = Mode.IDLE;
// Create HTML elements
@ -702,7 +705,11 @@ export class CanvasViewImpl implements CanvasView, Listener {
public notify(model: CanvasModel & Master, reason: UpdateReasons): void {
this.geometry = this.controller.geometry;
if (reason === UpdateReasons.IMAGE_CHANGED) {
if (reason === UpdateReasons.CONFIG_UPDATED) {
this.configuration = model.configuration;
this.setupObjects([]);
this.setupObjects(model.objects);
} else if (reason === UpdateReasons.IMAGE_CHANGED) {
const { image } = model;
if (!image) {
this.loadingAnimation.classList.remove('cvat_canvas_hidden');
@ -987,6 +994,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
private addObjects(states: any[], translate: (points: number[]) => number[]): void {
const { displayAllText } = this.configuration;
for (const state of states) {
if (state.objectType === 'tag') {
this.addTag(state);
@ -1030,6 +1039,14 @@ export class CanvasViewImpl implements CanvasView, Listener {
},
}));
});
if (displayAllText) {
this.svgTexts[state.clientID] = this.addText(state);
this.updateTextPosition(
this.svgTexts[state.clientID],
this.svgShapes[state.clientID],
);
}
}
this.saveState(state);
@ -1078,6 +1095,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
private deactivateShape(): void {
if (this.activeElement.clientID !== null) {
const { displayAllText } = this.configuration;
const { clientID } = this.activeElement;
const drawnState = this.drawnStates[clientID];
const shape = this.svgShapes[clientID];
@ -1101,7 +1119,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
// TODO: Hide text only if it is hidden by settings
const text = this.svgTexts[clientID];
if (text) {
if (text && !displayAllText) {
text.remove();
delete this.svgTexts[clientID];
}
@ -1347,6 +1365,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
private addText(state: any): SVG.Text {
const { undefinedAttrValue } = this.configuration;
const { label, clientID, attributes } = state;
const attrNames = label.attributes.reduce((acc: any, val: any): void => {
acc[val.id] = val.name;
@ -1356,7 +1375,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
return this.adoptedText.text((block): void => {
block.tspan(`${label.name} ${clientID}`).style('text-transform', 'uppercase');
for (const attrID of Object.keys(attributes)) {
const value = attributes[attrID] === consts.UNDEFINED_ATTRIBUTE_VALUE
const value = attributes[attrID] === undefinedAttrValue
? '' : attributes[attrID];
block.tspan(`${attrNames[attrID]}: ${value}`).attr({
attrID,

@ -28,6 +28,7 @@ export enum SettingsActionTypes {
CHANGE_AUTO_SAVE_INTERVAL = 'CHANGE_AUTO_SAVE_INTERVAL',
CHANGE_AAM_ZOOM_MARGIN = 'CHANGE_AAM_ZOOM_MARGIN',
SWITCH_SHOWNIG_INTERPOLATED_TRACKS = 'SWITCH_SHOWNIG_INTERPOLATED_TRACKS',
SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS = 'SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS',
}
export function changeShapesOpacity(opacity: number): AnyAction {
@ -200,3 +201,12 @@ export function switchShowingInterpolatedTracks(showAllInterpolationTracks: bool
},
};
}
export function switchShowingObjectsTextAlways(showObjectsTextAlways: boolean): AnyAction {
return {
type: SettingsActionTypes.SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS,
payload: {
showObjectsTextAlways,
},
};
}

@ -21,6 +21,7 @@ import {
import { LogType } from 'cvat-logger';
import { Canvas } from 'cvat-canvas';
import getCore from 'cvat-core';
import consts from 'consts';
const cvat = getCore();
@ -58,6 +59,7 @@ interface Props {
contextVisible: boolean;
contextType: ContextMenuType;
aamZoomMargin: number;
showObjectsTextAlways: boolean;
workspace: Workspace;
keyMap: Record<string, ExtendedKeyMapOptions>;
onSetupCanvas: () => void;
@ -91,6 +93,7 @@ interface Props {
export default class CanvasWrapperComponent extends React.PureComponent<Props> {
public componentDidMount(): void {
const {
showObjectsTextAlways,
canvasInstance,
curZLayer,
} = this.props;
@ -101,7 +104,12 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
.getElementsByClassName('cvat-canvas-container');
wrapper.appendChild(canvasInstance.html());
canvasInstance.configure({
undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE,
displayAllText: showObjectsTextAlways,
});
canvasInstance.setZLayer(curZLayer);
this.initialSetup();
this.updateCanvas();
}
@ -128,8 +136,16 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
saturationLevel,
workspace,
frameFetching,
showObjectsTextAlways,
} = this.props;
if (prevProps.showObjectsTextAlways !== showObjectsTextAlways) {
canvasInstance.configure({
undefinedAttrValue: consts.UNDEFINED_ATTRIBUTE_VALUE,
displayAllText: showObjectsTextAlways,
});
}
if (prevProps.sidebarCollapsed !== sidebarCollapsed) {
const [sidebar] = window.document.getElementsByClassName('cvat-objects-sidebar');
if (sidebar) {

@ -20,6 +20,8 @@
.cvat-player-settings-grid,
.cvat-workspace-settings-auto-save,
.cvat-workspace-settings-show-text-always,
.cvat-workspace-settings-show-text-always-checkbox,
.cvat-workspace-settings-show-interpolated-checkbox {
margin-bottom: 10px;
}
@ -31,6 +33,7 @@
.cvat-player-settings-speed,
.cvat-player-settings-reset-zoom,
.cvat-player-settings-rotate-all,
.cvat-workspace-settings-show-text-always,
.cvat-workspace-settings-show-interpolated,
.cvat-workspace-settings-aam-zoom-margin,
.cvat-workspace-settings-auto-save-interval {

@ -16,10 +16,12 @@ interface Props {
autoSaveInterval: number;
aamZoomMargin: number;
showAllInterpolationTracks: boolean;
showObjectsTextAlways: boolean;
onSwitchAutoSave(enabled: boolean): void;
onChangeAutoSaveInterval(interval: number): void;
onChangeAAMZoomMargin(margin: number): void;
onSwitchShowingInterpolatedTracks(enabled: boolean): void;
onSwitchShowingObjectsTextAlways(enabled: boolean): void;
}
export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
@ -28,10 +30,12 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
autoSaveInterval,
aamZoomMargin,
showAllInterpolationTracks,
showObjectsTextAlways,
onSwitchAutoSave,
onChangeAutoSaveInterval,
onChangeAAMZoomMargin,
onSwitchShowingInterpolatedTracks,
onSwitchShowingObjectsTextAlways,
} = props;
const minAutoSaveInterval = 5;
@ -93,6 +97,22 @@ export default function WorkspaceSettingsComponent(props: Props): JSX.Element {
<Text type='secondary'> Show hidden interpolated objects in the side panel </Text>
</Col>
</Row>
<Row className='cvat-workspace-settings-show-text-always'>
<Col className='cvat-workspace-settings-show-text-always-checkbox'>
<Checkbox
className='cvat-text-color'
checked={showObjectsTextAlways}
onChange={(event: CheckboxChangeEvent): void => {
onSwitchShowingObjectsTextAlways(event.target.checked);
}}
>
Always show object details
</Checkbox>
</Col>
<Col>
<Text type='secondary'> Show text for an object on the canvas not only when the object is activated </Text>
</Col>
</Row>
<Row className='cvat-workspace-settings-aam-zoom-margin'>
<Col>
<Text className='cvat-text-color'> Attribute annotation mode (AAM) zoom margin </Text>

@ -73,6 +73,7 @@ interface StateToProps {
saturationLevel: number;
resetZoom: boolean;
aamZoomMargin: number;
showObjectsTextAlways: boolean;
workspace: Workspace;
minZLayer: number;
maxZLayer: number;
@ -163,6 +164,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
},
workspace: {
aamZoomMargin,
showObjectsTextAlways,
},
shapes: {
opacity,
@ -203,6 +205,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
saturationLevel,
resetZoom,
aamZoomMargin,
showObjectsTextAlways,
curZLayer,
minZLayer,
maxZLayer,

@ -10,11 +10,10 @@ import {
changeAutoSaveInterval,
changeAAMZoomMargin,
switchShowingInterpolatedTracks,
switchShowingObjectsTextAlways,
} from 'actions/settings-actions';
import {
CombinedState,
} from 'reducers/interfaces';
import { CombinedState } from 'reducers/interfaces';
import WorkspaceSettingsComponent from 'components/settings-page/workspace-settings';
@ -23,6 +22,7 @@ interface StateToProps {
autoSaveInterval: number;
aamZoomMargin: number;
showAllInterpolationTracks: boolean;
showObjectsTextAlways: boolean;
}
interface DispatchToProps {
@ -30,6 +30,7 @@ interface DispatchToProps {
onChangeAutoSaveInterval(interval: number): void;
onChangeAAMZoomMargin(margin: number): void;
onSwitchShowingInterpolatedTracks(enabled: boolean): void;
onSwitchShowingObjectsTextAlways(enabled: boolean): void;
}
function mapStateToProps(state: CombinedState): StateToProps {
@ -39,6 +40,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
autoSaveInterval,
aamZoomMargin,
showAllInterpolationTracks,
showObjectsTextAlways,
} = workspace;
return {
@ -46,6 +48,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
autoSaveInterval,
aamZoomMargin,
showAllInterpolationTracks,
showObjectsTextAlways,
};
}
@ -63,6 +66,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
onSwitchShowingInterpolatedTracks(enabled: boolean): void {
dispatch(switchShowingInterpolatedTracks(enabled));
},
onSwitchShowingObjectsTextAlways(enabled: boolean): void {
dispatch(switchShowingObjectsTextAlways(enabled));
},
};
}

@ -426,6 +426,7 @@ export interface WorkspaceSettingsState {
autoSave: boolean;
autoSaveInterval: number; // in ms
aamZoomMargin: number;
showObjectsTextAlways: boolean;
showAllInterpolationTracks: boolean;
}

@ -27,6 +27,7 @@ const defaultState: SettingsState = {
autoSave: false,
autoSaveInterval: 15 * 60 * 1000,
aamZoomMargin: 100,
showObjectsTextAlways: false,
showAllInterpolationTracks: false,
},
player: {
@ -217,6 +218,15 @@ export default (state = defaultState, action: AnyAction): SettingsState => {
},
};
}
case SettingsActionTypes.SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS: {
return {
...state,
workspace: {
...state.workspace,
showObjectsTextAlways: action.payload.showObjectsTextAlways,
},
};
}
case AnnotationActionTypes.GET_JOB_SUCCESS: {
const { job } = action.payload;

Loading…
Cancel
Save