@deepnoid/canvas 0.1.38 → 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
@@ -1,23 +1,17 @@
1
1
  import { RefObject, WheelEvent, MouseEvent } from 'react';
2
- type CanvasState = {
3
- dx: number;
4
- dy: number;
5
- dw: number;
6
- dh: number;
7
- moveX: number;
8
- moveY: number;
9
- zoomX: number;
10
- zoomY: number;
11
- zoom: number;
2
+ import { AnnotationCanvasOptionsZoom, CanvasState } from '../../../types';
3
+ type ImageCanvasState = CanvasState & {
12
4
  initZoom: number;
13
5
  };
14
6
  type Props = {
15
7
  canvasRef: RefObject<HTMLCanvasElement | null>;
16
8
  imageRef: RefObject<HTMLImageElement>;
17
- panZoomable?: boolean;
9
+ panZoomEnabled?: boolean;
10
+ zoom?: AnnotationCanvasOptionsZoom;
11
+ editable?: boolean;
18
12
  };
19
- export declare function useImagePanZoom({ canvasRef, imageRef, panZoomable }: Props): {
20
- canvasState: CanvasState;
13
+ export declare function useImagePanZoom({ canvasRef, imageRef, panZoomEnabled, zoom, editable }: Props): {
14
+ canvasState: ImageCanvasState;
21
15
  initZoomAndPosition: (canvas: HTMLCanvasElement, image: HTMLImageElement) => void;
22
16
  preserveZoomAndPosition: (canvas: HTMLCanvasElement, image: HTMLImageElement, zoomRatio: number) => void;
23
17
  initCanvas: () => void;
@@ -1,20 +1,19 @@
1
1
  'use client';
2
2
  import { useState, useRef } from 'react';
3
- import { getMousePointTransform, canvasCenterPoint, calculatorZoomPoint, calculateInitZoom, calculateZoom, } from '../../../utils/graphic';
4
- export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
5
- const ZOOM_UNIT = 0.9;
6
- const MAX_ZOOM = 4;
7
- const MIN_ZOOM = 0.5;
3
+ import { getMousePointTransform } from '../../../utils/pointTransform';
4
+ import { isMouseClickAction, isMouseDragAction, MouseAction } from '../../../utils/mouseActions';
5
+ import { calculateInitZoom, calculateZoom, calculatorZoomPoint, canvasCenterPoint } from '../_utils/panZoom';
6
+ export function useImagePanZoom({ canvasRef, imageRef, panZoomEnabled = false, zoom, editable = false }) {
8
7
  const [canvasState, setCanvasState] = useState({
9
- dx: 0,
10
- dy: 0,
11
- dw: 0,
12
- dh: 0,
13
8
  moveX: 0,
14
9
  moveY: 0,
15
10
  zoomX: 0,
16
11
  zoomY: 0,
17
12
  zoom: 0,
13
+ dx: 0,
14
+ dy: 0,
15
+ dw: 0,
16
+ dh: 0,
18
17
  initZoom: 0,
19
18
  });
20
19
  const [startMousePoint, setStartMousePoint] = useState();
@@ -24,16 +23,16 @@ export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
24
23
  const zoomPoint = calculatorZoomPoint(canvas, 0, 0, center.x, center.y);
25
24
  const initZoomValue = calculateInitZoom(canvas, image);
26
25
  setCanvasState({
27
- dx: center.x,
28
- dy: center.y,
29
- dw: image.width,
30
- dh: image.height,
31
26
  moveX: 0,
32
27
  moveY: 0,
33
28
  zoomX: zoomPoint.x,
34
29
  zoomY: zoomPoint.y,
35
30
  zoom: initZoomValue,
36
31
  initZoom: initZoomValue,
32
+ dx: center.x,
33
+ dy: center.y,
34
+ dw: image.width,
35
+ dh: image.height,
37
36
  });
38
37
  };
39
38
  const preserveZoomAndPosition = (canvas, image, zoomRatio) => {
@@ -42,15 +41,15 @@ export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
42
41
  const newInitZoom = calculateInitZoom(canvas, image);
43
42
  const zoomPoint = calculatorZoomPoint(canvas, canvasState.moveX, canvasState.moveY, center.x, center.y);
44
43
  setCanvasState({
45
- dx: center.x,
46
- dy: center.y,
47
- dw: image.width,
48
- dh: image.height,
49
44
  moveX: canvasState.moveX,
50
45
  moveY: canvasState.moveY,
51
46
  zoomX: zoomPoint.x,
52
47
  zoomY: zoomPoint.y,
53
48
  zoom: newInitZoom * prevZoomRatio,
49
+ dx: center.x,
50
+ dy: center.y,
51
+ dw: image.width,
52
+ dh: image.height,
54
53
  initZoom: newInitZoom,
55
54
  });
56
55
  };
@@ -60,9 +59,16 @@ export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
60
59
  initZoomAndPosition(canvasRef.current, imageRef.current);
61
60
  };
62
61
  const handleWheel = (event) => {
63
- if (!panZoomable || !canvasRef.current || canvasState.initZoom <= 0)
62
+ if (!panZoomEnabled || !canvasRef.current || canvasState.initZoom <= 0)
64
63
  return;
65
- const newZoom = calculateZoom(canvasState.zoom, event.deltaY, canvasState.initZoom * MIN_ZOOM, canvasState.initZoom * MAX_ZOOM, ZOOM_UNIT);
64
+ const zoomStep = zoom?.step || 0.9;
65
+ const maxZoom = zoom?.max;
66
+ const minZoom = zoom?.min;
67
+ const newZoom = maxZoom && minZoom
68
+ ? calculateZoom(canvasState.zoom, event.deltaY, canvasState.initZoom * minZoom, canvasState.initZoom * maxZoom, zoomStep)
69
+ : event.deltaY < 0
70
+ ? (canvasState.zoom || 1) * (1 / zoomStep)
71
+ : (canvasState.zoom || 1) * zoomStep;
66
72
  const zoomPoint = calculatorZoomPoint(canvasRef.current, canvasState.moveX, canvasState.moveY, canvasState.dx, canvasState.dy);
67
73
  setCanvasState({
68
74
  ...canvasState,
@@ -72,7 +78,9 @@ export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
72
78
  });
73
79
  };
74
80
  const handleMouseMove = (event) => {
75
- if (!panZoomable || !canvasRef.current || !isDraggingRef.current)
81
+ if (!panZoomEnabled || !canvasRef.current || !isDraggingRef.current)
82
+ return;
83
+ if (editable && isMouseDragAction(event.button, MouseAction.LEFT))
76
84
  return;
77
85
  const canvas = canvasRef.current;
78
86
  const rect = canvas.getBoundingClientRect();
@@ -96,7 +104,9 @@ export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
96
104
  event.preventDefault();
97
105
  };
98
106
  const handleMouseDown = (event) => {
99
- if (!panZoomable || !canvasRef.current)
107
+ if (!panZoomEnabled || !canvasRef.current)
108
+ return;
109
+ if (editable && isMouseClickAction(event.button, MouseAction.LEFT))
100
110
  return;
101
111
  isDraggingRef.current = true;
102
112
  const canvas = canvasRef.current;
@@ -108,13 +118,13 @@ export function useImagePanZoom({ canvasRef, imageRef, panZoomable = false }) {
108
118
  event.preventDefault();
109
119
  };
110
120
  const handleMouseUp = (event) => {
111
- if (!panZoomable || !canvasRef.current)
121
+ if (!panZoomEnabled || !canvasRef.current)
112
122
  return;
113
123
  isDraggingRef.current = false;
114
124
  event.preventDefault();
115
125
  };
116
126
  const handleMouseLeave = (event) => {
117
- if (!panZoomable || !canvasRef.current)
127
+ if (!panZoomEnabled || !canvasRef.current)
118
128
  return;
119
129
  isDraggingRef.current = false;
120
130
  event.preventDefault();
@@ -0,0 +1,11 @@
1
+ import { Coordinate } from '../../../types';
2
+ export type CoordinateHistory = {
3
+ getHistory: () => Coordinate[][];
4
+ getHistoryIndex: () => number;
5
+ setHistoryIndex: (index: number) => void;
6
+ init: (coordinates?: Coordinate[]) => void;
7
+ add: (coordinates: Coordinate[]) => void;
8
+ undo: () => Coordinate[] | undefined;
9
+ redo: () => Coordinate[] | undefined;
10
+ };
11
+ export declare const createHistory: () => CoordinateHistory;
@@ -0,0 +1,34 @@
1
+ export const createHistory = () => {
2
+ let history = [];
3
+ let historyIndex = -1;
4
+ return {
5
+ getHistory: () => history,
6
+ getHistoryIndex: () => historyIndex,
7
+ setHistoryIndex: (index) => {
8
+ historyIndex = index;
9
+ },
10
+ init: (coordinates = []) => {
11
+ history = [coordinates];
12
+ historyIndex = 0;
13
+ },
14
+ add: (coordinates) => {
15
+ history.splice(historyIndex + 1);
16
+ history.push(coordinates);
17
+ historyIndex++;
18
+ },
19
+ undo: () => {
20
+ if (historyIndex > 0) {
21
+ historyIndex--;
22
+ return history[historyIndex];
23
+ }
24
+ return undefined;
25
+ },
26
+ redo: () => {
27
+ if (historyIndex < history.length - 1) {
28
+ historyIndex++;
29
+ return history[historyIndex];
30
+ }
31
+ return undefined;
32
+ },
33
+ };
34
+ };
@@ -0,0 +1,10 @@
1
+ export declare const canvasCenterPoint: (canvas: HTMLCanvasElement, image: HTMLImageElement) => {
2
+ x: number;
3
+ y: number;
4
+ };
5
+ export declare const calculatorZoomPoint: (canvas: HTMLCanvasElement, movementX: number, movementY: number, dx: number, dy: number) => {
6
+ x: number;
7
+ y: number;
8
+ };
9
+ export declare const calculateInitZoom: (canvas: HTMLCanvasElement, image: HTMLImageElement) => number;
10
+ export declare const calculateZoom: (currentZoom: number, deltaY: number, minZoom: number, maxZoom: number, zoomUnit: number) => number;
@@ -0,0 +1,29 @@
1
+ export const canvasCenterPoint = (canvas, image) => {
2
+ const centerX = canvas.width / 2 - image.width / 2;
3
+ const centerY = canvas.height / 2 - image.height / 2;
4
+ return { x: centerX, y: centerY };
5
+ };
6
+ export const calculatorZoomPoint = (canvas, movementX, movementY, dx, dy) => {
7
+ let x = 0;
8
+ let y = 0;
9
+ if (canvas) {
10
+ x = -dx - movementX + canvas.width / 2;
11
+ y = -dy - movementY + canvas.height / 2;
12
+ }
13
+ return { x, y };
14
+ };
15
+ export const calculateInitZoom = (canvas, image) => {
16
+ if (!canvas || !image.naturalWidth)
17
+ return 1;
18
+ const canvasRatio = canvas.clientWidth / canvas.clientHeight;
19
+ const imageRatio = image.naturalWidth / image.naturalHeight;
20
+ return canvasRatio < imageRatio ? canvas.clientWidth / image.naturalWidth : canvas.clientHeight / image.naturalHeight;
21
+ };
22
+ export const calculateZoom = (currentZoom, deltaY, minZoom, maxZoom, zoomUnit) => {
23
+ let newZoom = deltaY < 0 ? currentZoom * (1 / zoomUnit) : currentZoom * zoomUnit;
24
+ if (newZoom > maxZoom)
25
+ newZoom = maxZoom;
26
+ if (newZoom < minZoom)
27
+ newZoom = minZoom;
28
+ return newZoom;
29
+ };
@@ -0,0 +1,25 @@
1
+ import { ComponentType, ReactNode } from 'react';
2
+ import { AnnotationCanvasDrawing, AnnotationCanvasOptionsZoom, Coordinate } from '../../types';
3
+ export type ZoomButtonType = {
4
+ onClick: () => void;
5
+ children: ReactNode;
6
+ };
7
+ export type AnnotationCanvasProps = {
8
+ image: string;
9
+ coordinates?: Coordinate[];
10
+ options: {
11
+ panZoomEnabled?: boolean;
12
+ zoom?: AnnotationCanvasOptionsZoom;
13
+ ZoomButton?: ComponentType<ZoomButtonType>;
14
+ resetOnImageChange?: boolean;
15
+ timeout?: number;
16
+ };
17
+ drawing: AnnotationCanvasDrawing;
18
+ events: {
19
+ onImageLoadSuccess?: () => void;
20
+ onImageLoadError?: (error: Error) => void;
21
+ };
22
+ editable?: boolean;
23
+ };
24
+ declare const AnnotationCanvas: ({ image, coordinates, options, drawing, events, editable, }: AnnotationCanvasProps) => import("react/jsx-runtime").JSX.Element;
25
+ export default AnnotationCanvas;
@@ -0,0 +1,83 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import AnnotationLayer from '../AnnotationLayer';
5
+ import { useImagePanZoom } from './_hooks/useImagePanZoom';
6
+ import useResizeObserver from '../../hooks/useResizeObserver';
7
+ import { useDebounce } from '../../hooks/useDebounce';
8
+ import { DrawMode } from '../../enum/common';
9
+ import { createHistory } from './_utils/createHistory';
10
+ import { clearCanvasRect, drawCanvas, resolutionCanvas } from '../../utils/canvas';
11
+ const AnnotationCanvas = ({ image, coordinates, options, drawing, events, editable = false, }) => {
12
+ const { panZoomEnabled, zoom, ZoomButton, resetOnImageChange, timeout = 10000 } = options;
13
+ const { onImageLoadSuccess, onImageLoadError } = events;
14
+ const canvasRef = useRef(null);
15
+ const imageRef = useRef(new Image());
16
+ const historyRef = useRef(createHistory());
17
+ const [displayCoordinates, setDisplayCoordinates] = useState();
18
+ useResizeObserver({
19
+ ref: canvasRef,
20
+ onResize: useDebounce((size) => {
21
+ if (image && size.width && size.height && canvasRef.current && imageRef.current.src) {
22
+ const canvas = resolutionCanvas(canvasRef.current);
23
+ if (canvas)
24
+ initZoomAndPosition(canvas, imageRef.current);
25
+ }
26
+ }, 150),
27
+ });
28
+ const { canvasState, initZoomAndPosition, initCanvas, preserveZoomAndPosition, handleWheel, handleMouseDown, handleMouseMove, handleMouseUp, handleMouseLeave, } = useImagePanZoom({ canvasRef, imageRef, panZoomEnabled, zoom, editable });
29
+ const createEmptyImage = () => {
30
+ const img = new Image();
31
+ img.width = img.height = 0;
32
+ return img;
33
+ };
34
+ const resetCanvas = (errorMsg) => {
35
+ clearCanvasRect(canvasRef.current);
36
+ setDisplayCoordinates([]);
37
+ imageRef.current = createEmptyImage();
38
+ if (errorMsg)
39
+ onImageLoadError?.(new Error(errorMsg));
40
+ };
41
+ useEffect(() => {
42
+ if (!image?.trim())
43
+ return void resetCanvas();
44
+ let cancelled = false;
45
+ const tempImage = new Image();
46
+ tempImage.onload = () => {
47
+ if (cancelled || !canvasRef.current)
48
+ return;
49
+ onImageLoadSuccess?.();
50
+ if (resetOnImageChange) {
51
+ setTimeout(() => initCanvas(), 0);
52
+ }
53
+ else {
54
+ preserveZoomAndPosition(canvasRef.current, tempImage, canvasState.zoom / (canvasState.initZoom || 1));
55
+ }
56
+ imageRef.current = tempImage;
57
+ setDisplayCoordinates(coordinates?.map((coordinate) => {
58
+ return {
59
+ ...coordinate,
60
+ type: coordinate.type ? coordinate.type : DrawMode.RECTANGLE,
61
+ };
62
+ }) || []);
63
+ };
64
+ tempImage.onerror = () => !cancelled && resetCanvas(`Failed to load image: ${image}`);
65
+ tempImage.src = image;
66
+ return () => {
67
+ cancelled = true;
68
+ };
69
+ }, [image, resetOnImageChange]);
70
+ useEffect(() => {
71
+ if (!canvasRef.current)
72
+ return;
73
+ const redraw = (canvas) => {
74
+ const { moveX, moveY, zoomX, zoomY, zoom, dx, dy } = canvasState;
75
+ drawCanvas(moveX, moveY, zoomX, zoomY, zoom, dx, dy, canvas, imageRef.current, true);
76
+ };
77
+ const canvas = resolutionCanvas(canvasRef.current);
78
+ if (canvas)
79
+ redraw(canvas);
80
+ }, [canvasState]);
81
+ return (_jsx("div", { style: { width: '100%', height: '100%', display: 'flex', flex: 1 }, children: _jsxs("div", { onWheel: handleWheel, onMouseMove: handleMouseMove, onMouseDown: handleMouseDown, onMouseUp: handleMouseUp, onMouseLeave: handleMouseLeave, onContextMenu: (e) => e.preventDefault(), style: { flex: 1, position: 'relative', cursor: editable ? 'default' : 'grab' }, children: [_jsx("canvas", { ref: canvasRef, style: { position: 'absolute', width: '100%', height: '100%', left: 0, top: 0 } }), _jsx(AnnotationLayer, { canvasState: canvasState, coordinates: displayCoordinates, setCoordinates: setDisplayCoordinates, historyRef: historyRef, drawing: drawing, editable: editable }), ZoomButton && canvasState.initZoom > 0 && (_jsx(ZoomButton, { onClick: initCanvas, children: `${Math.round((canvasState.zoom / canvasState.initZoom) * 100)}%` }))] }) }));
82
+ };
83
+ export default AnnotationCanvas;
@@ -0,0 +1,5 @@
1
+ import { DrawEventsParams } from './useDrawEvents';
2
+ export declare const handleMouseDownRectangle: ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, startMousePointRef, currentCoordinateRef, coordinatesRef, rectangleAnchorRef, }: DrawEventsParams) => (event: globalThis.MouseEvent) => void;
3
+ export declare const handleMouseMoveRectangle: ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, prevMousePointRef, currentCoordinateRef, coordinatesRef, rectangleAnchorRef, }: DrawEventsParams) => (event: globalThis.MouseEvent) => void;
4
+ export declare const handleMouseUpRectangle: ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, startMousePointRef, prevMousePointRef, currentCoordinateRef, coordinatesRef, setCoordinates, rectangleAnchorRef, historyRef, drawLabel, }: DrawEventsParams) => (event: globalThis.MouseEvent) => void;
5
+ export declare const handleMouseLeaveRectangle: ({ canvasRef, canvasStateRef, setMousePoint, startMousePointRef, prevMousePointRef, mouseActionRef, rectangleAnchorRef, }: DrawEventsParams) => (event: globalThis.MouseEvent) => void;
@@ -0,0 +1,75 @@
1
+ import { DrawMode } from '../../../../enum/common';
2
+ import { cloneDeep } from '../../../../utils/common/cloneDeep';
3
+ import { isMouseClickAction, MouseAction } from '../../../../utils/mouseActions';
4
+ import { ACTIVE_POINT_SIZE, clampBoundingBoxToImage, createCoordinate, getCanvasMousePoint, handleBBoxOperations, isInsideImage, updateActiveRectangleAnchor, selectRectangleAtPoint, } from './rectangleUtils';
5
+ export const handleMouseDownRectangle = ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, startMousePointRef, currentCoordinateRef, coordinatesRef, rectangleAnchorRef, }) => (event) => {
6
+ if (!canvasRef.current || !isMouseClickAction(event.button, MouseAction.LEFT))
7
+ return;
8
+ const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
9
+ if (!isInsideImage(mousePoint, canvasStateRef.current.dw, canvasStateRef.current.dh))
10
+ return;
11
+ mouseActionRef.current = MouseAction.LEFT;
12
+ setMousePoint(mousePoint);
13
+ startMousePointRef.current = mousePoint;
14
+ if (currentCoordinateRef.current) {
15
+ const { zoom } = canvasStateRef.current;
16
+ selectRectangleAtPoint(zoom, mousePointRef.current, coordinatesRef, currentCoordinateRef);
17
+ updateActiveRectangleAnchor(zoom, mousePointRef.current, currentCoordinateRef, rectangleAnchorRef);
18
+ }
19
+ event.preventDefault();
20
+ };
21
+ export const handleMouseMoveRectangle = ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, prevMousePointRef, currentCoordinateRef, coordinatesRef, rectangleAnchorRef, }) => (event) => {
22
+ if (!canvasRef.current || !isMouseClickAction(event.button, MouseAction.LEFT))
23
+ return;
24
+ prevMousePointRef.current = cloneDeep(mousePointRef.current);
25
+ const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
26
+ setMousePoint(mousePoint);
27
+ handleBBoxOperations({
28
+ coordinatesRef,
29
+ dw: canvasStateRef.current.dw,
30
+ dh: canvasStateRef.current.dh,
31
+ mousePoint: mousePointRef.current,
32
+ prevMousePoint: prevMousePointRef.current,
33
+ mouseAction: mouseActionRef.current,
34
+ currentCoordinate: currentCoordinateRef.current,
35
+ rectangleAnchor: rectangleAnchorRef.current,
36
+ });
37
+ event.preventDefault();
38
+ };
39
+ export const handleMouseUpRectangle = ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, startMousePointRef, prevMousePointRef, currentCoordinateRef, coordinatesRef, setCoordinates, rectangleAnchorRef, historyRef, drawLabel, }) => (event) => {
40
+ if (!canvasRef.current || !isMouseClickAction(event.button, MouseAction.LEFT))
41
+ return;
42
+ const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
43
+ setMousePoint(mousePoint);
44
+ if (startMousePointRef.current) {
45
+ const movedWidth = Math.abs(startMousePointRef.current.x - mousePoint.x);
46
+ const movedHeight = Math.abs(startMousePointRef.current.y - mousePoint.y);
47
+ const { zoom, dw, dh } = canvasStateRef.current;
48
+ if (movedWidth > ACTIVE_POINT_SIZE || movedHeight > ACTIVE_POINT_SIZE) {
49
+ const { x, y, width, height } = clampBoundingBoxToImage(Math.min(startMousePointRef.current.x, mousePoint.x), Math.min(startMousePointRef.current.y, mousePoint.y), movedWidth, movedHeight, dw, dh);
50
+ if (!currentCoordinateRef.current) {
51
+ const newCoordinate = { label: drawLabel, type: DrawMode.RECTANGLE, x, y, width, height, selected: false };
52
+ createCoordinate(newCoordinate, setCoordinates, coordinatesRef, historyRef, currentCoordinateRef);
53
+ }
54
+ }
55
+ else {
56
+ selectRectangleAtPoint(zoom, mousePointRef.current, coordinatesRef, currentCoordinateRef);
57
+ }
58
+ }
59
+ mouseActionRef.current = null;
60
+ startMousePointRef.current = null;
61
+ prevMousePointRef.current = null;
62
+ rectangleAnchorRef.current = null;
63
+ event.preventDefault();
64
+ };
65
+ export const handleMouseLeaveRectangle = ({ canvasRef, canvasStateRef, setMousePoint, startMousePointRef, prevMousePointRef, mouseActionRef, rectangleAnchorRef, }) => (event) => {
66
+ if (!canvasRef.current)
67
+ return;
68
+ const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
69
+ setMousePoint(mousePoint);
70
+ mouseActionRef.current = null;
71
+ startMousePointRef.current = null;
72
+ prevMousePointRef.current = null;
73
+ rectangleAnchorRef.current = null;
74
+ event.preventDefault();
75
+ };
@@ -0,0 +1,30 @@
1
+ import { RefObject } from 'react';
2
+ import { EditableCoordinate, Point, Rectangle, CanvasState } from '../../../../types';
3
+ import { CoordinateHistory } from '../../../AnnotationCanvas/_utils/createHistory';
4
+ import { MouseAction } from '../../../../utils/mouseActions';
5
+ import { RectangleAnchor } from '../../../../enum/common';
6
+ export declare const ACTIVE_POINT_SIZE = 10;
7
+ export declare const getRectangleCorners: ({ x, y, width, height }: Rectangle) => {
8
+ x: number;
9
+ y: number;
10
+ }[];
11
+ export declare const selectRectangleAtPoint: (zoom: number, mousePoint: Point, coordinatesRef: RefObject<EditableCoordinate[]>, currentCoordinateRef: RefObject<EditableCoordinate | null>) => void;
12
+ export declare const updateActiveRectangleAnchor: (zoom: number, mousePointRef: Point, currentCoordinateRef: RefObject<EditableCoordinate | null>, rectangleAnchorRef: RefObject<RectangleAnchor | null>) => void;
13
+ export declare const createCoordinate: (coordinate: EditableCoordinate, setCoordinates: (dataSet: EditableCoordinate[]) => void, coordinatesRef: RefObject<EditableCoordinate[]>, historyRef: RefObject<CoordinateHistory>, currentCoordinateRef: RefObject<EditableCoordinate | null>) => void;
14
+ export declare const clampBoundingBoxToImage: (x: number, y: number, width: number, height: number, dw: number, dh: number) => Rectangle & {
15
+ selected?: boolean;
16
+ };
17
+ export declare const getCanvasMousePoint: (event: globalThis.MouseEvent | React.MouseEvent, canvas: HTMLCanvasElement, canvasState: CanvasState) => Point;
18
+ type BBoxParams = {
19
+ coordinatesRef: RefObject<EditableCoordinate[]>;
20
+ dw: number;
21
+ dh: number;
22
+ mousePoint: Point;
23
+ prevMousePoint: Point;
24
+ mouseAction: MouseAction | null;
25
+ currentCoordinate: EditableCoordinate | null;
26
+ rectangleAnchor: RectangleAnchor | null;
27
+ };
28
+ export declare const handleBBoxOperations: (params: BBoxParams) => void;
29
+ export declare const isInsideImage: (point: Point, imageWidth: number, imageHeight: number) => boolean;
30
+ export {};