Merge branch 'develop' into bs/reset_color_settings

main
Boris Sekachev 6 years ago committed by GitHub
commit 207dc99e04
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
- 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
- Button to reset colors settings (brightness, saturation, contrast) in the new UI
### Changed

@ -100,6 +100,7 @@ Canvas itself handles:
select(objectState: any): void;
fitCanvas(): void;
bitmap(enabled: boolean): void;
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;
@ -189,4 +190,5 @@ Standard JS events are used.
| dragCanvas() | + | - | - | - | - | - | + | - |
| zoomCanvas() | + | - | - | - | - | - | - | + |
| cancel() | - | + | + | + | + | + | + | + |
| bitmap() | + | + | + | + | + | + | + | + |
| setZLayer() | + | + | + | + | + | + | + | + |

@ -152,6 +152,16 @@ polyline.cvat_canvas_shape_splitting {
box-shadow: 2px 2px 5px 0px rgba(0,0,0,0.75);
}
#cvat_canvas_bitmap {
pointer-events: none;
position: absolute;
z-index: 4;
background: black;
width: 100%;
height: 100%;
box-shadow: 2px 2px 5px 0px rgba(0,0,0,0.75);
}
#cvat_canvas_grid {
position: absolute;
z-index: 2;

@ -49,6 +49,7 @@ interface Canvas {
select(objectState: any): void;
fitCanvas(): void;
bitmap(enable: boolean): void;
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;
@ -86,6 +87,10 @@ class CanvasImpl implements Canvas {
);
}
public bitmap(enable: boolean): void {
this.model.bitmap(enable);
}
public dragCanvas(enable: boolean): void {
this.model.dragCanvas(enable);
}

@ -98,8 +98,9 @@ export enum UpdateReasons {
GROUP = 'group',
SELECT = 'select',
CANCEL = 'cancel',
BITMAP = 'bitmap',
DRAG_CANVAS = 'drag_canvas',
ZOOM_CANVAS = 'ZOOM_CANVAS',
ZOOM_CANVAS = 'zoom_canvas',
}
export enum Mode {
@ -116,6 +117,7 @@ export enum Mode {
}
export interface CanvasModel {
readonly imageBitmap: boolean;
readonly image: Image | null;
readonly objects: any[];
readonly zLayer: number | null;
@ -148,6 +150,7 @@ export interface CanvasModel {
select(objectState: any): void;
fitCanvas(width: number, height: number): void;
bitmap(enabled: boolean): void;
dragCanvas(enable: boolean): void;
zoomCanvas(enable: boolean): void;
@ -159,6 +162,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
activeElement: ActiveElement;
angle: number;
canvasSize: Size;
imageBitmap: boolean;
image: Image | null;
imageID: number | null;
imageOffset: number;
@ -191,6 +195,7 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
height: 0,
width: 0,
},
imageBitmap: false,
image: null,
imageID: null,
imageOffset: 0,
@ -277,6 +282,11 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
this.notify(UpdateReasons.OBJECTS_UPDATED);
}
public bitmap(enabled: boolean): void {
this.data.imageBitmap = enabled;
this.notify(UpdateReasons.BITMAP);
}
public dragCanvas(enable: boolean): void {
if (enable && this.data.mode !== Mode.IDLE) {
throw Error(`Canvas is busy. Action: ${this.data.mode}`);
@ -522,6 +532,10 @@ export class CanvasModelImpl extends MasterImpl implements CanvasModel {
return this.data.zLayer;
}
public get imageBitmap(): boolean {
return this.data.imageBitmap;
}
public get image(): Image | null {
return this.data.image;
}

@ -47,6 +47,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
private text: SVGSVGElement;
private adoptedText: SVG.Container;
private background: HTMLCanvasElement;
private bitmap: HTMLCanvasElement;
private grid: SVGSVGElement;
private content: SVGSVGElement;
private adoptedContent: SVG.Container;
@ -285,7 +286,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
private moveCanvas(): void {
for (const obj of [this.background, this.grid]) {
for (const obj of [this.background, this.grid, this.bitmap]) {
obj.style.top = `${this.geometry.top}px`;
obj.style.left = `${this.geometry.left}px`;
}
@ -303,7 +304,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
private transformCanvas(): void {
// Transform canvas
for (const obj of [this.background, this.grid, this.content]) {
for (const obj of [this.background, this.grid, this.content, this.bitmap]) {
obj.style.transform = `scale(${this.geometry.scale}) rotate(${this.geometry.angle}deg)`;
}
@ -358,7 +359,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
}
private resizeCanvas(): void {
for (const obj of [this.background, this.grid]) {
for (const obj of [this.background, this.grid, this.bitmap]) {
obj.style.width = `${this.geometry.image.width}px`;
obj.style.height = `${this.geometry.image.height}px`;
}
@ -546,6 +547,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.text = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.adoptedText = (SVG.adopt((this.text as any as HTMLElement)) as SVG.Container);
this.background = window.document.createElement('canvas');
this.bitmap = window.document.createElement('canvas');
// window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
this.grid = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
@ -590,6 +592,8 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.text.setAttribute('id', 'cvat_canvas_text_content');
this.background.setAttribute('id', 'cvat_canvas_background');
this.content.setAttribute('id', 'cvat_canvas_content');
this.bitmap.setAttribute('id', 'cvat_canvas_bitmap');
this.bitmap.style.display = 'none';
// Setup wrappers
this.canvas.setAttribute('id', 'cvat_canvas_wrapper');
@ -605,6 +609,7 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.canvas.appendChild(this.loadingAnimation);
this.canvas.appendChild(this.text);
this.canvas.appendChild(this.background);
this.canvas.appendChild(this.bitmap);
this.canvas.appendChild(this.grid);
this.canvas.appendChild(this.content);
@ -702,7 +707,16 @@ 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.BITMAP) {
const { imageBitmap } = model;
if (imageBitmap) {
this.bitmap.style.display = '';
this.redrawBitmap();
} else {
this.bitmap.style.display = 'none';
}
} else if (reason === UpdateReasons.IMAGE_CHANGED) {
const { image } = model;
if (!image) {
this.loadingAnimation.classList.remove('cvat_canvas_hidden');
@ -875,12 +889,59 @@ export class CanvasViewImpl implements CanvasView, Listener {
this.mode = Mode.IDLE;
this.canvas.style.cursor = '';
}
if (model.imageBitmap
&& [UpdateReasons.IMAGE_CHANGED,
UpdateReasons.OBJECTS_UPDATED,
UpdateReasons.SET_Z_LAYER,
].includes(reason)
) {
this.redrawBitmap();
}
}
public html(): HTMLDivElement {
return this.canvas;
}
private redrawBitmap(): void {
const width = +this.background.style.width.slice(0, -2);
const height = +this.background.style.height.slice(0, -2);
this.bitmap.setAttribute('width', `${width}px`);
this.bitmap.setAttribute('height', `${height}px`);
const states = this.controller.objects;
const ctx = this.bitmap.getContext('2d');
if (ctx) {
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, width, height);
for (const state of states) {
if (state.hidden || state.outside) continue;
ctx.fillStyle = 'white';
if (['rectangle', 'polygon'].includes(state.shapeType)) {
const points = state.shapeType === 'rectangle' ? [
state.points[0], // xtl
state.points[1], // ytl
state.points[2], // xbr
state.points[1], // ytl
state.points[2], // xbr
state.points[3], // ybr
state.points[0], // xtl
state.points[3], // ybr
] : state.points;
ctx.beginPath();
ctx.moveTo(points[0], points[1]);
for (let i = 0; i < points.length; i += 2) {
ctx.lineTo(points[i], points[i + 1]);
}
ctx.closePath();
}
ctx.fill();
}
}
}
private saveState(state: any): void {
this.drawnStates[state.clientID] = {
clientID: state.clientID,

@ -18,6 +18,7 @@ export enum SettingsActionTypes {
CHANGE_SELECTED_SHAPES_OPACITY = 'CHANGE_SELECTED_SHAPES_OPACITY',
CHANGE_SHAPES_COLOR_BY = 'CHANGE_SHAPES_COLOR_BY',
CHANGE_SHAPES_BLACK_BORDERS = 'CHANGE_SHAPES_BLACK_BORDERS',
CHANGE_SHOW_UNLABELED_REGIONS = 'CHANGE_SHOW_UNLABELED_REGIONS',
CHANGE_FRAME_STEP = 'CHANGE_FRAME_STEP',
CHANGE_FRAME_SPEED = 'CHANGE_FRAME_SPEED',
SWITCH_RESET_ZOOM = 'SWITCH_RESET_ZOOM',
@ -66,6 +67,15 @@ export function changeShapesBlackBorders(blackBorders: boolean): AnyAction {
};
}
export function changeShowBitmap(showBitmap: boolean): AnyAction {
return {
type: SettingsActionTypes.CHANGE_SHOW_UNLABELED_REGIONS,
payload: {
showBitmap,
},
};
}
export function switchRotateAll(rotateAll: boolean): AnyAction {
return {
type: SettingsActionTypes.SWITCH_ROTATE_ALL,

@ -42,6 +42,7 @@ interface Props {
colorBy: ColorBy;
selectedOpacity: number;
blackBorders: boolean;
showBitmap: boolean;
grid: boolean;
gridSize: number;
gridColor: GridColor;
@ -112,6 +113,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
colorBy,
selectedOpacity,
blackBorders,
showBitmap,
frameData,
frameAngle,
annotations,
@ -198,6 +200,10 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
this.updateShapesView();
}
if (prevProps.showBitmap !== showBitmap) {
canvasInstance.bitmap(showBitmap);
}
if (prevProps.frameAngle !== frameAngle) {
canvasInstance.rotate(frameAngle);
}
@ -557,6 +563,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
for (const state of annotations) {
let shapeColor = '';
if (colorBy === ColorBy.INSTANCE) {
shapeColor = state.color;
} else if (colorBy === ColorBy.GROUP) {
@ -572,6 +579,7 @@ export default class CanvasWrapperComponent extends React.PureComponent<Props> {
if (handler && handler.nested) {
handler.nested.fill({ color: shapeColor });
}
(shapeView as any).instance.fill({ color: shapeColor, opacity: opacity / 100 });
(shapeView as any).instance.stroke({ color: blackBorders ? 'black' : shapeColor });
}

@ -24,12 +24,14 @@ interface Props {
opacity: number;
selectedOpacity: number;
blackBorders: boolean;
showBitmap: boolean;
collapseAppearance(): void;
changeShapesColorBy(event: RadioChangeEvent): void;
changeShapesOpacity(event: SliderValue): void;
changeSelectedShapesOpacity(event: SliderValue): void;
changeShapesBlackBorders(event: CheckboxChangeEvent): void;
changeShowBitmap(event: CheckboxChangeEvent): void;
}
function AppearanceBlock(props: Props): JSX.Element {
@ -39,11 +41,13 @@ function AppearanceBlock(props: Props): JSX.Element {
opacity,
selectedOpacity,
blackBorders,
showBitmap,
collapseAppearance,
changeShapesColorBy,
changeShapesOpacity,
changeSelectedShapesOpacity,
changeShapesBlackBorders,
changeShowBitmap,
} = props;
return (
@ -85,6 +89,12 @@ function AppearanceBlock(props: Props): JSX.Element {
>
Black borders
</Checkbox>
<Checkbox
onChange={changeShowBitmap}
checked={showBitmap}
>
Show bitmap
</Checkbox>
</div>
</Collapse.Panel>
</Collapse>

@ -29,6 +29,7 @@ interface Props {
opacity: number;
selectedOpacity: number;
blackBorders: boolean;
showBitmap: boolean;
collapseSidebar(): void;
collapseAppearance(): void;
@ -37,6 +38,7 @@ interface Props {
changeShapesOpacity(event: SliderValue): void;
changeSelectedShapesOpacity(event: SliderValue): void;
changeShapesBlackBorders(event: CheckboxChangeEvent): void;
changeShowBitmap(event: CheckboxChangeEvent): void;
}
function ObjectsSideBar(props: Props): JSX.Element {
@ -47,12 +49,14 @@ function ObjectsSideBar(props: Props): JSX.Element {
opacity,
selectedOpacity,
blackBorders,
showBitmap,
collapseSidebar,
collapseAppearance,
changeShapesColorBy,
changeShapesOpacity,
changeSelectedShapesOpacity,
changeShapesBlackBorders,
changeShowBitmap,
} = props;
const appearanceProps = {
@ -62,11 +66,13 @@ function ObjectsSideBar(props: Props): JSX.Element {
opacity,
selectedOpacity,
blackBorders,
showBitmap,
changeShapesColorBy,
changeShapesOpacity,
changeSelectedShapesOpacity,
changeShapesBlackBorders,
changeShowBitmap,
};
return (

@ -23,6 +23,11 @@
background: $background-color-2;
border-bottom: none;
height: 230px;
> .ant-collapse-content-box {
padding: 10px;
}
}
}
}
@ -254,6 +259,10 @@
width: 33%;
}
}
.ant-checkbox-wrapper {
margin-left: 0px;
}
}
.cvat-object-item-menu {

@ -62,6 +62,7 @@ interface StateToProps {
colorBy: ColorBy;
selectedOpacity: number;
blackBorders: boolean;
showBitmap: boolean;
grid: boolean;
gridSize: number;
gridColor: GridColor;
@ -169,6 +170,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
colorBy,
selectedOpacity,
blackBorders,
showBitmap,
},
},
shortcuts: {
@ -192,6 +194,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
colorBy,
selectedOpacity,
blackBorders,
showBitmap,
grid,
gridSize,
gridColor,

@ -27,6 +27,7 @@ import {
changeShapesOpacity as changeShapesOpacityAction,
changeSelectedShapesOpacity as changeSelectedShapesOpacityAction,
changeShapesBlackBorders as changeShapesBlackBordersAction,
changeShowBitmap as changeShowUnlabeledRegionsAction,
} from 'actions/settings-actions';
@ -37,6 +38,7 @@ interface StateToProps {
opacity: number;
selectedOpacity: number;
blackBorders: boolean;
showBitmap: boolean;
}
interface DispatchToProps {
@ -47,6 +49,7 @@ interface DispatchToProps {
changeShapesOpacity(shapesOpacity: number): void;
changeSelectedShapesOpacity(selectedShapesOpacity: number): void;
changeShapesBlackBorders(blackBorders: boolean): void;
changeShowBitmap(showBitmap: boolean): void;
}
function mapStateToProps(state: CombinedState): StateToProps {
@ -61,6 +64,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
opacity,
selectedOpacity,
blackBorders,
showBitmap,
},
},
} = state;
@ -72,6 +76,7 @@ function mapStateToProps(state: CombinedState): StateToProps {
opacity,
selectedOpacity,
blackBorders,
showBitmap,
};
}
@ -132,6 +137,9 @@ function mapDispatchToProps(dispatch: any): DispatchToProps {
changeShapesBlackBorders(blackBorders: boolean): void {
dispatch(changeShapesBlackBordersAction(blackBorders));
},
changeShowBitmap(showBitmap: boolean) {
dispatch(changeShowUnlabeledRegionsAction(showBitmap));
},
};
}
@ -177,6 +185,11 @@ class ObjectsSideBarContainer extends React.PureComponent<Props> {
changeShapesBlackBorders(event.target.checked);
};
private changeShowBitmap = (event: CheckboxChangeEvent): void => {
const { changeShowBitmap } = this.props;
changeShowBitmap(event.target.checked);
};
public render(): JSX.Element {
const {
sidebarCollapsed,
@ -185,6 +198,7 @@ class ObjectsSideBarContainer extends React.PureComponent<Props> {
opacity,
selectedOpacity,
blackBorders,
showBitmap,
collapseSidebar,
collapseAppearance,
} = this.props;
@ -197,12 +211,14 @@ class ObjectsSideBarContainer extends React.PureComponent<Props> {
opacity={opacity}
selectedOpacity={selectedOpacity}
blackBorders={blackBorders}
showBitmap={showBitmap}
collapseSidebar={collapseSidebar}
collapseAppearance={collapseAppearance}
changeShapesColorBy={this.changeShapesColorBy}
changeShapesOpacity={this.changeShapesOpacity}
changeSelectedShapesOpacity={this.changeSelectedShapesOpacity}
changeShapesBlackBorders={this.changeShapesBlackBorders}
changeShowBitmap={this.changeShowBitmap}
/>
);
}

@ -434,6 +434,7 @@ export interface ShapesSettingsState {
opacity: number;
selectedOpacity: number;
blackBorders: boolean;
showBitmap: boolean;
}
export interface SettingsState {

@ -22,6 +22,7 @@ const defaultState: SettingsState = {
opacity: 3,
selectedOpacity: 30,
blackBorders: false,
showBitmap: false,
},
workspace: {
autoSave: false,
@ -127,6 +128,15 @@ export default (state = defaultState, action: AnyAction): SettingsState => {
},
};
}
case SettingsActionTypes.CHANGE_SHOW_UNLABELED_REGIONS: {
return {
...state,
shapes: {
...state.shapes,
showBitmap: action.payload.showBitmap,
},
};
}
case SettingsActionTypes.CHANGE_FRAME_STEP: {
return {
...state,
@ -217,18 +227,18 @@ export default (state = defaultState, action: AnyAction): SettingsState => {
},
};
}
case BoundariesActionTypes.RESET_AFTER_ERROR:
case AnnotationActionTypes.GET_JOB_SUCCESS: {
const { job } = action.payload;
return {
...state,
...defaultState,
player: {
...state.player,
...defaultState.player,
resetZoom: job && job.task.mode === 'annotation',
},
};
}
case BoundariesActionTypes.RESET_AFTER_ERROR:
case AuthActionTypes.LOGOUT_SUCCESS: {
return { ...defaultState };
}

Loading…
Cancel
Save