@deepnoid/canvas 0.1.58 → 0.1.60

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 (84) hide show
  1. package/README.md +202 -3
  2. package/dist/engine/annotation/annotationTypes.d.ts +21 -0
  3. package/dist/engine/annotation/annotationTypes.js +6 -0
  4. package/dist/engine/annotation/rectangle/rectangleController.d.ts +26 -0
  5. package/dist/engine/annotation/rectangle/rectangleController.js +115 -0
  6. package/dist/engine/annotation/rectangle/rectangleHitTest.d.ts +7 -0
  7. package/dist/engine/annotation/rectangle/rectangleHitTest.js +102 -0
  8. package/dist/engine/annotation/rectangle/rectangleInteraction.d.ts +17 -0
  9. package/dist/engine/annotation/rectangle/rectangleInteraction.js +30 -0
  10. package/dist/engine/annotation/rectangle/rectangleMath.d.ts +10 -0
  11. package/dist/engine/annotation/rectangle/rectangleMath.js +29 -0
  12. package/dist/engine/annotation/rectangle/rectangleRenderer.d.ts +5 -0
  13. package/dist/engine/annotation/rectangle/rectangleRenderer.js +88 -0
  14. package/dist/engine/annotation/rectangle/rectangleTransform.d.ts +14 -0
  15. package/dist/engine/annotation/rectangle/rectangleTransform.js +65 -0
  16. package/dist/{enum/common.d.ts → engine/annotation/rectangle/rectangleTypes.d.ts} +0 -3
  17. package/dist/{enum/common.js → engine/annotation/rectangle/rectangleTypes.js} +0 -4
  18. package/dist/engine/history.d.ts +11 -0
  19. package/dist/{components/AnnotationCanvas/_utils/createHistory.js → engine/history.js} +4 -4
  20. package/dist/engine/interaction/drawModeRouter.d.ts +3 -0
  21. package/dist/engine/interaction/drawModeRouter.js +56 -0
  22. package/dist/engine/interaction/interactionController.d.ts +13 -0
  23. package/dist/engine/interaction/interactionController.js +53 -0
  24. package/dist/engine/interaction/interface.d.ts +15 -0
  25. package/dist/engine/interaction/panZoomInteraction.d.ts +3 -0
  26. package/dist/engine/interaction/panZoomInteraction.js +29 -0
  27. package/dist/engine/interaction/pointerInteraction.d.ts +16 -0
  28. package/dist/engine/interaction/pointerInteraction.js +48 -0
  29. package/dist/engine/pan-zoom/panZoomController.d.ts +26 -0
  30. package/dist/engine/pan-zoom/panZoomController.js +148 -0
  31. package/dist/engine/pan-zoom/panZoomUtils.d.ts +10 -0
  32. package/dist/engine/pan-zoom/panZoomUtils.js +24 -0
  33. package/dist/engine/public/annotationEngine.d.ts +75 -0
  34. package/dist/engine/public/annotationEngine.js +263 -0
  35. package/dist/engine/renderer/drawCross.d.ts +2 -0
  36. package/dist/engine/renderer/drawCross.js +19 -0
  37. package/dist/engine/renderer/interface.d.ts +6 -0
  38. package/dist/engine/renderer/interface.js +1 -0
  39. package/dist/{types/index.d.ts → engine/types.d.ts} +12 -21
  40. package/dist/engine/types.js +1 -0
  41. package/dist/engine/utils/mousePoint.d.ts +3 -0
  42. package/dist/engine/utils/mousePoint.js +52 -0
  43. package/dist/index.d.ts +4 -5
  44. package/dist/index.js +2 -2
  45. package/dist/{components/AnnotationCanvas/index.d.ts → react/AnnotationCanvas.d.ts} +7 -6
  46. package/dist/react/AnnotationCanvas.js +110 -0
  47. package/dist/{components → react}/index.d.ts +1 -1
  48. package/dist/{components → react}/index.js +1 -1
  49. package/package.json +1 -1
  50. package/dist/components/AnnotationCanvas/_hooks/useImagePanZoom.d.ts +0 -24
  51. package/dist/components/AnnotationCanvas/_hooks/useImagePanZoom.js +0 -143
  52. package/dist/components/AnnotationCanvas/_utils/createHistory.d.ts +0 -11
  53. package/dist/components/AnnotationCanvas/_utils/panZoom.d.ts +0 -10
  54. package/dist/components/AnnotationCanvas/_utils/panZoom.js +0 -29
  55. package/dist/components/AnnotationCanvas/index.js +0 -96
  56. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangle.d.ts +0 -5
  57. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangle.js +0 -88
  58. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangleUtils.d.ts +0 -28
  59. package/dist/components/AnnotationLayer/_hooks/drawEvents/rectangleUtils.js +0 -204
  60. package/dist/components/AnnotationLayer/_hooks/drawEvents/useDrawEvents.d.ts +0 -25
  61. package/dist/components/AnnotationLayer/_hooks/drawEvents/useDrawEvents.js +0 -43
  62. package/dist/components/AnnotationLayer/_hooks/useCanvasDraw.d.ts +0 -13
  63. package/dist/components/AnnotationLayer/_hooks/useCanvasDraw.js +0 -115
  64. package/dist/components/AnnotationLayer/index.d.ts +0 -14
  65. package/dist/components/AnnotationLayer/index.js +0 -122
  66. package/dist/utils/canvas.d.ts +0 -3
  67. package/dist/utils/canvas.js +0 -37
  68. package/dist/utils/pointTransform.d.ts +0 -2
  69. package/dist/utils/pointTransform.js +0 -46
  70. /package/dist/{types/index.js → engine/interaction/interface.js} +0 -0
  71. /package/dist/{utils/common → engine/utils}/cloneDeep.d.ts +0 -0
  72. /package/dist/{utils/common → engine/utils}/cloneDeep.js +0 -0
  73. /package/dist/{utils/common → engine/utils}/deepEqual.d.ts +0 -0
  74. /package/dist/{utils/common → engine/utils}/deepEqual.js +0 -0
  75. /package/dist/{utils/common → engine/utils}/isEqualWith.d.ts +0 -0
  76. /package/dist/{utils/common → engine/utils}/isEqualWith.js +0 -0
  77. /package/dist/{utils → engine/utils}/mouseActions.d.ts +0 -0
  78. /package/dist/{utils → engine/utils}/mouseActions.js +0 -0
  79. /package/dist/{hooks → react/hooks}/useDebounce.d.ts +0 -0
  80. /package/dist/{hooks → react/hooks}/useDebounce.js +0 -0
  81. /package/dist/{components/AnnotationLayer/_hooks → react/hooks}/useHotkeys.d.ts +0 -0
  82. /package/dist/{components/AnnotationLayer/_hooks → react/hooks}/useHotkeys.js +0 -0
  83. /package/dist/{hooks → react/hooks}/useResizeObserver.d.ts +0 -0
  84. /package/dist/{hooks → react/hooks}/useResizeObserver.js +0 -0
@@ -1,143 +0,0 @@
1
- 'use client';
2
- import { useState, useRef } from 'react';
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 }) {
7
- const [canvasState, setCanvasState] = useState({
8
- moveX: 0,
9
- moveY: 0,
10
- zoomX: 0,
11
- zoomY: 0,
12
- zoom: 1,
13
- dx: 0,
14
- dy: 0,
15
- dw: 0,
16
- dh: 0,
17
- initZoom: 0,
18
- });
19
- const [startMousePoint, setStartMousePoint] = useState();
20
- const isDraggingRef = useRef(false);
21
- const initZoomAndPosition = (canvas, image) => {
22
- const center = canvasCenterPoint(canvas, image);
23
- const zoomPoint = calculatorZoomPoint(canvas, 0, 0, center.x, center.y);
24
- const initZoomValue = calculateInitZoom(canvas, image);
25
- setCanvasState({
26
- moveX: 0,
27
- moveY: 0,
28
- zoomX: zoomPoint.x,
29
- zoomY: zoomPoint.y,
30
- zoom: initZoomValue,
31
- initZoom: initZoomValue,
32
- dx: center.x,
33
- dy: center.y,
34
- dw: image.width,
35
- dh: image.height,
36
- });
37
- };
38
- const preserveZoomAndPosition = (canvas, image, zoomRatio) => {
39
- const prevZoomRatio = zoomRatio || 1;
40
- const center = canvasCenterPoint(canvas, image);
41
- const newInitZoom = calculateInitZoom(canvas, image);
42
- const zoomPoint = calculatorZoomPoint(canvas, canvasState.moveX, canvasState.moveY, center.x, center.y);
43
- setCanvasState({
44
- moveX: canvasState.moveX,
45
- moveY: canvasState.moveY,
46
- zoomX: zoomPoint.x,
47
- zoomY: zoomPoint.y,
48
- zoom: newInitZoom * prevZoomRatio,
49
- dx: center.x,
50
- dy: center.y,
51
- dw: image.width,
52
- dh: image.height,
53
- initZoom: newInitZoom,
54
- });
55
- };
56
- const initCanvas = () => {
57
- if (!canvasRef.current)
58
- return;
59
- initZoomAndPosition(canvasRef.current, imageRef.current);
60
- };
61
- const handleWheel = (event) => {
62
- if (!panZoomEnabled || !canvasRef.current || canvasState.initZoom <= 0)
63
- return;
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;
72
- const zoomPoint = calculatorZoomPoint(canvasRef.current, canvasState.moveX, canvasState.moveY, canvasState.dx, canvasState.dy);
73
- setCanvasState({
74
- ...canvasState,
75
- zoomX: zoomPoint.x,
76
- zoomY: zoomPoint.y,
77
- zoom: newZoom,
78
- });
79
- };
80
- const handleMouseMove = (event) => {
81
- if (!panZoomEnabled || !canvasRef.current || !isDraggingRef.current)
82
- return;
83
- if (editable && isMouseDragAction(event.button, MouseAction.LEFT))
84
- return;
85
- const canvas = canvasRef.current;
86
- const rect = canvas.getBoundingClientRect();
87
- const mouseX = event.clientX - rect.left;
88
- const mouseY = event.clientY - rect.top;
89
- const mouse = getMousePointTransform({ x: mouseX, y: mouseY }, { x: canvasState.moveX, y: canvasState.moveY }, { x: canvasState.zoomX, y: canvasState.zoomY }, { x: canvasState.dx, y: canvasState.dy }, canvasState.zoom || 1, canvas);
90
- let x = mouse.x;
91
- let y = mouse.y;
92
- if (startMousePoint) {
93
- x -= startMousePoint.x;
94
- y -= startMousePoint.y;
95
- }
96
- const zoomPoint = calculatorZoomPoint(canvas, canvasState.moveX + x, canvasState.moveY + y, canvasState.dx, canvasState.dy);
97
- setCanvasState({
98
- ...canvasState,
99
- moveX: canvasState.moveX + x,
100
- moveY: canvasState.moveY + y,
101
- zoomX: zoomPoint.x,
102
- zoomY: zoomPoint.y,
103
- });
104
- event.preventDefault();
105
- };
106
- const handleMouseDown = (event) => {
107
- if (!panZoomEnabled || !canvasRef.current)
108
- return;
109
- if (editable && isMouseClickAction(event.button, MouseAction.LEFT))
110
- return;
111
- isDraggingRef.current = true;
112
- const canvas = canvasRef.current;
113
- const rect = canvas.getBoundingClientRect();
114
- const mouseX = event.clientX - rect.left;
115
- const mouseY = event.clientY - rect.top;
116
- const mouse = getMousePointTransform({ x: mouseX, y: mouseY }, { x: canvasState.moveX, y: canvasState.moveY }, { x: canvasState.zoomX, y: canvasState.zoomY }, { x: canvasState.dx, y: canvasState.dy }, canvasState.zoom || 1, canvas);
117
- setStartMousePoint({ x: mouse.x, y: mouse.y });
118
- event.preventDefault();
119
- };
120
- const handleMouseUp = (event) => {
121
- if (!panZoomEnabled || !canvasRef.current)
122
- return;
123
- isDraggingRef.current = false;
124
- event.preventDefault();
125
- };
126
- const handleMouseLeave = (event) => {
127
- if (!panZoomEnabled || !canvasRef.current)
128
- return;
129
- isDraggingRef.current = false;
130
- event.preventDefault();
131
- };
132
- return {
133
- canvasState,
134
- initZoomAndPosition,
135
- preserveZoomAndPosition,
136
- initCanvas,
137
- handleWheel,
138
- handleMouseDown,
139
- handleMouseMove,
140
- handleMouseUp,
141
- handleMouseLeave,
142
- };
143
- }
@@ -1,11 +0,0 @@
1
- import { Coordinate } from '../../../types';
2
- export type CoordinateHistory = {
3
- getHistory: () => Coordinate[][];
4
- init: (coordinates?: Coordinate[]) => void;
5
- getHistoryIndex: () => number;
6
- addInit: () => void;
7
- add: (coordinates: Coordinate[]) => void;
8
- undo: () => Coordinate[] | undefined;
9
- redo: () => Coordinate[] | undefined;
10
- };
11
- export declare const createHistory: () => CoordinateHistory;
@@ -1,10 +0,0 @@
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;
@@ -1,29 +0,0 @@
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
- };
@@ -1,96 +0,0 @@
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, setCoordinates, options, drawing, events, enableHotkeys = false, 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(null);
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 updateDisplayCoordinates = (coordinates) => {
30
- setDisplayCoordinates(coordinates?.map((coordinate) => ({
31
- ...coordinate,
32
- type: coordinate.type ?? DrawMode.RECTANGLE,
33
- })) || []);
34
- };
35
- const createEmptyImage = () => {
36
- const img = new Image();
37
- img.width = img.height = 0;
38
- return img;
39
- };
40
- const resetCanvas = (errorMsg) => {
41
- clearCanvasRect(canvasRef.current);
42
- setDisplayCoordinates([]);
43
- imageRef.current = createEmptyImage();
44
- if (errorMsg)
45
- onImageLoadError?.(new Error(errorMsg));
46
- };
47
- useEffect(() => {
48
- if (!image?.trim())
49
- return void resetCanvas();
50
- let cancelled = false;
51
- const tempImage = new Image();
52
- tempImage.onload = () => {
53
- if (cancelled || !canvasRef.current)
54
- return;
55
- onImageLoadSuccess?.();
56
- if (resetOnImageChange) {
57
- setTimeout(() => initCanvas(), 0);
58
- }
59
- else {
60
- preserveZoomAndPosition(canvasRef.current, tempImage, canvasState.zoom / (canvasState.initZoom || 1));
61
- }
62
- imageRef.current = tempImage;
63
- updateDisplayCoordinates(coordinates);
64
- };
65
- tempImage.onerror = () => !cancelled && resetCanvas(`Failed to load image: ${image}`);
66
- tempImage.src = image;
67
- historyRef.current = null;
68
- return () => {
69
- cancelled = true;
70
- tempImage.onload = null;
71
- tempImage.onerror = null;
72
- };
73
- }, [image, resetOnImageChange]);
74
- useEffect(() => {
75
- if (imageRef.current.src) {
76
- if (!historyRef.current && coordinates && coordinates.length > 0) {
77
- historyRef.current = createHistory();
78
- historyRef.current.init(coordinates);
79
- }
80
- updateDisplayCoordinates(coordinates);
81
- }
82
- }, [coordinates, imageRef.current]);
83
- useEffect(() => {
84
- if (!canvasRef.current)
85
- return;
86
- const redraw = (canvas) => {
87
- const { moveX, moveY, zoomX, zoomY, zoom, dx, dy } = canvasState;
88
- drawCanvas(moveX, moveY, zoomX, zoomY, zoom, dx, dy, canvas, imageRef.current, true);
89
- };
90
- const canvas = resolutionCanvas(canvasRef.current);
91
- if (canvas)
92
- redraw(canvas);
93
- }, [canvasState]);
94
- 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: !panZoomEnabled || 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: setCoordinates, historyRef: historyRef, drawing: drawing, enableHotkeys: enableHotkeys, editable: editable }), ZoomButton && canvasState.initZoom > 0 && (_jsx(ZoomButton, { onClick: initCanvas, children: `${Math.round((canvasState.zoom / canvasState.initZoom) * 100)}%` }))] }) }));
95
- };
96
- export default AnnotationCanvas;
@@ -1,5 +0,0 @@
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, drawLabelRef, historyRef, }: DrawEventsParams) => (event: globalThis.MouseEvent) => void;
5
- export declare const handleMouseLeaveRectangle: ({ canvasRef, canvasStateRef, setMousePoint, startMousePointRef, prevMousePointRef, mouseActionRef, rectangleAnchorRef, }: DrawEventsParams) => (event: globalThis.MouseEvent) => void;
@@ -1,88 +0,0 @@
1
- import { DrawMode } from '../../../../enum/common';
2
- import { cloneDeep } from '../../../../utils/common/cloneDeep';
3
- import { isMouseClickAction, MouseAction } from '../../../../utils/mouseActions';
4
- import { createHistory } from '../../../AnnotationCanvas/_utils/createHistory';
5
- import { ACTIVE_POINT_SIZE, clampBoundingBoxToImage, getCanvasMousePoint, handleBBoxOperations, isInsideImage, updateActiveRectangleAnchor, selectRectangleAtPoint, } from './rectangleUtils';
6
- export const handleMouseDownRectangle = ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, startMousePointRef, currentCoordinateRef, coordinatesRef, rectangleAnchorRef, }) => (event) => {
7
- if (!canvasRef.current || !isMouseClickAction(event.button, MouseAction.LEFT))
8
- return;
9
- const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
10
- if (!isInsideImage(mousePoint, canvasStateRef.current.dw, canvasStateRef.current.dh))
11
- return;
12
- mouseActionRef.current = MouseAction.LEFT;
13
- setMousePoint(mousePoint);
14
- startMousePointRef.current = mousePoint;
15
- if (currentCoordinateRef.current) {
16
- const { zoom } = canvasStateRef.current;
17
- selectRectangleAtPoint(zoom, mousePointRef.current, coordinatesRef, currentCoordinateRef);
18
- updateActiveRectangleAnchor(zoom, mousePointRef.current, currentCoordinateRef, rectangleAnchorRef);
19
- }
20
- event.preventDefault();
21
- };
22
- export const handleMouseMoveRectangle = ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, prevMousePointRef, currentCoordinateRef, coordinatesRef, rectangleAnchorRef, }) => (event) => {
23
- if (!canvasRef.current || !isMouseClickAction(event.button, MouseAction.LEFT))
24
- return;
25
- prevMousePointRef.current = cloneDeep(mousePointRef.current);
26
- const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
27
- setMousePoint(mousePoint);
28
- handleBBoxOperations({
29
- coordinatesRef,
30
- dw: canvasStateRef.current.dw,
31
- dh: canvasStateRef.current.dh,
32
- mousePoint: mousePointRef.current,
33
- prevMousePoint: prevMousePointRef.current,
34
- mouseAction: mouseActionRef.current,
35
- currentCoordinate: currentCoordinateRef.current,
36
- rectangleAnchor: rectangleAnchorRef.current,
37
- });
38
- event.preventDefault();
39
- };
40
- export const handleMouseUpRectangle = ({ canvasRef, canvasStateRef, mouseActionRef, mousePointRef, setMousePoint, startMousePointRef, prevMousePointRef, currentCoordinateRef, coordinatesRef, setCoordinates, rectangleAnchorRef, drawLabelRef, historyRef, }) => (event) => {
41
- if (!canvasRef.current || !isMouseClickAction(event.button, MouseAction.LEFT))
42
- return;
43
- const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
44
- setMousePoint(mousePoint);
45
- if (startMousePointRef.current) {
46
- const movedWidth = Math.abs(startMousePointRef.current.x - mousePoint.x);
47
- const movedHeight = Math.abs(startMousePointRef.current.y - mousePoint.y);
48
- const { zoom, dw, dh } = canvasStateRef.current;
49
- if (movedWidth > ACTIVE_POINT_SIZE || movedHeight > ACTIVE_POINT_SIZE) {
50
- const { x, y, width, height } = clampBoundingBoxToImage(Math.min(startMousePointRef.current.x, mousePoint.x), Math.min(startMousePointRef.current.y, mousePoint.y), movedWidth, movedHeight, dw, dh);
51
- if (currentCoordinateRef.current) {
52
- historyRef.current?.add(cloneDeep(coordinatesRef.current));
53
- }
54
- else {
55
- const label = drawLabelRef.current;
56
- const newCoordinate = { label, type: DrawMode.RECTANGLE, x, y, width, height, selected: false };
57
- coordinatesRef.current.push(newCoordinate);
58
- setCoordinates(coordinatesRef.current);
59
- if (!historyRef.current) {
60
- historyRef.current = createHistory();
61
- historyRef.current.addInit();
62
- }
63
- historyRef.current?.add(cloneDeep(coordinatesRef.current));
64
- currentCoordinateRef.current = null;
65
- }
66
- }
67
- else {
68
- selectRectangleAtPoint(zoom, mousePointRef.current, coordinatesRef, currentCoordinateRef);
69
- setCoordinates(coordinatesRef.current);
70
- }
71
- }
72
- mouseActionRef.current = null;
73
- startMousePointRef.current = null;
74
- prevMousePointRef.current = null;
75
- rectangleAnchorRef.current = null;
76
- event.preventDefault();
77
- };
78
- export const handleMouseLeaveRectangle = ({ canvasRef, canvasStateRef, setMousePoint, startMousePointRef, prevMousePointRef, mouseActionRef, rectangleAnchorRef, }) => (event) => {
79
- if (!canvasRef.current)
80
- return;
81
- const mousePoint = getCanvasMousePoint(event, canvasRef.current, canvasStateRef.current);
82
- setMousePoint(mousePoint);
83
- mouseActionRef.current = null;
84
- startMousePointRef.current = null;
85
- prevMousePointRef.current = null;
86
- rectangleAnchorRef.current = null;
87
- event.preventDefault();
88
- };
@@ -1,28 +0,0 @@
1
- import { RefObject } from 'react';
2
- import { Coordinate, Point, Rectangle, CanvasState } from '../../../../types';
3
- import { MouseAction } from '../../../../utils/mouseActions';
4
- import { RectangleAnchor } from '../../../../enum/common';
5
- export declare const ACTIVE_POINT_SIZE = 10;
6
- export declare const getRectangleCorners: ({ x, y, width, height }: Rectangle) => {
7
- x: number;
8
- y: number;
9
- }[];
10
- export declare const selectRectangleAtPoint: (zoom: number, mousePoint: Point, coordinatesRef: RefObject<Coordinate[]>, currentCoordinateRef: RefObject<Coordinate | null>) => void;
11
- export declare const updateActiveRectangleAnchor: (zoom: number, mousePointRef: Point, currentCoordinateRef: RefObject<Coordinate | null>, rectangleAnchorRef: RefObject<RectangleAnchor | null>) => void;
12
- export declare const clampBoundingBoxToImage: (x: number, y: number, width: number, height: number, dw: number, dh: number) => Rectangle & {
13
- selected?: boolean;
14
- };
15
- export declare const getCanvasMousePoint: (event: globalThis.MouseEvent | React.MouseEvent, canvas: HTMLCanvasElement, canvasState: CanvasState) => Point;
16
- type BBoxParams = {
17
- coordinatesRef: RefObject<Coordinate[]>;
18
- dw: number;
19
- dh: number;
20
- mousePoint: Point;
21
- prevMousePoint: Point;
22
- mouseAction: MouseAction | null;
23
- currentCoordinate: Coordinate | null;
24
- rectangleAnchor: RectangleAnchor | null;
25
- };
26
- export declare const handleBBoxOperations: (params: BBoxParams) => void;
27
- export declare const isInsideImage: (point: Point, imageWidth: number, imageHeight: number) => boolean;
28
- export {};
@@ -1,204 +0,0 @@
1
- import { MouseAction } from '../../../../utils/mouseActions';
2
- import { DrawMode, RectangleAnchor } from '../../../../enum/common';
3
- import { getMousePointTransform } from '../../../../utils/pointTransform';
4
- export const ACTIVE_POINT_SIZE = 10;
5
- export const getRectangleCorners = ({ x, y, width, height }) => {
6
- return [
7
- { x, y },
8
- { x: x + width, y },
9
- { x, y: y + height },
10
- { x: x + width, y: y + height },
11
- ];
12
- };
13
- export const selectRectangleAtPoint = (zoom, mousePoint, coordinatesRef, currentCoordinateRef) => {
14
- const coordinates = coordinatesRef.current;
15
- const { x: mouseX, y: mouseY } = mousePoint;
16
- const padding = ACTIVE_POINT_SIZE / zoom;
17
- const isPointInBBox = (c) => mouseX >= c.x - padding &&
18
- mouseX <= c.x + c.width + padding &&
19
- mouseY >= c.y - padding &&
20
- mouseY <= c.y + c.height + padding;
21
- let selectedIndex = -1;
22
- let minArea = Number.MAX_SAFE_INTEGER;
23
- const currentIndex = coordinates.findIndex((c) => c.selected);
24
- if (currentIndex >= 0) {
25
- const c = coordinates[currentIndex];
26
- if (c.type === DrawMode.RECTANGLE && isPointInBBox(c)) {
27
- selectedIndex = currentIndex;
28
- minArea = c.width * c.height;
29
- }
30
- }
31
- if (selectedIndex === -1) {
32
- coordinates.forEach((c, idx) => {
33
- if (c.type !== DrawMode.RECTANGLE || !isPointInBBox(c))
34
- return;
35
- const area = c.width * c.height;
36
- if (area < minArea) {
37
- minArea = area;
38
- selectedIndex = idx;
39
- }
40
- });
41
- }
42
- coordinates.forEach((c) => (c.selected = false));
43
- if (selectedIndex >= 0) {
44
- coordinates[selectedIndex].selected = true;
45
- currentCoordinateRef.current = coordinates[selectedIndex];
46
- }
47
- else {
48
- currentCoordinateRef.current = null;
49
- }
50
- };
51
- export const updateActiveRectangleAnchor = (zoom, mousePointRef, currentCoordinateRef, rectangleAnchorRef) => {
52
- if (!currentCoordinateRef.current)
53
- return;
54
- const points = getRectangleCorners(currentCoordinateRef.current);
55
- const pointSize = ACTIVE_POINT_SIZE / zoom;
56
- const { x: mouseX, y: mouseY } = mousePointRef;
57
- const { x, y, width: w, height: h } = currentCoordinateRef.current;
58
- if (mouseX >= points[0].x - pointSize / 2 &&
59
- mouseX <= points[0].x + pointSize / 2 &&
60
- mouseY >= points[0].y - pointSize / 2 &&
61
- mouseY <= points[0].y + pointSize / 2) {
62
- rectangleAnchorRef.current = RectangleAnchor.LEFT_TOP;
63
- }
64
- else if (mouseX >= points[1].x - pointSize / 2 &&
65
- mouseX <= points[1].x + pointSize / 2 &&
66
- mouseY >= points[1].y - pointSize / 2 &&
67
- mouseY <= points[1].y + pointSize / 2) {
68
- rectangleAnchorRef.current = RectangleAnchor.RIGHT_TOP;
69
- }
70
- else if (mouseX >= points[2].x - pointSize / 2 &&
71
- mouseX <= points[2].x + pointSize / 2 &&
72
- mouseY >= points[2].y - pointSize / 2 &&
73
- mouseY <= points[2].y + pointSize / 2) {
74
- rectangleAnchorRef.current = RectangleAnchor.LEFT_BOTTOM;
75
- }
76
- else if (mouseX >= points[3].x - pointSize / 2 &&
77
- mouseX <= points[3].x + pointSize / 2 &&
78
- mouseY >= points[3].y - pointSize / 2 &&
79
- mouseY <= points[3].y + pointSize / 2) {
80
- rectangleAnchorRef.current = RectangleAnchor.RIGHT_BOTTOM;
81
- }
82
- else if (mouseX >= x && mouseX <= x + w && mouseY >= y - pointSize / 2 && mouseY <= y + pointSize / 2) {
83
- rectangleAnchorRef.current = RectangleAnchor.TOP;
84
- }
85
- else if (mouseX >= x && mouseX <= x + w && mouseY >= y + h - pointSize / 2 && mouseY <= y + h + pointSize / 2) {
86
- rectangleAnchorRef.current = RectangleAnchor.BOTTOM;
87
- }
88
- else if (mouseY >= y && mouseY <= y + h && mouseX >= x - pointSize / 2 && mouseX <= x + pointSize / 2) {
89
- rectangleAnchorRef.current = RectangleAnchor.LEFT;
90
- }
91
- else if (mouseY >= y && mouseY <= y + h && mouseX >= x + w - pointSize / 2 && mouseX <= x + w + pointSize / 2) {
92
- rectangleAnchorRef.current = RectangleAnchor.RIGHT;
93
- }
94
- else {
95
- rectangleAnchorRef.current = null;
96
- }
97
- };
98
- export const clampBoundingBoxToImage = (x, y, width, height, dw, dh) => {
99
- let correctedX = x;
100
- let correctedY = y;
101
- let correctedWidth = width;
102
- let correctedHeight = height;
103
- if (x + width > dw)
104
- correctedWidth = dw - x;
105
- if (y + height > dh)
106
- correctedHeight = dh - y;
107
- if (x < 0) {
108
- correctedWidth = width + x;
109
- correctedX = 0;
110
- }
111
- if (y < 0) {
112
- correctedHeight = height + y;
113
- correctedY = 0;
114
- }
115
- return {
116
- x: correctedX,
117
- y: correctedY,
118
- width: Math.max(0, correctedWidth),
119
- height: Math.max(0, correctedHeight),
120
- selected: false,
121
- };
122
- };
123
- export const getCanvasMousePoint = (event, canvas, canvasState) => {
124
- const rect = canvas.getBoundingClientRect();
125
- const { moveX, moveY, zoomX, zoomY, zoom, dx, dy } = canvasState;
126
- const mouseX = event.clientX - rect.left;
127
- const mouseY = event.clientY - rect.top;
128
- 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);
129
- };
130
- const moveBBox = ({ coordinatesRef, dw, dh, mousePoint, prevMousePoint, mouseAction, currentCoordinate, rectangleAnchor, }) => {
131
- if (mouseAction === MouseAction.LEFT &&
132
- currentCoordinate &&
133
- rectangleAnchor === null &&
134
- mousePoint &&
135
- prevMousePoint) {
136
- const findIndex = coordinatesRef.current.findIndex((coordinate) => coordinate.selected);
137
- const findCoordinate = coordinatesRef.current[findIndex];
138
- if (findIndex >= 0 && findCoordinate) {
139
- const newX = currentCoordinate.x + mousePoint.x - prevMousePoint.x;
140
- const newY = currentCoordinate.y + mousePoint.y - prevMousePoint.y;
141
- findCoordinate.x = Math.max(0, Math.min(newX, dw - findCoordinate.width));
142
- findCoordinate.y = Math.max(0, Math.min(newY, dh - findCoordinate.height));
143
- }
144
- }
145
- };
146
- const editBBox = ({ dw, dh, mousePoint, prevMousePoint, mouseAction, currentCoordinate, rectangleAnchor, coordinatesRef, }) => {
147
- if (rectangleAnchor && mouseAction === MouseAction.LEFT && currentCoordinate && mousePoint && prevMousePoint) {
148
- const findIndex = coordinatesRef.current.findIndex((coordinate) => coordinate.selected);
149
- const findCoordinate = coordinatesRef.current[findIndex];
150
- if (findIndex >= 0 && findCoordinate) {
151
- const dx = mousePoint.x - prevMousePoint.x;
152
- const dy = mousePoint.y - prevMousePoint.y;
153
- switch (rectangleAnchor) {
154
- case RectangleAnchor.LEFT_TOP:
155
- findCoordinate.x += dx;
156
- findCoordinate.y += dy;
157
- findCoordinate.width -= dx;
158
- findCoordinate.height -= dy;
159
- break;
160
- case RectangleAnchor.RIGHT_TOP:
161
- findCoordinate.y += dy;
162
- findCoordinate.width += dx;
163
- findCoordinate.height -= dy;
164
- break;
165
- case RectangleAnchor.LEFT_BOTTOM:
166
- findCoordinate.x += dx;
167
- findCoordinate.width -= dx;
168
- findCoordinate.height += dy;
169
- break;
170
- case RectangleAnchor.RIGHT_BOTTOM:
171
- findCoordinate.width += dx;
172
- findCoordinate.height += dy;
173
- break;
174
- case RectangleAnchor.TOP:
175
- findCoordinate.y += dy;
176
- findCoordinate.height -= dy;
177
- break;
178
- case RectangleAnchor.BOTTOM:
179
- findCoordinate.height += dy;
180
- break;
181
- case RectangleAnchor.LEFT:
182
- findCoordinate.x += dx;
183
- findCoordinate.width -= dx;
184
- break;
185
- case RectangleAnchor.RIGHT:
186
- findCoordinate.width += dx;
187
- break;
188
- default:
189
- break;
190
- }
191
- findCoordinate.x = Math.max(0, Math.min(findCoordinate.x, dw - findCoordinate.width));
192
- findCoordinate.y = Math.max(0, Math.min(findCoordinate.y, dh - findCoordinate.height));
193
- findCoordinate.width = Math.max(0, Math.min(findCoordinate.width, dw - findCoordinate.x));
194
- findCoordinate.height = Math.max(0, Math.min(findCoordinate.height, dh - findCoordinate.y));
195
- }
196
- }
197
- };
198
- export const handleBBoxOperations = (params) => {
199
- moveBBox(params);
200
- editBBox(params);
201
- };
202
- export const isInsideImage = (point, imageWidth, imageHeight) => {
203
- return point.x >= 0 && point.y >= 0 && point.x <= imageWidth && point.y <= imageHeight;
204
- };
@@ -1,25 +0,0 @@
1
- import { RefObject } from 'react';
2
- import { Point, Coordinate, CanvasState, Label } from '../../../../types';
3
- import { DrawMode, RectangleAnchor } from '../../../../enum/common';
4
- import { MouseAction } from '../../../../utils/mouseActions';
5
- import { CoordinateHistory } from '../../../AnnotationCanvas/_utils/createHistory';
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<Coordinate[]>;
16
- setCoordinates: (coordinates: Coordinate[]) => void;
17
- rectangleAnchorRef: RefObject<RectangleAnchor | null>;
18
- maskImageRef: RefObject<HTMLImageElement | null>;
19
- drawLabelRef: RefObject<Label | undefined>;
20
- historyRef: RefObject<CoordinateHistory | null>;
21
- };
22
- export declare const useDrawEvents: (params: DrawEventsParams & {
23
- selectedDrawMode?: DrawMode;
24
- editable: boolean;
25
- }) => void;