Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React UI: Added option to display shape text always #1349

Merged
merged 7 commits into from
Apr 3, 2020
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Special behaviour for attribute value ``__undefined__`` (invisibility, no shortcuts to be set in AAM)
- Dialog window with some helpful information about using filters
- Ability to display a bitmap in the new UI
- Added option to display shape text always

### Changed
-
Expand Down
9 changes: 8 additions & 1 deletion cvat-canvas/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ Canvas itself handles:
ZOOM_CANVAS = 'zoom_canvas',
}

interface Configuration {
displayAllText?: boolean;
undefinedAttrValue?: string;
}

interface DrawData {
enabled: boolean;
shapeType?: string;
Expand Down Expand Up @@ -83,7 +88,6 @@ Canvas itself handles:
}

interface Canvas {
mode(): Mode;
html(): HTMLDivElement;
setZLayer(zLayer: number | null): void;
setup(frameData: any, objectStates: any[]): void;
Expand All @@ -104,7 +108,9 @@ Canvas itself handles:
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;

mode(): void;
ActiveChooN marked this conversation as resolved.
Show resolved Hide resolved
cancel(): void;
configure(configuration: Configuration): void;
}
```

Expand Down Expand Up @@ -190,5 +196,6 @@ Standard JS events are used.
| dragCanvas() | + | - | - | - | - | - | + | - |
| zoomCanvas() | + | - | - | - | - | - | - | + |
| cancel() | - | + | + | + | + | + | + | + |
| configure() | + | - | - | - | - | - | - | - |
| bitmap() | + | + | + | + | + | + | + | + |
| setZLayer() | + | + | + | + | + | + | + | + |
7 changes: 7 additions & 0 deletions cvat-canvas/src/typescript/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
CanvasModel,
CanvasModelImpl,
RectDrawingMethod,
Configuration,
} from './canvasModel';

import {
Expand Down Expand Up @@ -55,6 +56,7 @@ interface Canvas {

mode(): void;
cancel(): void;
configure(configuration: Configuration): void;
}

class CanvasImpl implements Canvas {
Expand Down Expand Up @@ -146,11 +148,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,
};
1 change: 0 additions & 1 deletion cvat-canvas/src/typescript/canvasController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export interface CanvasController {
enableDrag(x: number, y: number): void;
drag(x: number, y: number): void;
disableDrag(): void;

fit(): void;
}

Expand Down
33 changes: 33 additions & 0 deletions cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -101,6 +106,7 @@ export enum UpdateReasons {
BITMAP = 'bitmap',
DRAG_CANVAS = 'drag_canvas',
ZOOM_CANVAS = 'zoom_canvas',
CONFIG_UPDATED = 'config_updated',
}

export enum Mode {
Expand Down Expand Up @@ -128,6 +134,7 @@ export interface CanvasModel {
readonly mergeData: MergeData;
readonly splitData: SplitData;
readonly groupData: GroupData;
readonly configuration: Configuration;
readonly selected: any;
geometry: Geometry;
mode: Mode;
Expand All @@ -154,6 +161,7 @@ export interface CanvasModel {
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;

configure(configuration: Configuration): void;
cancel(): void;
}

Expand All @@ -162,6 +170,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
activeElement: ActiveElement;
angle: number;
canvasSize: Size;
configuration: Configuration;
imageBitmap: boolean;
image: Image | null;
imageID: number | null;
Expand Down Expand Up @@ -195,6 +204,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
height: 0,
width: 0,
},
configuration: {
displayAllText: false,
undefinedAttrValue: '',
},
imageBitmap: false,
image: null,
imageID: null,
Expand Down Expand Up @@ -495,10 +508,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,
Expand Down
71 changes: 51 additions & 20 deletions cvat-canvas/src/typescript/canvasView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
GroupData,
Mode,
Size,
Configuration,
} from './canvasModel';

export interface CanvasView {
Expand Down Expand Up @@ -66,6 +67,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;
Expand Down Expand Up @@ -539,6 +541,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
clientID: null,
attributeID: null,
};
this.configuration = model.configuration;
this.mode = Mode.IDLE;

// Create HTML elements
Expand Down Expand Up @@ -707,8 +710,11 @@ export class CanvasViewImpl implements CanvasView, Listener {

public notify(model: CanvasModel & Master, reason: UpdateReasons): void {
this.geometry = this.controller.geometry;

if (reason === UpdateReasons.BITMAP) {
if (reason === UpdateReasons.CONFIG_UPDATED) {
this.configuration = model.configuration;
this.setupObjects([]);
this.setupObjects(model.objects);
} else if (reason === UpdateReasons.BITMAP) {
const { imageBitmap } = model;
if (imageBitmap) {
this.bitmap.style.display = '';
Expand Down Expand Up @@ -961,31 +967,44 @@ export class CanvasViewImpl implements CanvasView, Listener {
for (const state of states) {
const { clientID } = state;
const drawnState = this.drawnStates[clientID];
const shape = this.svgShapes[state.clientID];
const text = this.svgTexts[state.clientID];

if (drawnState.hidden !== state.hidden || drawnState.outside !== state.outside) {
const none = state.hidden || state.outside;
if (state.shapeType === 'points') {
this.svgShapes[clientID].remember('_selectHandler').nested
.style('display', none ? 'none' : '');
const isInvisible = state.hidden || state.outside;
if (isInvisible) {
(state.shapeType === 'points' ? shape.remember('_selectHandler').nested : shape)
.style('display', 'none');
if (text) {
text.addClass('cvat_canvas_hidden');
}
} else {
this.svgShapes[clientID].style('display', none ? 'none' : '');
(state.shapeType === 'points' ? shape.remember('_selectHandler').nested : shape)
.style('display', '');
if (text) {
text.removeClass('cvat_canvas_hidden');
this.updateTextPosition(
text,
shape,
);
}
}
}

if (drawnState.zOrder !== state.zOrder) {
if (state.shapeType === 'points') {
this.svgShapes[clientID].remember('_selectHandler').nested
shape.remember('_selectHandler').nested
.attr('data-z-order', state.zOrder);
} else {
this.svgShapes[clientID].attr('data-z-order', state.zOrder);
shape.attr('data-z-order', state.zOrder);
}
}

if (drawnState.occluded !== state.occluded) {
if (state.occluded) {
this.svgShapes[clientID].addClass('cvat_canvas_shape_occluded');
shape.addClass('cvat_canvas_shape_occluded');
} else {
this.svgShapes[clientID].removeClass('cvat_canvas_shape_occluded');
shape.removeClass('cvat_canvas_shape_occluded');
}
}

Expand All @@ -1003,7 +1022,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
if (state.shapeType === 'rectangle') {
const [xtl, ytl, xbr, ybr] = translatedPoints;

this.svgShapes[clientID].attr({
shape.attr({
x: xtl,
y: ytl,
width: xbr - xtl,
Expand All @@ -1019,21 +1038,20 @@ export class CanvasViewImpl implements CanvasView, Listener {
return `${acc}${val},`;
}, '',
);
(this.svgShapes[clientID] as any).clear();
this.svgShapes[clientID].attr('points', stringified);
(shape as any).clear();
shape.attr('points', stringified);

if (state.shapeType === 'points') {
this.selectize(false, this.svgShapes[clientID]);
this.setupPoints(this.svgShapes[clientID] as SVG.PolyLine, state);
this.selectize(false, shape);
this.setupPoints(shape as SVG.PolyLine, state);
}
}
}

for (const attrID of Object.keys(state.attributes)) {
if (state.attributes[attrID] !== drawnState.attributes[attrID]) {
const text = this.svgTexts[state.clientID];
if (text) {
const [span] = this.svgTexts[state.clientID].node
const [span] = text.node
.querySelectorAll(`[attrID="${attrID}"]`) as any as SVGTSpanElement[];
if (span && span.textContent) {
const prefix = span.textContent.split(':').slice(0, -1).join(':');
Expand All @@ -1048,6 +1066,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);
Expand Down Expand Up @@ -1091,6 +1111,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);
Expand Down Expand Up @@ -1139,6 +1167,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];
Expand All @@ -1162,7 +1191,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];
}
Expand Down Expand Up @@ -1370,6 +1399,7 @@ export class CanvasViewImpl implements CanvasView, Listener {

// Update text position after corresponding box has been moved, resized, etc.
private updateTextPosition(text: SVG.Text, shape: SVG.Shape): void {
if (text.node.style.display === 'none') return; // wrong transformation matrix
let box = (shape.node as any).getBBox();

// Translate the whole box to the client coordinate system
Expand Down Expand Up @@ -1408,6 +1438,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;
Expand All @@ -1417,7 +1448,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,
Expand Down
10 changes: 10 additions & 0 deletions cvat-ui/src/actions/settings-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,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 {
Expand Down Expand Up @@ -210,3 +211,12 @@ export function switchShowingInterpolatedTracks(showAllInterpolationTracks: bool
},
};
}

export function switchShowingObjectsTextAlways(showObjectsTextAlways: boolean): AnyAction {
return {
type: SettingsActionTypes.SWITCH_SHOWING_OBJECTS_TEXT_ALWAYS,
payload: {
showObjectsTextAlways,
},
};
}
Loading