Skip to content

Commit

Permalink
1.2.1-alpha relese merge (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
SkalskiP authored Sep 4, 2019
1 parent 1f734db commit 86584b1
Show file tree
Hide file tree
Showing 70 changed files with 692 additions and 505 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,17 @@ Our application is being actively developed. If you have an idea for a new funct
- [ ] Integration with external storage - Amazon S3, Google Drive, Dropbox
- [ ] Copy annotations from previous image into the next one

## Citation

```
@MISC{make-sense,
author = {Piotr Skalski},
title = {{Make Sense}},
howpublished = "\url{https://github.com/SkalskiP/make-sense/}",
year = {2019},
}
```

## License

This project is licensed under the GPL-3.0 License - see the [LICENSE][2] file for details
Expand Down
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';
import './App.scss';
import EditorView from "./views/EditorView/EditorView";
import MainView from "./views/MainView/MainView";
import {ProjectType} from "./data/ProjectType";
import {ProjectType} from "./data/enums/ProjectType";
import {AppState} from "./store";
import {connect} from "react-redux";
import PopupView from "./views/PopupView/PopupView";
Expand Down
4 changes: 0 additions & 4 deletions src/data/Direction.ts

This file was deleted.

1 change: 1 addition & 0 deletions src/data/EditorData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ export interface EditorData {
canvasSize: ISize,
activeImageScale: number,
activeImageRectOnCanvas: IRect,
activeKeyCombo: string[],
event?: Event
}
4 changes: 2 additions & 2 deletions src/data/RectAnchor.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {AnchorType} from "./AnchorType";
import {IPoint} from "../interfaces/IPoint";
import {Direction} from "./enums/Direction";

export interface RectAnchor {
type: AnchorType,
type: Direction,
position: IPoint
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/data/Context.ts → src/data/enums/ContextType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum Context {
export enum ContextType {
EDITOR = "EDITOR",
LEFT_NAVBAR = "LEFT_NAVBAR",
RIGHT_NAVBAR = "RIGHT_NAVBAR",
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion src/data/AnchorType.ts → src/data/enums/Direction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum AnchorType {
export enum Direction {
TOP = "TOP",
BOTTOM = "BOTTOM",
LEFT = "LEFT",
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ExportFormatType} from "./ExportFormatType";
import {IExportFormat} from "../interfaces/IExportFormat";
import {ExportFormatType} from "../enums/ExportFormatType";
import {IExportFormat} from "../../interfaces/IExportFormat";

export const PointExportFormatData: IExportFormat[] = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {IExportFormat} from "../interfaces/IExportFormat";
import {ExportFormatType} from "./ExportFormatType";
import {IExportFormat} from "../../interfaces/IExportFormat";
import {ExportFormatType} from "../enums/ExportFormatType";

export const PolygonExportFormatData: IExportFormat[] = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {ExportFormatType} from "./ExportFormatType";
import {IExportFormat} from "../interfaces/IExportFormat";
import {ExportFormatType} from "../enums/ExportFormatType";
import {IExportFormat} from "../../interfaces/IExportFormat";

export const RectExportFormatData: IExportFormat[] = [
{
Expand All @@ -14,4 +14,4 @@ export const RectExportFormatData: IExportFormat[] = [
type: ExportFormatType.CSV,
label: "Single CSV file."
}
]
];
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {LabelType} from "./LabelType";
import {LabelType} from "../enums/LabelType";

export interface ILabelToolkit {
labelType: LabelType;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Settings} from "../settings/Settings";
import {Settings} from "../../settings/Settings";

export interface ISocialMedia {
displayName:string;
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IExportFormat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {ExportFormatType} from "../data/ExportFormatType";
import {ExportFormatType} from "../data/enums/ExportFormatType";

export interface IExportFormat {
type: ExportFormatType,
Expand Down
164 changes: 164 additions & 0 deletions src/logic/actions/EditorActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import {LabelType} from "../../data/enums/LabelType";
import {EditorModel} from "../../model/EditorModel";
import {RectRenderEngine} from "../render/RectRenderEngine";
import {PointRenderEngine} from "../render/PointRenderEngine";
import {PolygonRenderEngine} from "../render/PolygonRenderEngine";
import {IRect} from "../../interfaces/IRect";
import {Settings} from "../../settings/Settings";
import {RectUtil} from "../../utils/RectUtil";
import {EditorData} from "../../data/EditorData";
import {CanvasUtil} from "../../utils/CanvasUtil";
import {ISize} from "../../interfaces/ISize";
import React from "react";
import {IPoint} from "../../interfaces/IPoint";
import {DrawUtil} from "../../utils/DrawUtil";
import {PrimaryEditorRenderEngine} from "../render/PrimaryEditorRenderEngine";
import {ContextManager} from "../context/ContextManager";

export class EditorActions {

// =================================================================================================================
// RENDER ENGINES
// =================================================================================================================

public static mountSupportRenderingEngine(activeLabelType: LabelType) {
switch (activeLabelType) {
case LabelType.RECTANGLE:
EditorModel.supportRenderingEngine = new RectRenderEngine(EditorModel.canvas);
break;
case LabelType.POINT:
EditorModel.supportRenderingEngine = new PointRenderEngine(EditorModel.canvas);
break;
case LabelType.POLYGON:
EditorModel.supportRenderingEngine = new PolygonRenderEngine(EditorModel.canvas);
break;
default:
EditorModel.supportRenderingEngine = null;
break;
}
};

public static swapSupportRenderingEngine(activeLabelType: LabelType) {
EditorActions.mountSupportRenderingEngine(activeLabelType);
};

public static mountRenderEngines(activeLabelType: LabelType) {
EditorModel.primaryRenderingEngine = new PrimaryEditorRenderEngine(EditorModel.canvas);
EditorActions.mountSupportRenderingEngine(activeLabelType);
}

// =================================================================================================================
// RENDER
// =================================================================================================================

public static fullRender() {
DrawUtil.clearCanvas(EditorModel.canvas);
EditorModel.primaryRenderingEngine.drawImage(EditorModel.image, EditorModel.imageRectOnCanvas);
EditorModel.primaryRenderingEngine.render(EditorActions.getEditorData());
EditorModel.supportRenderingEngine && EditorModel.supportRenderingEngine.render(EditorActions.getEditorData());
}

// =================================================================================================================
// SETTERS
// =================================================================================================================

public static setLoadingStatus(status: boolean) {
EditorModel.isLoading = status;
}

public static setActiveImage(image: HTMLImageElement) {
EditorModel.image = image;
}

// =================================================================================================================
// GETTERS
// =================================================================================================================

public static getImageRect(image: HTMLImageElement): IRect | null {
if (!!image) {
const canvasPaddingWidth: number = Settings.CANVAS_PADDING_WIDTH_PX;
const imageRect: IRect = { x: 0, y: 0, width: image.width, height: image.height};
const canvasRect: IRect = {
x: canvasPaddingWidth,
y: canvasPaddingWidth,
width: EditorModel.canvas.width - 2 * canvasPaddingWidth,
height: EditorModel.canvas.height - 2 * canvasPaddingWidth
};
return RectUtil.fitInsideRectWithRatio(canvasRect, RectUtil.getRatio(imageRect));
}
return null;
};

public static getImageScale(image: HTMLImageElement): number | null {
if (!image || !EditorModel.imageRectOnCanvas)
return null;

return image.width / EditorModel.imageRectOnCanvas.width;
}

public static getEditorData(event?: Event): EditorData {
return {
mousePositionOnCanvas: EditorModel.mousePositionOnCanvas,
canvasSize: CanvasUtil.getSize(EditorModel.canvas),
activeImageScale: EditorModel.imageScale,
activeImageRectOnCanvas: EditorModel.imageRectOnCanvas,
activeKeyCombo: ContextManager.getActiveCombo(),
event: event
}
}

// =================================================================================================================
// HELPERS
// =================================================================================================================

public static calculateActiveImageCharacteristics() {
EditorModel.imageRectOnCanvas = EditorActions.getImageRect(EditorModel.image);
EditorModel.imageScale = EditorActions.getImageScale(EditorModel.image);
}

public static resizeCanvas = (newCanvasSize: ISize) => {
if (!!newCanvasSize && !!EditorModel.canvas) {
EditorModel.canvas.width = newCanvasSize.width;
EditorModel.canvas.height = newCanvasSize.height;
}
};

public static updateMousePositionIndicator(event: React.MouseEvent<HTMLCanvasElement, MouseEvent> | MouseEvent) {

if (!EditorModel.imageRectOnCanvas || !EditorModel.canvas) {
EditorModel.mousePositionIndicator.style.display = "none";
EditorModel.cursor.style.display = "none";
return;
}

const mousePositionOnCanvas: IPoint = CanvasUtil.getMousePositionOnCanvasFromEvent(event, EditorModel.canvas);
const canvasRect: IRect = {x: 0, y: 0, ...CanvasUtil.getSize(EditorModel.canvas)};
const isOverCanvas: boolean = RectUtil.isPointInside(canvasRect, mousePositionOnCanvas);

if (!isOverCanvas) {
EditorModel.mousePositionIndicator.style.display = "none";
EditorModel.cursor.style.display = "none";
return;
}

const isOverImage: boolean = RectUtil.isPointInside(EditorModel.imageRectOnCanvas, mousePositionOnCanvas);

if (isOverImage) {
const scale = EditorModel.imageScale;
const x: number = Math.round((mousePositionOnCanvas.x - EditorModel.imageRectOnCanvas.x) * scale);
const y: number = Math.round((mousePositionOnCanvas.y - EditorModel.imageRectOnCanvas.y) * scale);
const text: string = "x: " + x + ", y: " + y;

EditorModel.mousePositionIndicator.innerHTML = text;
EditorModel.mousePositionIndicator.style.left = (mousePositionOnCanvas.x + 15) + "px";
EditorModel.mousePositionIndicator.style.top = (mousePositionOnCanvas.y + 15) + "px";
EditorModel.mousePositionIndicator.style.display = "block";
} else {
EditorModel.mousePositionIndicator.style.display = "none";
}

EditorModel.cursor.style.left = mousePositionOnCanvas.x + "px";
EditorModel.cursor.style.top = mousePositionOnCanvas.y + "px";
EditorModel.cursor.style.display = "block";
};
}
9 changes: 9 additions & 0 deletions src/logic/context/BaseContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import {HotKeyAction} from "../../data/HotKeyAction";

export class BaseContext {
public static actions: HotKeyAction[] = [];

public static getActions(): HotKeyAction[] {
return this.actions;
}
}
26 changes: 23 additions & 3 deletions src/logic/context/ContextManager.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,41 @@
import {Context} from "../../data/Context";
import {ContextType} from "../../data/enums/ContextType";
import {HotKeyAction} from "../../data/HotKeyAction";
import {store} from "../../index";
import {updateActiveContext} from "../../store/general/actionCreators";
import * as _ from "lodash";
import {EditorContext} from "./EditorContext";
import {PopupContext} from "./PopupContext";

export class ContextManager {
private static activeCombo: string[] = [];
private static actions: HotKeyAction[] = [];
private static contextHistory: ContextType[] = [];

public static getActiveCombo(): string[] {
return ContextManager.activeCombo;
}

public static init(): void {
window.addEventListener("keydown", ContextManager.onDown);
window.addEventListener("keyup", ContextManager.onUp);
}

public static switchCtx(context: Context, actions: HotKeyAction[]): void {
public static switchCtx(context: ContextType): void {
store.dispatch(updateActiveContext(context));
ContextManager.actions = actions;
switch (context) {
case ContextType.EDITOR:
ContextManager.actions = EditorContext.getActions();
break;
case ContextType.POPUP:
ContextManager.actions = PopupContext.getActions();
break;
default:
ContextManager.actions = [];
}
}

public static restoreContext(): void {
ContextManager.switchCtx(ContextManager.contextHistory.pop());
}

private static onDown(event: KeyboardEvent): void {
Expand Down
58 changes: 58 additions & 0 deletions src/logic/context/EditorContext.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {HotKeyAction} from "../../data/HotKeyAction";
import {EditorModel} from "../../model/EditorModel";
import {LabelType} from "../../data/enums/LabelType";
import {EditorData} from "../../data/EditorData";
import {EditorActions} from "../actions/EditorActions";
import {PolygonRenderEngine} from "../render/PolygonRenderEngine";
import {EditorSelector} from "../../store/selectors/EditorSelector";
import {store} from "../../index";
import {updateActiveImageIndex} from "../../store/editor/actionCreators";
import {BaseContext} from "./BaseContext";

export class EditorContext extends BaseContext {
public static actions: HotKeyAction[] = [
{
keyCombo: ["Enter"],
action: (event: KeyboardEvent) => {
if (EditorModel.supportRenderingEngine && EditorModel.supportRenderingEngine.labelType === LabelType.POLYGON) {
const editorData: EditorData = EditorActions.getEditorData();
(EditorModel.supportRenderingEngine as PolygonRenderEngine).addLabelAndFinishCreation(editorData);
}
EditorActions.fullRender();
}
},
{
keyCombo: ["Escape"],
action: (event: KeyboardEvent) => {
if (EditorModel.supportRenderingEngine && EditorModel.supportRenderingEngine.labelType === LabelType.POLYGON)
(EditorModel.supportRenderingEngine as PolygonRenderEngine).cancelLabelCreation();
EditorActions.fullRender();
}
},
{
keyCombo: ["ArrowLeft"],
action: (event: KeyboardEvent) => {
EditorContext.getPreviousImage();
}
},
{
keyCombo: ["ArrowRight"],
action: (event: KeyboardEvent) => {
EditorContext.getNextImage();
}
}
];

private static getPreviousImage(): void {
const currentImageIndex: number = EditorSelector.getActiveImageIndex();
const previousImageIndex: number = Math.max(0, currentImageIndex - 1);
store.dispatch(updateActiveImageIndex(previousImageIndex));
}

private static getNextImage(): void {
const currentImageIndex: number = EditorSelector.getActiveImageIndex();
const imageCount: number = EditorSelector.getImagesData().length;
const nextImageIndex: number = Math.min(imageCount - 1, currentImageIndex + 1);
store.dispatch(updateActiveImageIndex(nextImageIndex));
}
}
Loading

0 comments on commit 86584b1

Please sign in to comment.