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

Hide mask during editing #8554

Merged
merged 34 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
b1b89e7
added information about edited state to cvat-ui
klakhov Oct 16, 2024
dc04778
hide mask on shortcut
klakhov Oct 16, 2024
65a13b2
fixed missing cursor
klakhov Oct 17, 2024
0684a9a
add hide icon
klakhov Oct 17, 2024
c6aecf3
refactored code, fixed issues
klakhov Oct 18, 2024
60005d0
Merge branch 'develop' into kl/hide-mask
klakhov Oct 18, 2024
a47e5e7
added changelog, fixed some issues
klakhov Oct 18, 2024
c7a2ac2
Merge branch 'kl/hide-mask' of https://github.com/cvat-ai/cvat into k…
klakhov Oct 18, 2024
0b81b8b
fixed sonar cloud issue
klakhov Oct 18, 2024
dd28e80
Merge branch 'develop' into kl/hide-mask
klakhov Oct 18, 2024
2f8f8db
fixed resetting edited state
klakhov Oct 21, 2024
15d0c0b
small refactoring
klakhov Oct 21, 2024
58f970a
stop drawing polygon on hide
klakhov Oct 21, 2024
920dbc1
fix create hidden mask
klakhov Oct 21, 2024
0610dd4
added tooltip, fixed single shape
klakhov Oct 21, 2024
cc3a215
Merge branch 'develop' into kl/hide-mask
klakhov Oct 21, 2024
70b65cf
Merge branch 'develop' into kl/hide-mask
klakhov Oct 22, 2024
b662c37
Merge branch 'develop' into kl/hide-mask
klakhov Oct 28, 2024
8866cac
fixed cvat-ui comments
klakhov Oct 28, 2024
8ef68c9
Merge branch 'develop' into kl/hide-mask
klakhov Oct 29, 2024
bda9424
fix hiding polygon during hide
klakhov Oct 29, 2024
2548ed6
refactored code duplication
klakhov Oct 29, 2024
4a658ae
fixed excessive configurate calls
klakhov Oct 29, 2024
c05f45b
fixed remove, renamed hide variable
klakhov Oct 29, 2024
3c7d622
Merge branch 'develop' into kl/hide-mask
klakhov Oct 30, 2024
6b1c612
reset hide on new mask draw/edit
klakhov Oct 30, 2024
1770803
show new mask even if hide mode is enabled
klakhov Oct 30, 2024
9ecfc2c
fix hide in single shape mode
klakhov Oct 30, 2024
617569c
reverted some changes, updated package
klakhov Oct 30, 2024
b908ccf
fix moving from single shape workspace
klakhov Oct 30, 2024
6ad833e
hide tooltip on mask finish
klakhov Oct 30, 2024
c00529c
Merge branch 'develop' into kl/hide-mask
bsekachev Oct 30, 2024
6f06e91
Merge branch 'develop' into kl/hide-mask
klakhov Oct 31, 2024
56e6f0d
Merge branch 'kl/hide-mask' of https://github.com/cvat-ai/cvat into k…
klakhov Oct 31, 2024
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
3 changes: 3 additions & 0 deletions changelog.d/20241018_142148_klakhov_hide_mask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Added

- Feature to hide a mask during editing (<https://github.com/cvat-ai/cvat/pull/8554>)
2 changes: 1 addition & 1 deletion cvat-canvas/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-canvas",
"version": "2.20.9",
"version": "2.20.10",
"type": "module",
"description": "Part of Computer Vision Annotation Tool which presents its canvas library",
"main": "src/canvas.ts",
Expand Down
6 changes: 6 additions & 0 deletions cvat-canvas/src/typescript/canvasModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export interface Configuration {
controlPointsSize?: number;
outlinedBorders?: string | false;
resetZoom?: boolean;
hideEditedObject?: boolean;
}

export interface BrushTool {
Expand Down Expand Up @@ -416,6 +417,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
textPosition: consts.DEFAULT_SHAPE_TEXT_POSITION,
textContent: consts.DEFAULT_SHAPE_TEXT_CONTENT,
undefinedAttrValue: consts.DEFAULT_UNDEFINED_ATTR_VALUE,
hideEditedObject: false,
},
imageBitmap: false,
image: null,
Expand Down Expand Up @@ -981,6 +983,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.data.configuration.CSSImageFilter = configuration.CSSImageFilter;
}

if (typeof configuration.hideEditedObject === 'boolean') {
this.data.configuration.hideEditedObject = configuration.hideEditedObject;
}

this.notify(UpdateReasons.CONFIG_UPDATED);
}

Expand Down
40 changes: 36 additions & 4 deletions cvat-canvas/src/typescript/drawHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import * as SVG from 'svg.js';
import 'svg.draw.js';
import './svg.patch';
import { CIRCLE_STROKE } from './svg.patch';

import { AutoborderHandler } from './autoborderHandler';
import {
Expand Down Expand Up @@ -104,6 +104,7 @@
private controlPointsSize: number;
private selectedShapeOpacity: number;
private outlinedBorders: string;
private isHidden: boolean;

// we should use any instead of SVG.Shape because svg plugins cannot change declared interface
// so, methods like draw() just undefined for SVG.Shape, but nevertheless they exist
Expand Down Expand Up @@ -1276,6 +1277,7 @@
this.selectedShapeOpacity = configuration.selectedShapeOpacity;
this.outlinedBorders = configuration.outlinedBorders || 'black';
this.autobordersEnabled = false;
this.isHidden = false;
this.startTimestamp = Date.now();
this.onDrawDoneDefault = onDrawDone;
this.canvas = canvas;
Expand All @@ -1301,10 +1303,28 @@
});
}

private strokePoint(point: SVG.Element): void {
point.attr('stroke', this.isHidden ? 'none' : CIRCLE_STROKE);
point.fill({ opacity: this.isHidden ? 0 : 1 });
}

private updateHidden(value: boolean) {

Check warning on line 1311 in cvat-canvas/src/typescript/drawHandler.ts

View workflow job for this annotation

GitHub Actions / Linter

Missing return type on function
this.isHidden = value;

if (value) {
this.canvas.attr('pointer-events', 'none');
} else {
this.canvas.attr('pointer-events', 'all');
}
}

public configurate(configuration: Configuration): void {
this.controlPointsSize = configuration.controlPointsSize;
this.selectedShapeOpacity = configuration.selectedShapeOpacity;
this.outlinedBorders = configuration.outlinedBorders || 'black';
if (this.isHidden !== configuration.hideEditedObject) {
this.updateHidden(configuration.hideEditedObject);
}

const isFillableRect = this.drawData &&
this.drawData.shapeType === 'rectangle' &&
Expand All @@ -1315,15 +1335,26 @@
const isFilalblePolygon = this.drawData && this.drawData.shapeType === 'polygon';

if (this.drawInstance && (isFillableRect || isFillableCuboid || isFilalblePolygon)) {
this.drawInstance.fill({ opacity: configuration.selectedShapeOpacity });
this.drawInstance.fill({
opacity: configuration.hideEditedObject ? 0 : configuration.selectedShapeOpacity,
});
}

if (this.drawInstance && (isFilalblePolygon)) {
const paintHandler = this.drawInstance.remember('_paintHandler');
if (paintHandler) {
for (const point of (paintHandler as any).set.members) {
this.strokePoint(point);
}
}
}

if (this.drawInstance && this.drawInstance.attr('stroke')) {
this.drawInstance.attr('stroke', this.outlinedBorders);
this.drawInstance.attr('stroke', configuration.hideEditedObject ? 'none' : this.outlinedBorders);
}

if (this.pointsGroup && this.pointsGroup.attr('stroke')) {
this.pointsGroup.attr('stroke', this.outlinedBorders);
this.pointsGroup.attr('stroke', configuration.hideEditedObject ? 'none' : this.outlinedBorders);
}

this.autobordersEnabled = configuration.autoborders;
Expand Down Expand Up @@ -1369,6 +1400,7 @@
const paintHandler = this.drawInstance.remember('_paintHandler');

for (const point of (paintHandler as any).set.members) {
this.strokePoint(point);
point.attr('stroke-width', `${consts.POINTS_STROKE_WIDTH / geometry.scale}`);
point.attr('r', `${this.controlPointsSize / geometry.scale}`);
}
Expand Down
2 changes: 1 addition & 1 deletion cvat-canvas/src/typescript/editHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ export class EditHandlerImpl implements EditHandler {

const paintHandler = this.editLine.remember('_paintHandler');

for (const point of (paintHandler as any).set.members) {
for (const point of paintHandler.set.members) {
point.attr('stroke-width', `${consts.POINTS_STROKE_WIDTH / geometry.scale}`);
point.attr('r', `${this.controlPointsSize / geometry.scale}`);
}
Expand Down
43 changes: 36 additions & 7 deletions cvat-canvas/src/typescript/masksHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import debounce from 'lodash/debounce';

import {
DrawData, MasksEditData, Geometry, Configuration, BrushTool, ColorBy,
DrawData, MasksEditData, Geometry, Configuration, BrushTool, ColorBy, Position,
} from './canvasModel';
import consts from './consts';
import { DrawHandler } from './drawHandler';
Expand Down Expand Up @@ -61,10 +61,11 @@
private editData: MasksEditData | null;

private colorBy: ColorBy;
private latestMousePos: { x: number; y: number; };
private latestMousePos: Position;
private startTimestamp: number;
private geometry: Geometry;
private drawingOpacity: number;
private isHidden: boolean;

private keepDrawnPolygon(): void {
const canvasWrapper = this.canvas.getElement().parentElement;
Expand Down Expand Up @@ -217,12 +218,29 @@
private imageDataFromCanvas(wrappingBBox: WrappingBBox): Uint8ClampedArray {
const imageData = this.canvas.toCanvasElement()
.getContext('2d').getImageData(
wrappingBBox.left, wrappingBBox.top,
wrappingBBox.right - wrappingBBox.left + 1, wrappingBBox.bottom - wrappingBBox.top + 1,
wrappingBBox.left,
wrappingBBox.top,
wrappingBBox.right - wrappingBBox.left + 1,
wrappingBBox.bottom - wrappingBBox.top + 1,
).data;
return imageData;
}

private updateHidden(value: boolean) {

Check warning on line 229 in cvat-canvas/src/typescript/masksHandler.ts

View workflow job for this annotation

GitHub Actions / Linter

Missing return type on function
this.isHidden = value;

// Need to update style of upper canvas explicitly because update of default cursor is not applied immediately
// https://github.com/fabricjs/fabric.js/issues/1456
const newOpacity = value ? '0' : '';
const newCursor = value ? 'inherit' : 'none';
this.canvas.getElement().parentElement.style.opacity = newOpacity;
const upperCanvas = this.canvas.getElement().parentElement.querySelector('.upper-canvas') as HTMLElement;
if (upperCanvas) {
upperCanvas.style.cursor = newCursor;
}
this.canvas.defaultCursor = newCursor;
}

private updateBrushTools(brushTool?: BrushTool, opts: Partial<BrushTool> = {}): void {
if (this.isPolygonDrawing) {
// tool was switched from polygon to brush for example
Expand Down Expand Up @@ -350,6 +368,7 @@
this.editData = null;
this.drawingOpacity = 0.5;
this.brushMarker = null;
this.isHidden = false;
this.colorBy = ColorBy.LABEL;
this.onDrawDone = onDrawDone;
this.onDrawRepeat = onDrawRepeat;
Expand Down Expand Up @@ -452,7 +471,7 @@
this.canvas.renderAll();
}

if (isMouseDown && !isBrushSizeChanging && ['brush', 'eraser'].includes(tool?.type)) {
if (isMouseDown && !this.isHidden && !isBrushSizeChanging && ['brush', 'eraser'].includes(tool?.type)) {
const color = fabric.Color.fromHex(tool.color);
color.setAlpha(tool.type === 'eraser' ? 1 : 0.5);

Expand Down Expand Up @@ -530,6 +549,10 @@

public configurate(configuration: Configuration): void {
this.colorBy = configuration.colorBy;

if (this.isHidden !== configuration.hideEditedObject) {
this.updateHidden(configuration.hideEditedObject);
}
}

public transform(geometry: Geometry): void {
Expand Down Expand Up @@ -563,7 +586,10 @@
const color = fabric.Color.fromHex(this.getStateColor(drawData.initialState)).getSource();
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points);
imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1,
imageDataToDataURL(
imageBitmap,
right - left + 1,
bottom - top + 1,
(dataURL: string) => new Promise((resolve) => {
fabric.Image.fromURL(dataURL, (image: fabric.Image) => {
try {
Expand Down Expand Up @@ -654,7 +680,10 @@
const color = fabric.Color.fromHex(this.getStateColor(editData.state)).getSource();
const [left, top, right, bottom] = points.slice(-4);
const imageBitmap = expandChannels(color[0], color[1], color[2], points);
imageDataToDataURL(imageBitmap, right - left + 1, bottom - top + 1,
imageDataToDataURL(
imageBitmap,
right - left + 1,
bottom - top + 1,
(dataURL: string) => new Promise((resolve) => {
fabric.Image.fromURL(dataURL, (image: fabric.Image) => {
try {
Expand Down
2 changes: 2 additions & 0 deletions cvat-canvas/src/typescript/svg.patch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ SVG.Element.prototype.draw.extend(
}),
);

export const CIRCLE_STROKE = '#000';
klakhov marked this conversation as resolved.
Show resolved Hide resolved
// Fix method drawCircles
function drawCircles(): void {
const array = this.el.array().valueOf();
Expand All @@ -109,6 +110,7 @@ function drawCircles(): void {
.circle(5)
.stroke({
width: 1,
color: CIRCLE_STROKE,
})
.fill('#ccc')
.center(p.x, p.y),
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.66.2",
"version": "1.66.3",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
51 changes: 50 additions & 1 deletion cvat-ui/src/actions/annotation-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ export enum AnnotationActionTypes {
COLLAPSE_APPEARANCE = 'COLLAPSE_APPEARANCE',
COLLAPSE_OBJECT_ITEMS = 'COLLAPSE_OBJECT_ITEMS',
ACTIVATE_OBJECT = 'ACTIVATE_OBJECT',
UPDATE_EDITED_STATE = 'UPDATE_EDITED_STATE',
HIDE_ACTIVE_OBJECT = 'HIDE_ACTIVE_OBJECT',
REMOVE_OBJECT = 'REMOVE_OBJECT',
REMOVE_OBJECT_SUCCESS = 'REMOVE_OBJECT_SUCCESS',
REMOVE_OBJECT_FAILED = 'REMOVE_OBJECT_FAILED',
Expand Down Expand Up @@ -1320,7 +1322,7 @@ export function searchAnnotationsAsync(
};
}

const ShapeTypeToControl: Record<ShapeType, ActiveControl> = {
export const ShapeTypeToControl: Record<ShapeType, ActiveControl> = {
[ShapeType.RECTANGLE]: ActiveControl.DRAW_RECTANGLE,
[ShapeType.POLYLINE]: ActiveControl.DRAW_POLYLINE,
[ShapeType.POLYGON]: ActiveControl.DRAW_POLYGON,
Expand Down Expand Up @@ -1608,3 +1610,50 @@ export function restoreFrameAsync(frame: number): ThunkAction {
}
};
}

export function changeHideActiveObjectAsync(hide: boolean): ThunkAction {
return async (dispatch: ThunkDispatch, getState): Promise<void> => {
const state = getState();
const { instance: canvas } = state.annotation.canvas;
if (canvas) {
(canvas as Canvas).configure({
hideEditedObject: hide,
});

const { objectState } = state.annotation.editing;
if (objectState) {
objectState.hidden = hide;
await dispatch(updateAnnotationsAsync([objectState]));
}

dispatch({
type: AnnotationActionTypes.HIDE_ACTIVE_OBJECT,
payload: {
hide,
},
});
}
};
}

export function updateEditedStateAsync(objectState: ObjectState | null): ThunkAction {
return async (dispatch: ThunkDispatch, getState): Promise<void> => {
let newActiveObjectHidden = false;
if (objectState) {
newActiveObjectHidden = objectState.hidden;
}

dispatch({
type: AnnotationActionTypes.UPDATE_EDITED_STATE,
payload: {
objectState,
},
});

const state = getState();
const { activeObjectHidden } = state.annotation.canvas;
if (activeObjectHidden !== newActiveObjectHidden) {
dispatch(changeHideActiveObjectAsync(newActiveObjectHidden));
}
};
}
Loading
Loading