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

Commit 578fa57

Browse files
committed
fix: drag bound for rectangle and ellipse
1 parent 81b0b06 commit 578fa57

7 files changed

Lines changed: 132 additions & 40 deletions

File tree

src/components/Annotation/Editor/Shape/EllipseShape.tsx

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
selectorSelectedEllipse,
1414
} from "reduxes/annotation/selector";
1515
import { DrawObject, DrawState, DrawType } from "reduxes/annotation/type";
16+
import { selectorCurrentImageInEditorProps } from "reduxes/annotationmanager/selecetor";
1617
import { CIRCLE_STYLE, CORNER_RADIUS, LINE_STYLE } from "../const";
1718
import { EllipseCompProps, EllipseProps, EllipseSpec } from "../type";
1819
import useCommonShapeEvent from "../useCommonShapeEvent";
@@ -47,7 +48,9 @@ function EllipseComp({
4748
const commonShapeEvent = useCommonShapeEvent({ drawObject: spec });
4849
const currentDrawState = useSelector(selectorCurrentDrawState);
4950
const drawObjectState = useSelector(selectorDrawObjectState(spec.id));
50-
51+
const currentImageInEditorProps = useSelector(
52+
selectorCurrentImageInEditorProps
53+
);
5154
const [strokeWidth, setStrokeWidth] = useState<number>(
5255
spec.cssStyle.strokeWidth
5356
);
@@ -75,28 +78,62 @@ function EllipseComp({
7578
trRef.current.getLayer().batchDraw();
7679
}
7780
}, [isSelected]);
78-
const [stage, setStage] = useState<Konva.Stage | null>(null);
7981

8082
const groupDragBound = (pos: Vector2d) => {
8183
let { x, y } = pos;
82-
const sw = stage ? stage.width() : 0;
83-
const sh = stage ? stage.height() : 0;
84-
if (shapeRef && shapeRef.current) {
84+
if (shapeRef && shapeRef.current && currentImageInEditorProps) {
85+
const { clientRectOfBaseImage } = currentImageInEditorProps;
8586
const box = shapeRef.current.getClientRect();
8687

87-
if (y - box.height / 2 < 0) y = box.height / 2;
88-
if (x - box.width / 2 < 0) x = box.width / 2;
89-
if (y + box.height / 2 > sh) y = sh - box.height / 2;
90-
if (x + box.width / 2 > sw) x = sw - box.width / 2;
91-
return { x, y };
88+
if (clientRectOfBaseImage) {
89+
if (x - box.width / 2 < clientRectOfBaseImage.x) {
90+
x = clientRectOfBaseImage.x + box.width / 2;
91+
}
92+
if (y - box.height / 2 < clientRectOfBaseImage.y) {
93+
y = clientRectOfBaseImage.y + box.height / 2;
94+
}
95+
if (
96+
x + box.width >
97+
clientRectOfBaseImage.x + clientRectOfBaseImage.width
98+
) {
99+
x =
100+
clientRectOfBaseImage.x +
101+
clientRectOfBaseImage.width -
102+
box.width / 2;
103+
}
104+
if (
105+
y + box.height >
106+
clientRectOfBaseImage.y + clientRectOfBaseImage.height
107+
) {
108+
y =
109+
clientRectOfBaseImage.y +
110+
clientRectOfBaseImage.height -
111+
box.height / 2;
112+
}
113+
}
92114
}
93-
return { x: 0, y: 0 };
94-
};
95115

96-
const handleDragStart = (e: KonvaEventObject<DragEvent>) => {
97-
setStage(e.target.getStage());
98-
commonShapeEvent.handleDragStart(e);
116+
return {
117+
x,
118+
y,
119+
};
99120
};
121+
// const groupDragBound = (pos: Vector2d) => {
122+
// let { x, y } = pos;
123+
// const sw = stage ? stage.width() : 0;
124+
// const sh = stage ? stage.height() : 0;
125+
// if (shapeRef && shapeRef.current) {
126+
// const box = shapeRef.current.getClientRect();
127+
128+
// if (y - box.height / 2 < 0) y = box.height / 2;
129+
// if (x - box.width / 2 < 0) x = box.width / 2;
130+
// if (y + box.height / 2 > sh) y = sh - box.height / 2;
131+
// if (x + box.width / 2 > sw) x = sw - box.width / 2;
132+
// return { x, y };
133+
// }
134+
// return { x: 0, y: 0 };
135+
// };
136+
100137
const handleTransformEnd = (e: KonvaEventObject<Event>) => {
101138
const node = shapeRef.current;
102139
if (!node) return;
@@ -150,7 +187,6 @@ function EllipseComp({
150187
onMouseOut={onMouseOut}
151188
draggable={commonShapeEvent.isLock !== true}
152189
onDragEnd={handleDragEnd}
153-
onDragStart={handleDragStart}
154190
onTransformEnd={handleTransformEnd}
155191
strokeScaleEnabled={false}
156192
{...spec}

src/components/Annotation/Editor/Shape/Rectangle.tsx

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -78,31 +78,38 @@ function RectangleComp({
7878
trRef.current.getLayer().batchDraw();
7979
}
8080
}, [isSelected]);
81-
const [stage, setStage] = useState<Konva.Stage | null>(null);
82-
8381
const groupDragBound = (pos: Vector2d) => {
84-
if (currentImageInEditorProps) {
85-
let { x, y } = pos;
86-
const sw = stage ? currentImageInEditorProps.width : 0;
87-
const sh = stage ? currentImageInEditorProps.height : 0;
88-
if (shapeRef && shapeRef.current) {
82+
let { x, y } = pos;
83+
if (shapeRef && shapeRef.current && currentImageInEditorProps) {
84+
const { clientRectOfBaseImage } = currentImageInEditorProps;
85+
if (clientRectOfBaseImage) {
86+
if (x < clientRectOfBaseImage.x) {
87+
x = clientRectOfBaseImage.x;
88+
}
89+
if (y < clientRectOfBaseImage.y) {
90+
y = clientRectOfBaseImage.y;
91+
}
8992
const box = shapeRef.current.getClientRect();
90-
const minMaxX = [-currentImageInEditorProps.paddingLeft, box.width];
91-
const minMaxY = [-currentImageInEditorProps.paddingTop, box.height];
92-
93-
if (minMaxY[0] + y < 0) y = -1 * minMaxY[0];
94-
if (minMaxX[0] + x < 0) x = -1 * minMaxX[0];
95-
if (minMaxY[1] + y > sh) y = sh - minMaxY[1];
96-
if (minMaxX[1] + x > sw) x = sw - minMaxX[1];
97-
return { x, y };
93+
if (
94+
x + box.width >
95+
clientRectOfBaseImage.x + clientRectOfBaseImage.width
96+
) {
97+
x = clientRectOfBaseImage.x + clientRectOfBaseImage.width - box.width;
98+
}
99+
if (
100+
y + box.height >
101+
clientRectOfBaseImage.y + clientRectOfBaseImage.height
102+
) {
103+
y =
104+
clientRectOfBaseImage.y + clientRectOfBaseImage.height - box.height;
105+
}
98106
}
99107
}
100-
return { x: 0, y: 0 };
101-
};
102108

103-
const handleDragStart = (e: KonvaEventObject<DragEvent>) => {
104-
setStage(e.target.getStage());
105-
commonShapeEvent.handleDragStart(e);
109+
return {
110+
x,
111+
y,
112+
};
106113
};
107114
const handleDragEnd = (e: KonvaEventObject<DragEvent>) => {
108115
onChange({
@@ -157,7 +164,6 @@ function RectangleComp({
157164
onMouseOut={onMouseOut}
158165
draggable={commonShapeEvent.isLock !== true}
159166
onDragEnd={handleDragEnd}
160-
onDragStart={handleDragStart}
161167
onTransformEnd={handleTransformEnd}
162168
strokeScaleEnabled={false}
163169
{...spec}

src/reduxes/annotationmanager/action.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
SAVE_ANNOTATION_STATE_MANAGER,
1010
SAVE_REMOTE_NEW_CLASS_LABEL,
1111
SET_ANNOTATION_STATE_MANAGER,
12+
SET_CLIENT_RECT_OF_BASE_IMAGE,
1213
SET_CLASS_MANAGE_MODAL,
1314
SET_PREVIEW_IMAGE,
1415
} from "./constants";
@@ -21,6 +22,7 @@ import {
2122
EditClassManageModalProps,
2223
FetchingFileAndAnnotaitonProps,
2324
SaveAnnotationStateManagerProps,
25+
SetClientRectOfBaseImageProps,
2426
} from "./type";
2527

2628
export const addImagesToAnnotation = (payload: AddImageToAnnotationProps) => ({
@@ -86,3 +88,9 @@ export const fetchingFileAndAnnotaiton = (
8688
export const resetAnnotationManager = () => ({
8789
type: RESET_ANNOTATION_MANAGER,
8890
});
91+
export const setClientRectOfBaseImage = (
92+
payload: SetClientRectOfBaseImageProps
93+
) => ({
94+
type: SET_CLIENT_RECT_OF_BASE_IMAGE,
95+
payload,
96+
});

src/reduxes/annotationmanager/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ export const FETCH_FILE_AND_ANNOTATION = asyncAction(
1616
);
1717
export const SAVE_REMOTE_NEW_CLASS_LABEL = asyncAction("SAVE_NEW_CLASS_LABEL");
1818
export const RESET_ANNOTATION_MANAGER = "RESET_ANNOTATION_MANAGER";
19+
export const SET_CLIENT_RECT_OF_BASE_IMAGE = "SET_CLIENT_RECT_OF_BASE_IMAGE";

src/reduxes/annotationmanager/reducer.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
RESET_ANNOTATION_MANAGER,
1414
SAVE_ANNOTATION_STATE_MANAGER,
1515
SET_ANNOTATION_STATE_MANAGER,
16+
SET_CLIENT_RECT_OF_BASE_IMAGE,
1617
SET_CLASS_MANAGE_MODAL,
1718
SET_PREVIEW_IMAGE,
1819
} from "./constants";
@@ -25,6 +26,7 @@ import {
2526
EditClassLabelProps,
2627
EditClassManageModalProps,
2728
SaveAnnotationStateManagerProps,
29+
SetClientRectOfBaseImageProps,
2830
} from "./type";
2931

3032
const inititalState: AnnotationManagerReducer = {
@@ -87,7 +89,7 @@ const annotationManagerReducer = (
8789
}
8890
const scaleX = newWidth / width;
8991
const scaleY = newHeight / height;
90-
const paddingLeft = (MAX_WIDTH_EDITOR - newHeight) / scaleX / 2.0;
92+
const paddingLeft = (MAX_WIDTH_EDITOR - newWidth) / scaleX / 2.0;
9193
const paddingTop = (MAX_HEIGHT_EDITOR - newHeight) / scaleY / 2.0;
9294
return {
9395
...state,
@@ -98,6 +100,7 @@ const annotationManagerReducer = (
98100
height: newHeight,
99101
paddingLeft,
100102
paddingTop,
103+
clientRectOfBaseImage: null,
101104
},
102105
isFetchingImageData: false,
103106
};
@@ -109,6 +112,20 @@ const annotationManagerReducer = (
109112
isFetchingImageData: false,
110113
};
111114
}
115+
case SET_CLIENT_RECT_OF_BASE_IMAGE: {
116+
const { clientRectOfBaseImage } =
117+
payload as SetClientRectOfBaseImageProps;
118+
if (state.currentImageInEditorProps) {
119+
return {
120+
...state,
121+
currentImageInEditorProps: {
122+
...state.currentImageInEditorProps,
123+
clientRectOfBaseImage,
124+
},
125+
};
126+
}
127+
return state;
128+
}
112129
case CHANGE_PREVIEW_IMAGE.FAILED: {
113130
return {
114131
...state,

src/reduxes/annotationmanager/type.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ export interface ImageInEditorProps {
1818
height: number;
1919
paddingLeft: number;
2020
paddingTop: number;
21+
clientRectOfBaseImage: ClientRectType | null;
22+
}
23+
export interface ClientRectType {
24+
width: number;
25+
height: number;
26+
x: number;
27+
y: number;
2128
}
2229

2330
export type ClassManageModalType = "VIEW" | "CREATE" | "EDIT";
@@ -61,3 +68,6 @@ export interface FetchingFileAndAnnotaitonProps {
6168
s3keyLabel: string;
6269
s3keyFile: string;
6370
}
71+
export interface SetClientRectOfBaseImageProps {
72+
clientRectOfBaseImage: ClientRectType;
73+
}

src/routes/AnnotationPage/Editor/BaseImage/index.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
import { useEffect, useState } from "react";
1+
import Konva from "konva";
2+
import { useEffect, useRef, useState } from "react";
23
import { Image } from "react-konva";
3-
import { useSelector } from "react-redux";
4+
import { useDispatch, useSelector } from "react-redux";
5+
import { setClientRectOfBaseImage } from "reduxes/annotationmanager/action";
46
import { selectorCurrentAnnotationFile } from "reduxes/annotationmanager/selecetor";
57

68
export default function BaseImage() {
9+
const dispatch = useDispatch();
710
const currentAnnotationFile = useSelector(selectorCurrentAnnotationFile);
811
const [image, setImage] = useState<HTMLImageElement>();
12+
const ref = useRef<Konva.Image | null>(null);
913

1014
useEffect(() => {
1115
if (currentAnnotationFile) {
@@ -14,9 +18,19 @@ export default function BaseImage() {
1418
setImage(element);
1519
}
1620
}, [currentAnnotationFile]);
21+
useEffect(() => {
22+
if (image && ref.current) {
23+
dispatch(
24+
setClientRectOfBaseImage({
25+
clientRectOfBaseImage: ref.current.getClientRect(),
26+
})
27+
);
28+
}
29+
}, [image]);
1730

1831
return (
1932
<Image
33+
ref={ref}
2034
image={image}
2135
width={currentAnnotationFile?.width}
2236
height={currentAnnotationFile?.height}

0 commit comments

Comments
 (0)