Skip to content
This repository has been archived by the owner on May 30, 2023. It is now read-only.

Commit

Permalink
Merge pull request #271 from daita-technologies/update/optimize_split…
Browse files Browse the repository at this point in the history
…_layer_editor

refactor: improve performance when drawing shapes
  • Loading branch information
ttattl authored Nov 6, 2022
2 parents b74dc6c + 9c7210a commit 65af709
Show file tree
Hide file tree
Showing 11 changed files with 603 additions and 153 deletions.
39 changes: 26 additions & 13 deletions src/components/Annotation/Editor/Shape/Polygon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { useDispatch, useSelector } from "react-redux";
import {
changeCurrentStatus,
removeDrawObjectStateIdByAI,
setHiddenDrawObject,
setSelectedShape,
updateDrawObject,
} from "reduxes/annotation/action";
Expand Down Expand Up @@ -286,6 +285,24 @@ const PolygonComp = ({
);
commonShapeEvent.handleDragEnd(e);
};
const converFlattenPointToPoint = (flatPoints: number[]) => {
const newPoints: Vector2d[] = [];
for (let index = 0; index < flatPoints.length; index = index + 2) {
newPoints.push({ x: flatPoints[index], y: flatPoints[index + 1] });
}
return newPoints;
};
const handleTransformEnd = (e: KonvaEventObject<DragEvent>) => {
dispatch(
updateDrawObject({
data: {
...spec,
points: converFlattenPointToPoint(flattenedPoints as number[]),
},
})
);
e.cancelBubble = true;
};
const handlePointDragMove = (e: KonvaEventObject<DragEvent>) => {
const { points } = spec;
if (groupRef && groupRef.current) {
Expand All @@ -294,17 +311,13 @@ const PolygonComp = ({
x: groupRef.current.getRelativePointerPosition().x,
y: groupRef.current.getRelativePointerPosition().y,
};
dispatch(
updateDrawObject({
data: {
...spec,
points: [
...points.slice(0, index),
pos,
...points.slice(index + 1),
],
},
})
const newPoints = [
...points.slice(0, index),
pos,
...points.slice(index + 1),
];
setFlattenedPoints(
newPoints.reduce((a, b) => a.concat([b.x, b.y]), [] as number[])
);
}
};
Expand Down Expand Up @@ -361,7 +374,7 @@ const PolygonComp = ({
draggable
onDragMove={handlePointDragMove}
onDragStart={commonShapeEvent.handleTransformStart}
onDragEnd={commonShapeEvent.handleTransformEnd}
onDragEnd={handleTransformEnd}
dragBoundFunc={dragBound}
{...CIRCLE_STYLE}
{...startPointAttr}
Expand Down
23 changes: 22 additions & 1 deletion src/components/Annotation/Editor/utils/event.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Layer } from "konva/lib/Layer";
import { KonvaEventObject } from "konva/lib/Node";
import { Stage } from "konva/lib/Stage";
import { Vector2d } from "konva/lib/types";
import {
MAX_HEIGHT_IMAGE_IN_EDITOR,
MAX_WIDTH_IMAGE_IN_EDITOR,
} from "../const";
import { ScaleResult } from "../type";
const scaleBy = 1.2;

export function getNewPositionOnWheel(
e: KonvaEventObject<WheelEvent>,
obj: Layer,
obj: Layer | Stage,
pointer: Vector2d
): ScaleResult {
e.evt.preventDefault();
Expand All @@ -29,3 +34,19 @@ export function getNewPositionOnWheel(
};
return { newPosition, newScale };
}
export function getFitScaleEditor(width: number, height: number) {
const widthRatio = MAX_WIDTH_IMAGE_IN_EDITOR / width;
const heightRatio = MAX_HEIGHT_IMAGE_IN_EDITOR / height;
let newWidth = width;
let newHeight = height;
if (widthRatio < 1 || heightRatio < 1) {
if (widthRatio < heightRatio) {
newWidth = MAX_WIDTH_IMAGE_IN_EDITOR;
newHeight = newHeight * widthRatio;
} else {
newHeight = MAX_HEIGHT_IMAGE_IN_EDITOR;
newWidth = newWidth * heightRatio;
}
}
return newWidth / width;
}
60 changes: 54 additions & 6 deletions src/routes/AnnotationPage/ControlPanel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { useDropzone } from "react-dropzone";
import { useDispatch, useSelector } from "react-redux";
import {
changeCurrentDrawType,
changeCurrentStatus,
changeZoom,
createDrawObject,
redoDrawObject,
Expand All @@ -44,11 +45,12 @@ import {
} from "reduxes/annotation/action";
import {
selectorAnnotationStatehHistory,
selectorCurrentDrawState,
selectorcurrentDrawType,
selectorDrawObjectById,
selectorDrawObjectStateIdByAI,
} from "reduxes/annotation/selector";
import { DrawObject, DrawType } from "reduxes/annotation/type";
import { DrawObject, DrawState, DrawType } from "reduxes/annotation/type";
import {
addImagesToAnnotation,
addNewClassLabel,
Expand All @@ -64,10 +66,21 @@ import {
} from "reduxes/annotationmanager/selecetor";
import { hashCode, intToRGB } from "../LabelAnnotation";
import { convertStrokeColorToFillColor } from "../LabelAnnotation/ClassLabel";
import NearMeIcon from "@mui/icons-material/NearMe";
import {
MAX_HEIGHT_IMAGE_IN_EDITOR,
MAX_WIDTH_IMAGE_IN_EDITOR,
} from "components/Annotation/Editor/const";
import { getFitScaleEditor } from "components/Annotation/Editor/utils";

const ControlPanel = () => {
const dispatch = useDispatch();
const currentDrawType = useSelector(selectorcurrentDrawType);
const [drawType, setDrawType] = React.useState<DrawType | null>(
useSelector(selectorcurrentDrawType)
);
const [drawState, setDrawState] = React.useState<DrawState | null>(
useSelector(selectorCurrentDrawState)
);
const drawObjectById = useSelector(selectorDrawObjectById);
const currentPreviewImageName = useSelector(selectorCurrentPreviewImageName);
const currentAnnotationFile = useSelector(selectorCurrentAnnotationFile);
Expand All @@ -88,14 +101,32 @@ const ControlPanel = () => {
);

const resetScaleHandler = () => {
dispatch(changeZoom({ zoom: { zoom: 1, position: { x: 0, y: 0 } } }));
if (currentAnnotationFile) {
const { width, height } = currentAnnotationFile;
const zoom = getFitScaleEditor(width, height);
dispatch(
changeZoom({
zoom: { zoom, position: { x: 0, y: 0 } },
})
);
}
};

const selectModeHandle = (
event: React.MouseEvent<HTMLElement>,
drawType: DrawType
type: DrawType
) => {
dispatch(changeCurrentDrawType({ currentDrawType: drawType }));
dispatch(changeCurrentDrawType({ currentDrawType: type }));
setDrawType(type);
setDrawState(null);
};
const handleSelectDrawState = (
event: React.MouseEvent<HTMLElement>,
state: DrawState
) => {
dispatch(changeCurrentStatus({ drawState: state }));
setDrawState(state);
setDrawType(null);
};
const handleExportLabelMe = () => {
if (currentAnnotationFile && drawObjectById) {
Expand Down Expand Up @@ -350,7 +381,7 @@ const ControlPanel = () => {
<>
<Box sx={{ minWidth: 100 }} display="flex" flexDirection="column" gap={1}>
<ToggleButtonGroup
value={currentDrawType}
value={drawType}
exclusive
onChange={selectModeHandle}
aria-label="mode"
Expand Down Expand Up @@ -387,6 +418,23 @@ const ControlPanel = () => {
<PolylineIcon />
</ToggleButton>
</ToggleButtonGroup>
<ToggleButtonGroup
value={drawState}
exclusive
onChange={handleSelectDrawState}
aria-label="mode"
className="annotationControlPanel"
size="large"
sx={{ border: "1px dashed grey" }}
>
<ToggleButton
className="annotationBtn"
value={DrawState.SELECTING}
aria-label="selecting"
>
<NearMeIcon />
</ToggleButton>
</ToggleButtonGroup>
<Box
display="flex"
mt={3}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { KonvaEventObject } from "konva/lib/Node";
import { useEffect, useRef, useState } from "react";
import { Layer, Rect } from "react-konva";

import Konva from "konva";
import { useDispatch } from "react-redux";
import { setDetectedArea } from "reduxes/annotation/action";
import { DetectedAreaType } from "reduxes/annotation/type";
import { convertStrokeColorToFillColor } from "routes/AnnotationPage/LabelAnnotation/ClassLabel";
import DummyRect from "./DummyRect";

const DetectedRectangleDrawLayer = () => {
const dispatch = useDispatch();
const refDetectedArea = useRef<Konva.Rect | null>(null);
const [localDetectedArea, setLocalDetectedArea] =
useState<DetectedAreaType | null>(null);

const mousedownHandler = (e: KonvaEventObject<MouseEvent>) => {
const position = e.currentTarget.getRelativePointerPosition();
if (position) {
setLocalDetectedArea({
x: position.x,
y: position.y,
width: 3,
height: 3,
});
}
};
const mousemoveHandler = (e: KonvaEventObject<MouseEvent>) => {
const position = e.currentTarget.getRelativePointerPosition();
if (position) {
if (localDetectedArea)
setLocalDetectedArea({
...localDetectedArea,
width: position.x - localDetectedArea.x,
height: position.y - localDetectedArea.y,
});
}
};
const mouseupHandler = (e: KonvaEventObject<MouseEvent>) => {
if (localDetectedArea && refDetectedArea.current) {
dispatch(
setDetectedArea({
detectedArea: { ...refDetectedArea.current.getClientRect() },
})
);
}
setLocalDetectedArea(null);
};
const layer = useRef<Konva.Layer | null>(null);
useEffect(() => {
layer.current?.moveToTop();
}, []);
return (
<Layer
ref={layer}
onMouseMove={mousemoveHandler}
onMouseDown={mousedownHandler}
onMouseUp={mouseupHandler}
>
<DummyRect />
{localDetectedArea && (
<Rect
ref={refDetectedArea}
{...localDetectedArea}
fill={convertStrokeColorToFillColor("#000000")}
strokeWidth={4}
stroke="#000000"
/>
)}
</Layer>
);
};
export default DetectedRectangleDrawLayer;
36 changes: 36 additions & 0 deletions src/routes/AnnotationPage/Editor/Layer/DrawLayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Layer } from "react-konva";
import { useSelector } from "react-redux";
import {
selectorCurrentDrawState,
selectorcurrentDrawType,
} from "reduxes/annotation/selector";
import { DrawState, DrawType } from "reduxes/annotation/type";
import DetectedRectangleDrawLayer from "./DetectedRectangleDrawLayer";
import EllipseDrawLayer from "./EllipseDrawLayer";
import PolygonDrawLayer from "./PolygonDrawLayer";
import RectangleDrawLayer from "./RectangleDrawLayer";

const DrawLayer = () => {
const currentDrawState = useSelector(selectorCurrentDrawState);
const drawType = useSelector(selectorcurrentDrawType);

const render = () => {
if (
currentDrawState === DrawState.FREE ||
currentDrawState === DrawState.DRAWING
) {
if (drawType == DrawType.POLYGON || drawType == DrawType.LINE_STRIP) {
return <PolygonDrawLayer />;
} else if (drawType === DrawType.RECTANGLE) {
return <RectangleDrawLayer />;
} else if (drawType === DrawType.ELLIPSE) {
return <EllipseDrawLayer />;
} else if (drawType === DrawType.DETECTED_RECTANGLE) {
return <DetectedRectangleDrawLayer />;
}
}
return <Layer></Layer>;
};
return render();
};
export default DrawLayer;
13 changes: 13 additions & 0 deletions src/routes/AnnotationPage/Editor/Layer/DummyRect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Rect } from "react-konva";
import { useSelector } from "react-redux";
import { selectorCurrentAnnotationFile } from "reduxes/annotationmanager/selecetor";

const DummyRect = () => {
const currentAnnotationFile = useSelector(selectorCurrentAnnotationFile);
if (currentAnnotationFile) {
const { width, height } = currentAnnotationFile;
return <Rect width={width} height={height} />;
}
return <></>;
};
export default DummyRect;
Loading

0 comments on commit 65af709

Please sign in to comment.