Skip to content

Commit

Permalink
Merge pull request #1349 from opencv/bs/show_text_always
Browse files Browse the repository at this point in the history
React UI: Added option to display shape text always
  • Loading branch information
ActiveChooN authored Apr 3, 2020
2 parents dadd3e6 + f0c6bdb commit 16afc69
Show file tree
Hide file tree
Showing 14 changed files with 173 additions and 26 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Dialog window with some helpful information about using filters
- Ability to display a bitmap in the new UI
- Button to reset colors settings (brightness, saturation, contrast) 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(): Mode;
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() | + | + | + | + | + | + | + | + |
9 changes: 8 additions & 1 deletion 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 @@ -53,8 +54,9 @@ interface Canvas {
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;

mode(): void;
mode(): Mode;
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

0 comments on commit 16afc69

Please sign in to comment.