@deepnoid/canvas 0.1.37 → 0.1.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/components/{AnnotationViewer → AnnotationCanvas}/_hooks/useImagePanZoom.d.ts +7 -13
  2. package/dist/components/{AnnotationViewer → AnnotationCanvas}/_hooks/useImagePanZoom.js +33 -23
  3. package/dist/components/AnnotationCanvas/_utils/createHistory.d.ts +11 -0
  4. package/dist/components/AnnotationCanvas/_utils/createHistory.js +34 -0
  5. package/dist/components/AnnotationCanvas/_utils/panZoom.d.ts +10 -0
  6. package/dist/components/AnnotationCanvas/_utils/panZoom.js +29 -0
  7. package/dist/components/AnnotationCanvas/index.d.ts +25 -0
  8. package/dist/components/AnnotationCanvas/index.js +83 -0
  9. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangle.d.ts +5 -0
  10. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangle.js +75 -0
  11. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangleUtils.d.ts +30 -0
  12. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangleUtils.js +211 -0
  13. package/dist/components/AnnotationLayer/_hooks/drawEvents/useDrawEvents.d.ts +25 -0
  14. package/dist/components/AnnotationLayer/_hooks/drawEvents/useDrawEvents.js +42 -0
  15. package/dist/components/AnnotationLayer/_hooks/useCanvasDraw.d.ts +13 -0
  16. package/dist/components/AnnotationLayer/_hooks/useCanvasDraw.js +115 -0
  17. package/dist/components/AnnotationLayer/_hooks/useHotkeys.d.ts +7 -0
  18. package/dist/components/AnnotationLayer/_hooks/useHotkeys.js +15 -0
  19. package/dist/components/AnnotationLayer/_hooks/useMouse.d.ts +21 -0
  20. package/dist/components/AnnotationLayer/_hooks/useMouse.js +34 -0
  21. package/dist/components/AnnotationLayer/index.d.ts +10 -13
  22. package/dist/components/AnnotationLayer/index.js +116 -22
  23. package/dist/components/index.d.ts +8 -0
  24. package/dist/components/index.js +8 -0
  25. package/dist/enum/common.d.ts +13 -0
  26. package/dist/enum/common.js +15 -0
  27. package/dist/index.d.ts +5 -4
  28. package/dist/index.js +2 -2
  29. package/dist/types/index.d.ts +58 -0
  30. package/dist/utils/canvas.d.ts +3 -0
  31. package/dist/utils/canvas.js +37 -0
  32. package/dist/utils/common/cloneDeep.d.ts +1 -0
  33. package/dist/utils/common/cloneDeep.js +18 -0
  34. package/dist/utils/common/cloneDeepWith.d.ts +1 -0
  35. package/dist/utils/common/cloneDeepWith.js +34 -0
  36. package/dist/utils/common/isEqualWith.d.ts +2 -0
  37. package/dist/utils/common/isEqualWith.js +70 -0
  38. package/dist/utils/mouseActions.d.ts +8 -0
  39. package/dist/utils/mouseActions.js +19 -0
  40. package/dist/utils/pointTransform.d.ts +2 -0
  41. package/dist/utils/pointTransform.js +46 -0
  42. package/package.json +2 -1
  43. package/dist/components/AnnotationViewer/index.d.ts +0 -22
  44. package/dist/components/AnnotationViewer/index.js +0 -80
  45. package/dist/constants/graphic.d.ts +0 -1
  46. package/dist/constants/graphic.js +0 -1
  47. package/dist/types/coordinate.d.ts +0 -10
  48. package/dist/utils/graphic.d.ts +0 -48
  49. package/dist/utils/graphic.js +0 -158
  50. /package/dist/types/{coordinate.js → index.js} +0 -0
@@ -0,0 +1,211 @@
1
+ import { MouseAction } from '../../../../utils/mouseActions';
2
+ import { cloneDeep } from '../../../../utils/common/cloneDeep';
3
+ import { DrawMode, RectangleAnchor } from '../../../../enum/common';
4
+ import { getMousePointTransform } from '../../../../utils/pointTransform';
5
+ export const ACTIVE_POINT_SIZE = 10;
6
+ export const getRectangleCorners = ({ x, y, width, height }) => {
7
+ return [
8
+ { x, y },
9
+ { x: x + width, y },
10
+ { x, y: y + height },
11
+ { x: x + width, y: y + height },
12
+ ];
13
+ };
14
+ export const selectRectangleAtPoint = (zoom, mousePoint, coordinatesRef, currentCoordinateRef) => {
15
+ const coordinates = coordinatesRef.current;
16
+ const { x: mouseX, y: mouseY } = mousePoint;
17
+ const padding = ACTIVE_POINT_SIZE / zoom;
18
+ const isPointInBBox = (c) => mouseX >= c.x - padding &&
19
+ mouseX <= c.x + c.width + padding &&
20
+ mouseY >= c.y - padding &&
21
+ mouseY <= c.y + c.height + padding;
22
+ let selectedIndex = -1;
23
+ let minArea = Number.MAX_SAFE_INTEGER;
24
+ const currentIndex = coordinates.findIndex((c) => c.selected);
25
+ if (currentIndex >= 0) {
26
+ const c = coordinates[currentIndex];
27
+ if (c.type === DrawMode.RECTANGLE && isPointInBBox(c)) {
28
+ selectedIndex = currentIndex;
29
+ minArea = c.width * c.height;
30
+ }
31
+ }
32
+ if (selectedIndex === -1) {
33
+ coordinates.forEach((c, idx) => {
34
+ if (c.type !== DrawMode.RECTANGLE || !isPointInBBox(c))
35
+ return;
36
+ const area = c.width * c.height;
37
+ if (area < minArea) {
38
+ minArea = area;
39
+ selectedIndex = idx;
40
+ }
41
+ });
42
+ }
43
+ coordinates.forEach((c) => (c.selected = false));
44
+ if (selectedIndex >= 0) {
45
+ coordinates[selectedIndex].selected = true;
46
+ currentCoordinateRef.current = coordinates[selectedIndex];
47
+ }
48
+ else {
49
+ currentCoordinateRef.current = null;
50
+ }
51
+ };
52
+ export const updateActiveRectangleAnchor = (zoom, mousePointRef, currentCoordinateRef, rectangleAnchorRef) => {
53
+ if (!currentCoordinateRef.current)
54
+ return;
55
+ const points = getRectangleCorners(currentCoordinateRef.current);
56
+ const pointSize = ACTIVE_POINT_SIZE / zoom;
57
+ const { x: mouseX, y: mouseY } = mousePointRef;
58
+ const { x, y, width: w, height: h } = currentCoordinateRef.current;
59
+ if (mouseX >= points[0].x - pointSize / 2 &&
60
+ mouseX <= points[0].x + pointSize / 2 &&
61
+ mouseY >= points[0].y - pointSize / 2 &&
62
+ mouseY <= points[0].y + pointSize / 2) {
63
+ rectangleAnchorRef.current = RectangleAnchor.LEFT_TOP;
64
+ }
65
+ else if (mouseX >= points[1].x - pointSize / 2 &&
66
+ mouseX <= points[1].x + pointSize / 2 &&
67
+ mouseY >= points[1].y - pointSize / 2 &&
68
+ mouseY <= points[1].y + pointSize / 2) {
69
+ rectangleAnchorRef.current = RectangleAnchor.RIGHT_TOP;
70
+ }
71
+ else if (mouseX >= points[2].x - pointSize / 2 &&
72
+ mouseX <= points[2].x + pointSize / 2 &&
73
+ mouseY >= points[2].y - pointSize / 2 &&
74
+ mouseY <= points[2].y + pointSize / 2) {
75
+ rectangleAnchorRef.current = RectangleAnchor.LEFT_BOTTOM;
76
+ }
77
+ else if (mouseX >= points[3].x - pointSize / 2 &&
78
+ mouseX <= points[3].x + pointSize / 2 &&
79
+ mouseY >= points[3].y - pointSize / 2 &&
80
+ mouseY <= points[3].y + pointSize / 2) {
81
+ rectangleAnchorRef.current = RectangleAnchor.RIGHT_BOTTOM;
82
+ }
83
+ else if (mouseX >= x && mouseX <= x + w && mouseY >= y - pointSize / 2 && mouseY <= y + pointSize / 2) {
84
+ rectangleAnchorRef.current = RectangleAnchor.TOP;
85
+ }
86
+ else if (mouseX >= x && mouseX <= x + w && mouseY >= y + h - pointSize / 2 && mouseY <= y + h + pointSize / 2) {
87
+ rectangleAnchorRef.current = RectangleAnchor.BOTTOM;
88
+ }
89
+ else if (mouseY >= y && mouseY <= y + h && mouseX >= x - pointSize / 2 && mouseX <= x + pointSize / 2) {
90
+ rectangleAnchorRef.current = RectangleAnchor.LEFT;
91
+ }
92
+ else if (mouseY >= y && mouseY <= y + h && mouseX >= x + w - pointSize / 2 && mouseX <= x + w + pointSize / 2) {
93
+ rectangleAnchorRef.current = RectangleAnchor.RIGHT;
94
+ }
95
+ else {
96
+ rectangleAnchorRef.current = null;
97
+ }
98
+ };
99
+ export const createCoordinate = (coordinate, setCoordinates, coordinatesRef, historyRef, currentCoordinateRef) => {
100
+ coordinatesRef.current.push(coordinate);
101
+ historyRef.current.add(cloneDeep(coordinatesRef.current));
102
+ setCoordinates(coordinatesRef.current);
103
+ currentCoordinateRef.current = null;
104
+ };
105
+ export const clampBoundingBoxToImage = (x, y, width, height, dw, dh) => {
106
+ let correctedX = x;
107
+ let correctedY = y;
108
+ let correctedWidth = width;
109
+ let correctedHeight = height;
110
+ if (x + width > dw)
111
+ correctedWidth = dw - x;
112
+ if (y + height > dh)
113
+ correctedHeight = dh - y;
114
+ if (x < 0) {
115
+ correctedWidth = width + x;
116
+ correctedX = 0;
117
+ }
118
+ if (y < 0) {
119
+ correctedHeight = height + y;
120
+ correctedY = 0;
121
+ }
122
+ return {
123
+ x: correctedX,
124
+ y: correctedY,
125
+ width: Math.max(0, correctedWidth),
126
+ height: Math.max(0, correctedHeight),
127
+ selected: false,
128
+ };
129
+ };
130
+ export const getCanvasMousePoint = (event, canvas, canvasState) => {
131
+ const rect = canvas.getBoundingClientRect();
132
+ const { moveX, moveY, zoomX, zoomY, zoom, dx, dy } = canvasState;
133
+ const mouseX = event.clientX - rect.left;
134
+ const mouseY = event.clientY - rect.top;
135
+ return getMousePointTransform({ x: mouseX, y: mouseY, selected: false }, { x: moveX, y: moveY, selected: false }, { x: zoomX, y: zoomY, selected: false }, { x: dx, y: dy, selected: false }, zoom, canvas);
136
+ };
137
+ const moveBBox = ({ coordinatesRef, dw, dh, mousePoint, prevMousePoint, mouseAction, currentCoordinate, rectangleAnchor, }) => {
138
+ if (mouseAction === MouseAction.LEFT &&
139
+ currentCoordinate &&
140
+ rectangleAnchor === null &&
141
+ mousePoint &&
142
+ prevMousePoint) {
143
+ const findIndex = coordinatesRef.current.findIndex((coordinate) => coordinate.selected);
144
+ const findCoordinate = coordinatesRef.current[findIndex];
145
+ if (findIndex >= 0 && findCoordinate) {
146
+ const newX = currentCoordinate.x + mousePoint.x - prevMousePoint.x;
147
+ const newY = currentCoordinate.y + mousePoint.y - prevMousePoint.y;
148
+ findCoordinate.x = Math.max(0, Math.min(newX, dw - findCoordinate.width));
149
+ findCoordinate.y = Math.max(0, Math.min(newY, dh - findCoordinate.height));
150
+ }
151
+ }
152
+ };
153
+ const editBBox = ({ dw, dh, mousePoint, prevMousePoint, mouseAction, currentCoordinate, rectangleAnchor, coordinatesRef, }) => {
154
+ if (rectangleAnchor && mouseAction === MouseAction.LEFT && currentCoordinate && mousePoint && prevMousePoint) {
155
+ const findIndex = coordinatesRef.current.findIndex((coordinate) => coordinate.selected);
156
+ const findCoordinate = coordinatesRef.current[findIndex];
157
+ if (findIndex >= 0 && findCoordinate) {
158
+ const dx = mousePoint.x - prevMousePoint.x;
159
+ const dy = mousePoint.y - prevMousePoint.y;
160
+ switch (rectangleAnchor) {
161
+ case RectangleAnchor.LEFT_TOP:
162
+ findCoordinate.x += dx;
163
+ findCoordinate.y += dy;
164
+ findCoordinate.width -= dx;
165
+ findCoordinate.height -= dy;
166
+ break;
167
+ case RectangleAnchor.RIGHT_TOP:
168
+ findCoordinate.y += dy;
169
+ findCoordinate.width += dx;
170
+ findCoordinate.height -= dy;
171
+ break;
172
+ case RectangleAnchor.LEFT_BOTTOM:
173
+ findCoordinate.x += dx;
174
+ findCoordinate.width -= dx;
175
+ findCoordinate.height += dy;
176
+ break;
177
+ case RectangleAnchor.RIGHT_BOTTOM:
178
+ findCoordinate.width += dx;
179
+ findCoordinate.height += dy;
180
+ break;
181
+ case RectangleAnchor.TOP:
182
+ findCoordinate.y += dy;
183
+ findCoordinate.height -= dy;
184
+ break;
185
+ case RectangleAnchor.BOTTOM:
186
+ findCoordinate.height += dy;
187
+ break;
188
+ case RectangleAnchor.LEFT:
189
+ findCoordinate.x += dx;
190
+ findCoordinate.width -= dx;
191
+ break;
192
+ case RectangleAnchor.RIGHT:
193
+ findCoordinate.width += dx;
194
+ break;
195
+ default:
196
+ break;
197
+ }
198
+ findCoordinate.x = Math.max(0, Math.min(findCoordinate.x, dw - findCoordinate.width));
199
+ findCoordinate.y = Math.max(0, Math.min(findCoordinate.y, dh - findCoordinate.height));
200
+ findCoordinate.width = Math.max(0, Math.min(findCoordinate.width, dw - findCoordinate.x));
201
+ findCoordinate.height = Math.max(0, Math.min(findCoordinate.height, dh - findCoordinate.y));
202
+ }
203
+ }
204
+ };
205
+ export const handleBBoxOperations = (params) => {
206
+ moveBBox(params);
207
+ editBBox(params);
208
+ };
209
+ export const isInsideImage = (point, imageWidth, imageHeight) => {
210
+ return point.x >= 0 && point.y >= 0 && point.x <= imageWidth && point.y <= imageHeight;
211
+ };
@@ -0,0 +1,25 @@
1
+ import { RefObject } from 'react';
2
+ import { Point, Coordinate, EditableCoordinate, CanvasState, Label } from '../../../../types';
3
+ import { CoordinateHistory } from '../../../AnnotationCanvas/_utils/createHistory';
4
+ import { DrawMode, RectangleAnchor } from '../../../../enum/common';
5
+ import { MouseAction } from '../../../../utils/mouseActions';
6
+ export type DrawEventsParams = {
7
+ canvasRef: RefObject<HTMLCanvasElement | null>;
8
+ canvasStateRef: RefObject<CanvasState>;
9
+ mousePointRef: RefObject<Point>;
10
+ setMousePoint: (point: Point) => void;
11
+ mouseActionRef: RefObject<MouseAction | null>;
12
+ startMousePointRef: RefObject<Point | null>;
13
+ prevMousePointRef: RefObject<Point | null>;
14
+ currentCoordinateRef: RefObject<Coordinate | null>;
15
+ coordinatesRef: RefObject<EditableCoordinate[]>;
16
+ setCoordinates: (coordinates: EditableCoordinate[]) => void;
17
+ rectangleAnchorRef: RefObject<RectangleAnchor | null>;
18
+ historyRef: RefObject<CoordinateHistory>;
19
+ maskImageRef: RefObject<HTMLImageElement | null>;
20
+ drawLabel?: Label;
21
+ };
22
+ export declare const useDrawEvents: (params: DrawEventsParams & {
23
+ selectedDrawMode?: DrawMode;
24
+ editable: boolean;
25
+ }) => void;
@@ -0,0 +1,42 @@
1
+ import { useEffect } from 'react';
2
+ import * as Rectangle from './rectangle';
3
+ import { DrawMode } from '../../../../enum/common';
4
+ export const useDrawEvents = (params) => {
5
+ const { canvasRef, setMousePoint, startMousePointRef, currentCoordinateRef, coordinatesRef, setCoordinates, maskImageRef, selectedDrawMode, editable, } = params;
6
+ const initSelector = (coordinates) => {
7
+ coordinates.map((coordinate) => {
8
+ coordinate.selected = false;
9
+ return coordinate;
10
+ });
11
+ return coordinates;
12
+ };
13
+ useEffect(() => {
14
+ if (!canvasRef.current || !editable || !selectedDrawMode)
15
+ return;
16
+ const handlers = selectedDrawMode === DrawMode.RECTANGLE
17
+ ? {
18
+ down: Rectangle.handleMouseDownRectangle(params),
19
+ move: Rectangle.handleMouseMoveRectangle(params),
20
+ up: Rectangle.handleMouseUpRectangle(params),
21
+ leave: Rectangle.handleMouseLeaveRectangle(params),
22
+ }
23
+ : null;
24
+ if (!handlers)
25
+ return;
26
+ canvasRef.current.addEventListener('mousedown', handlers.down);
27
+ canvasRef.current.addEventListener('mousemove', handlers.move);
28
+ canvasRef.current.addEventListener('mouseup', handlers.up);
29
+ canvasRef.current.addEventListener('mouseleave', handlers.leave);
30
+ setMousePoint({ x: 0, y: 0, selected: false });
31
+ setCoordinates(initSelector(coordinatesRef.current));
32
+ currentCoordinateRef.current = null;
33
+ startMousePointRef.current = null;
34
+ maskImageRef.current = new Image();
35
+ return () => {
36
+ canvasRef.current?.removeEventListener('mousedown', handlers.down);
37
+ canvasRef.current?.removeEventListener('mousemove', handlers.move);
38
+ canvasRef.current?.removeEventListener('mouseup', handlers.up);
39
+ canvasRef.current?.removeEventListener('mouseleave', handlers.leave);
40
+ };
41
+ }, [canvasRef, selectedDrawMode]);
42
+ };
@@ -0,0 +1,13 @@
1
+ import { RefObject } from 'react';
2
+ import { EditableCoordinate, Point } from '../../../types';
3
+ type UseCanvasDrawParams = {
4
+ drawLineSize: number;
5
+ drawColor?: string;
6
+ };
7
+ export declare function useCanvasDraw({ drawLineSize, drawColor }: UseCanvasDrawParams): {
8
+ drawCross: (context: CanvasRenderingContext2D, dw: number, dh: number, zoom: number, point: Point) => void;
9
+ drawActiveRect: (context: CanvasRenderingContext2D, coordinate: EditableCoordinate, zoom: number) => void;
10
+ drawRectFromPoints: (context: CanvasRenderingContext2D, startPoint: Point, endPoint: Point, zoom: number, color?: string | undefined) => void;
11
+ setCursorStyle: (canvas: HTMLCanvasElement, mousePointRef: RefObject<Point>, coordinate: EditableCoordinate, zoom: number) => void;
12
+ };
13
+ export {};
@@ -0,0 +1,115 @@
1
+ import { ACTIVE_POINT_SIZE, getRectangleCorners } from './drawEvents/rectangleUtils';
2
+ export function useCanvasDraw({ drawLineSize, drawColor }) {
3
+ const drawCross = (context, dw, dh, zoom, point) => {
4
+ if (point.x > 0 && point.y > 0 && point.x < dw && point.y < dh) {
5
+ if (context)
6
+ context.lineWidth = (drawLineSize / 2) * (1 / zoom);
7
+ context?.setLineDash([5]);
8
+ context?.beginPath();
9
+ context?.moveTo(point.x, 0);
10
+ context?.lineTo(point.x, dh);
11
+ if (context)
12
+ context.strokeStyle = '#001f3f';
13
+ context?.stroke();
14
+ context?.beginPath();
15
+ context?.moveTo(0, point.y);
16
+ context?.lineTo(dw, point.y);
17
+ if (context)
18
+ context.strokeStyle = '#001f3f';
19
+ context?.stroke();
20
+ }
21
+ };
22
+ const drawActiveRect = (context, coordinate, zoom) => {
23
+ const { x, y, width, height, selected } = coordinate;
24
+ if (!(selected && x && y && width && height))
25
+ return;
26
+ context.lineWidth = drawLineSize / zoom;
27
+ context.fillStyle = '#FFF';
28
+ const pointSize = ACTIVE_POINT_SIZE / zoom;
29
+ const points = getRectangleCorners({ x, y, width, height });
30
+ points.forEach((point) => {
31
+ context.fillStyle = '#FFF';
32
+ context.fillRect(point.x - pointSize / 2, point.y - pointSize / 2, pointSize, pointSize);
33
+ context.strokeStyle = '#000';
34
+ context.lineWidth = 1 / zoom;
35
+ context.strokeRect(point.x - pointSize / 2, point.y - pointSize / 2, pointSize, pointSize);
36
+ });
37
+ };
38
+ const drawRectFromPoints = (context, startPoint, endPoint, zoom, color = drawColor) => {
39
+ if (!color)
40
+ return;
41
+ const x = Math.min(endPoint.x, startPoint.x);
42
+ const y = Math.min(endPoint.y, startPoint.y);
43
+ const width = Math.abs(endPoint.x - startPoint.x);
44
+ const height = Math.abs(endPoint.y - startPoint.y);
45
+ context.beginPath();
46
+ context.lineWidth = drawLineSize / zoom;
47
+ context.rect(x, y, width, height);
48
+ context.strokeStyle = color;
49
+ context.stroke();
50
+ };
51
+ const setCursorStyle = (canvas, mousePointRef, coordinate, zoom) => {
52
+ if (coordinate.selected) {
53
+ let cursorStyle = 'default';
54
+ const pointSize = ACTIVE_POINT_SIZE / zoom;
55
+ const mouseX = mousePointRef.current.x;
56
+ const mouseY = mousePointRef.current.y;
57
+ const { x, y, width: w, height: h } = coordinate;
58
+ if (x && y && w && h) {
59
+ const points = getRectangleCorners({ x, y, width: w, height: h });
60
+ if (mouseX >= points[0].x - pointSize / 2 &&
61
+ mouseX <= points[0].x + pointSize / 2 &&
62
+ mouseY >= points[0].y - pointSize / 2 &&
63
+ mouseY <= points[0].y + pointSize / 2) {
64
+ cursorStyle = 'nwse-resize';
65
+ }
66
+ else if (mouseX >= points[1].x - pointSize / 2 &&
67
+ mouseX <= points[1].x + pointSize / 2 &&
68
+ mouseY >= points[1].y - pointSize / 2 &&
69
+ mouseY <= points[1].y + pointSize / 2) {
70
+ cursorStyle = 'nesw-resize';
71
+ }
72
+ else if (mouseX >= points[2].x - pointSize / 2 &&
73
+ mouseX <= points[2].x + pointSize / 2 &&
74
+ mouseY >= points[2].y - pointSize / 2 &&
75
+ mouseY <= points[2].y + pointSize / 2) {
76
+ cursorStyle = 'nesw-resize';
77
+ }
78
+ else if (mouseX >= points[3].x - pointSize / 2 &&
79
+ mouseX <= points[3].x + pointSize / 2 &&
80
+ mouseY >= points[3].y - pointSize / 2 &&
81
+ mouseY <= points[3].y + pointSize / 2) {
82
+ cursorStyle = 'nwse-resize';
83
+ }
84
+ else if (mouseX >= x && mouseX <= x + w && mouseY >= y - pointSize / 2 && mouseY <= y + pointSize / 2) {
85
+ cursorStyle = 'ns-resize';
86
+ }
87
+ else if (mouseX >= x &&
88
+ mouseX <= x + w &&
89
+ mouseY >= y + h - pointSize / 2 &&
90
+ mouseY <= y + h + pointSize / 2) {
91
+ cursorStyle = 'ns-resize';
92
+ }
93
+ else if (mouseY >= y && mouseY <= y + h && mouseX >= x - pointSize / 2 && mouseX <= x + pointSize / 2) {
94
+ cursorStyle = 'ew-resize';
95
+ }
96
+ else if (mouseY >= y &&
97
+ mouseY <= y + h &&
98
+ mouseX >= x + w - pointSize / 2 &&
99
+ mouseX <= x + w + pointSize / 2) {
100
+ cursorStyle = 'ew-resize';
101
+ }
102
+ else {
103
+ cursorStyle = 'default';
104
+ }
105
+ }
106
+ canvas.style.cursor = cursorStyle;
107
+ }
108
+ };
109
+ return {
110
+ drawCross,
111
+ drawActiveRect,
112
+ drawRectFromPoints,
113
+ setCursorStyle,
114
+ };
115
+ }
@@ -0,0 +1,7 @@
1
+ type Props = {
2
+ onDelete: () => void;
3
+ toggleSelectionOnly: () => void;
4
+ onUndoRedo: (isRedo: boolean) => void;
5
+ };
6
+ export declare function useHotkeys({ onDelete, toggleSelectionOnly, onUndoRedo }: Props): void;
7
+ export {};
@@ -0,0 +1,15 @@
1
+ import { useEffect } from 'react';
2
+ export function useHotkeys({ onDelete, toggleSelectionOnly, onUndoRedo }) {
3
+ useEffect(() => {
4
+ const handleKeyDown = (event) => {
5
+ if (event.key === 'Delete')
6
+ onDelete();
7
+ if (event.code === 'KeyX' && !(event.metaKey || event.ctrlKey) && !event.shiftKey)
8
+ toggleSelectionOnly();
9
+ if (event.code === 'KeyZ' && (event.metaKey || event.ctrlKey))
10
+ onUndoRedo(event.shiftKey);
11
+ };
12
+ window.addEventListener('keydown', handleKeyDown);
13
+ return () => window.removeEventListener('keydown', handleKeyDown);
14
+ }, [onDelete, toggleSelectionOnly, onUndoRedo]);
15
+ }
@@ -0,0 +1,21 @@
1
+ import { MouseEvent, RefObject } from 'react';
2
+ import { EditableCoordinate, Point } from '../../../types';
3
+ import { MouseAction } from '../../../utils/mouseActions';
4
+ import { CoordinateHistory } from '../../AnnotationCanvas/_utils/createHistory';
5
+ import { DrawMode } from '../../../enum/common';
6
+ export declare const INIT_POINT: Point;
7
+ type UseMouseParams = {
8
+ canvasRef: RefObject<HTMLCanvasElement | null>;
9
+ mouseActionRef: RefObject<MouseAction | null>;
10
+ setMousePoint: (point: Point) => void;
11
+ coordinatesRef?: RefObject<EditableCoordinate[]>;
12
+ setCoordinates?: (coordinates: EditableCoordinate[]) => void;
13
+ historyRef: RefObject<CoordinateHistory>;
14
+ selectedDrawMode?: DrawMode;
15
+ };
16
+ export declare function useMouse({ canvasRef, mouseActionRef, setMousePoint, coordinatesRef, setCoordinates, historyRef, selectedDrawMode, }: UseMouseParams): {
17
+ handleMouseDown: (event: MouseEvent) => void;
18
+ handleMouseUp: (event: MouseEvent) => void;
19
+ handleMouseLeave: (_event: MouseEvent) => void;
20
+ };
21
+ export {};
@@ -0,0 +1,34 @@
1
+ import { useCallback } from 'react';
2
+ import { isMouseClickAction, mapButtonToMouseAction, MouseAction } from '../../../utils/mouseActions';
3
+ import { DrawMode } from '../../../enum/common';
4
+ export const INIT_POINT = { x: 0, y: 0, selected: false };
5
+ export function useMouse({ canvasRef, mouseActionRef, setMousePoint, coordinatesRef, setCoordinates, historyRef, selectedDrawMode, }) {
6
+ const handleMouseDown = useCallback((event) => {
7
+ if (!canvasRef.current || !selectedDrawMode)
8
+ return;
9
+ const action = mapButtonToMouseAction(event.button);
10
+ if (action)
11
+ mouseActionRef.current = action;
12
+ }, [canvasRef, mouseActionRef]);
13
+ const handleMouseUp = useCallback((event) => {
14
+ if (canvasRef.current && isMouseClickAction(event.button, MouseAction.LEFT) && selectedDrawMode) {
15
+ if (selectedDrawMode === DrawMode.RECTANGLE && coordinatesRef?.current && setCoordinates) {
16
+ setCoordinates(coordinatesRef.current);
17
+ historyRef.current.add(JSON.parse(JSON.stringify(coordinatesRef.current)));
18
+ }
19
+ }
20
+ mouseActionRef.current = null;
21
+ event.preventDefault();
22
+ }, [canvasRef, coordinatesRef, setCoordinates, historyRef, selectedDrawMode, mouseActionRef]);
23
+ const handleMouseLeave = useCallback((_event) => {
24
+ if (!canvasRef.current || !selectedDrawMode)
25
+ return;
26
+ mouseActionRef.current = null;
27
+ setMousePoint(INIT_POINT);
28
+ }, [canvasRef, setMousePoint, mouseActionRef]);
29
+ return {
30
+ handleMouseDown,
31
+ handleMouseUp,
32
+ handleMouseLeave,
33
+ };
34
+ }
@@ -1,16 +1,13 @@
1
- import { Coordinate } from '../../types/coordinate';
1
+ import { Dispatch, RefObject, SetStateAction } from 'react';
2
+ import { CanvasState, EditableCoordinate, AnnotationCanvasDrawing } from '../../types';
3
+ import { CoordinateHistory } from '../AnnotationCanvas/_utils/createHistory';
2
4
  type Props = {
3
- moveX: number;
4
- moveY: number;
5
- zoomX: number;
6
- zoomY: number;
7
- zoom: number;
8
- dx: number;
9
- dy: number;
10
- dw: number;
11
- dh: number;
12
- coordinates?: Coordinate[];
13
- editable?: boolean;
5
+ canvasState: CanvasState;
6
+ coordinates: EditableCoordinate[] | undefined;
7
+ setCoordinates: Dispatch<SetStateAction<EditableCoordinate[] | undefined>>;
8
+ historyRef: RefObject<CoordinateHistory>;
9
+ drawing: AnnotationCanvasDrawing;
10
+ editable: boolean;
14
11
  };
15
- declare const AnnotationLayer: ({ moveX, moveY, zoom, zoomX, zoomY, dx, dy, dw, dh, coordinates }: Props) => import("react/jsx-runtime").JSX.Element;
12
+ declare const AnnotationLayer: ({ canvasState, coordinates, setCoordinates: propSetCoordinates, historyRef, drawing, editable, }: Props) => import("react/jsx-runtime").JSX.Element;
16
13
  export default AnnotationLayer;