@deepnoid/canvas 0.1.22 → 0.1.23
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.
|
@@ -7,10 +7,10 @@ import { usePanZoom } from '../hooks/usePanZoom';
|
|
|
7
7
|
const AnnotatedCanvas = ({ image, coordinates, panZoomable = false, ZoomButton, resetOnImageChange = true, editable = false, onImageLoadError, onImageLoadSuccess, }) => {
|
|
8
8
|
const canvasRef = useRef(null);
|
|
9
9
|
const [displayCoordinates, setDisplayCoordinates] = useState();
|
|
10
|
-
const { image: loadedImage, isLoading, error } = useImageLoader(image, 10000, onImageLoadSuccess, onImageLoadError);
|
|
10
|
+
const { image: loadedImage, isLoading, error, imageRef, } = useImageLoader(image, 10000, onImageLoadSuccess, onImageLoadError);
|
|
11
11
|
const { moveX, moveY, zoom, initZoom, zoomX, zoomY, dx, dy, dw, dh, handleWheel, handleMouseDown, handleMouseMove, handleMouseUp, handleMouseLeave, initCanvas, } = usePanZoom({
|
|
12
12
|
canvasRef,
|
|
13
|
-
|
|
13
|
+
imageRef,
|
|
14
14
|
panZoomable,
|
|
15
15
|
resetOnImageChange,
|
|
16
16
|
});
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { RefObject, WheelEvent, MouseEvent } from 'react';
|
|
2
2
|
type UsePanZoomProps = {
|
|
3
3
|
canvasRef: RefObject<HTMLCanvasElement | null>;
|
|
4
|
-
|
|
4
|
+
imageRef: RefObject<HTMLImageElement | null>;
|
|
5
5
|
panZoomable?: boolean;
|
|
6
6
|
resetOnImageChange?: boolean;
|
|
7
7
|
};
|
|
8
|
-
export declare const usePanZoom: ({ canvasRef,
|
|
8
|
+
export declare const usePanZoom: ({ canvasRef, imageRef, panZoomable, resetOnImageChange, }: UsePanZoomProps) => {
|
|
9
9
|
moveX: number;
|
|
10
10
|
moveY: number;
|
|
11
11
|
zoom: number;
|
|
@@ -17,7 +17,7 @@ export declare const usePanZoom: ({ canvasRef, image, panZoomable, resetOnImageC
|
|
|
17
17
|
dw: number;
|
|
18
18
|
dh: number;
|
|
19
19
|
handleWheel: (event: WheelEvent) => void;
|
|
20
|
-
handleMouseDown: (event: MouseEvent) =>
|
|
20
|
+
handleMouseDown: (event: MouseEvent) => void;
|
|
21
21
|
handleMouseMove: (event: MouseEvent) => void;
|
|
22
22
|
handleMouseUp: (event: MouseEvent) => void;
|
|
23
23
|
handleMouseLeave: (event: MouseEvent) => void;
|
package/dist/hooks/usePanZoom.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useCallback, useEffect, useState
|
|
2
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
3
3
|
import { resolutionCanvas, drawCanvas, getMousePointTransform, canvasCenterPoint } from '../utils/graphic';
|
|
4
4
|
import { MouseStatus } from '../enum/common';
|
|
5
5
|
import useResizeObserver from './useResizeObserver';
|
|
6
|
-
export const usePanZoom = ({ canvasRef,
|
|
6
|
+
export const usePanZoom = ({ canvasRef, imageRef, panZoomable = false, resetOnImageChange = true, }) => {
|
|
7
7
|
const ZOOM_UNIT = 0.9;
|
|
8
8
|
const MAX_ZOOM = 4;
|
|
9
9
|
const MIN_ZOOM = 0.5;
|
|
@@ -20,8 +20,7 @@ export const usePanZoom = ({ canvasRef, image, panZoomable = false, resetOnImage
|
|
|
20
20
|
const [moveY, setMoveY] = useState(0);
|
|
21
21
|
const [status, setStatus] = useState('');
|
|
22
22
|
const [imageOnloadCount, setImageOnloadCount] = useState(0);
|
|
23
|
-
const [
|
|
24
|
-
const imageRef = useRef(new Image());
|
|
23
|
+
const [startMousePoint, setStartMousePoint] = useState();
|
|
25
24
|
const calculatorZoomPoint = useCallback((canvasEl, movementX, movementY, dx, dy) => {
|
|
26
25
|
let x = 0;
|
|
27
26
|
let y = 0;
|
|
@@ -30,18 +29,15 @@ export const usePanZoom = ({ canvasRef, image, panZoomable = false, resetOnImage
|
|
|
30
29
|
y = -dy - movementY + canvasEl.height / 2;
|
|
31
30
|
}
|
|
32
31
|
return { x, y };
|
|
33
|
-
}, []);
|
|
34
|
-
const calculateInitZoom = useCallback((
|
|
35
|
-
if (
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
? canvasEl.clientHeight / image.height
|
|
43
|
-
: canvasEl.clientWidth / image.width;
|
|
44
|
-
}
|
|
32
|
+
}, [canvasRef]);
|
|
33
|
+
const calculateInitZoom = useCallback((canvasEl, image) => {
|
|
34
|
+
if (!image)
|
|
35
|
+
return 1;
|
|
36
|
+
const canvasRatio = canvasEl.clientWidth / canvasEl.clientHeight;
|
|
37
|
+
const imageRatio = image.naturalWidth / image.naturalHeight;
|
|
38
|
+
return canvasRatio < imageRatio
|
|
39
|
+
? canvasEl.clientWidth / image.naturalWidth
|
|
40
|
+
: canvasEl.clientHeight / image.naturalHeight;
|
|
45
41
|
}, []);
|
|
46
42
|
const init = (canvasEl, image) => {
|
|
47
43
|
const point = canvasCenterPoint(canvasEl, image);
|
|
@@ -51,7 +47,7 @@ export const usePanZoom = ({ canvasRef, image, panZoomable = false, resetOnImage
|
|
|
51
47
|
setDh(image.height);
|
|
52
48
|
setMoveX(0);
|
|
53
49
|
setMoveY(0);
|
|
54
|
-
const init_zoom = calculateInitZoom(
|
|
50
|
+
const init_zoom = calculateInitZoom(canvasEl, image);
|
|
55
51
|
setZoom(init_zoom);
|
|
56
52
|
setInitZoom(init_zoom);
|
|
57
53
|
const zoomPoint = calculatorZoomPoint(canvasEl, 0, 0, point.x, point.y);
|
|
@@ -59,7 +55,7 @@ export const usePanZoom = ({ canvasRef, image, panZoomable = false, resetOnImage
|
|
|
59
55
|
setZoomY(zoomPoint.y);
|
|
60
56
|
};
|
|
61
57
|
const initCanvas = () => {
|
|
62
|
-
if (
|
|
58
|
+
if (imageRef?.current) {
|
|
63
59
|
const canvasEl = resolutionCanvas(canvasRef.current);
|
|
64
60
|
if (canvasEl)
|
|
65
61
|
init(canvasEl, imageRef.current);
|
|
@@ -67,96 +63,77 @@ export const usePanZoom = ({ canvasRef, image, panZoomable = false, resetOnImage
|
|
|
67
63
|
}
|
|
68
64
|
};
|
|
69
65
|
useEffect(() => {
|
|
66
|
+
const image = imageRef?.current;
|
|
70
67
|
if (image) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
78
|
-
setImageOnloadCount((prev) => prev + 1);
|
|
79
|
-
};
|
|
68
|
+
if (resetOnImageChange) {
|
|
69
|
+
const canvasEl = resolutionCanvas(canvasRef.current);
|
|
70
|
+
if (canvasEl)
|
|
71
|
+
init(canvasEl, image);
|
|
72
|
+
}
|
|
73
|
+
setImageOnloadCount((prev) => prev + 1);
|
|
80
74
|
}
|
|
81
|
-
}, [
|
|
82
|
-
const [startMousePoint, setStartMousePoint] = useState();
|
|
75
|
+
}, [imageRef?.current, resetOnImageChange]);
|
|
83
76
|
useEffect(() => {
|
|
84
77
|
const redraw = () => {
|
|
85
|
-
if (canvasRef.current) {
|
|
78
|
+
if (canvasRef.current && imageRef?.current) {
|
|
86
79
|
drawCanvas(moveX, moveY, zoomX, zoomY, zoom, dx, dy, resolutionCanvas(canvasRef.current), imageRef.current, true);
|
|
87
80
|
}
|
|
88
81
|
};
|
|
89
82
|
redraw();
|
|
90
|
-
}, [moveX, moveY, zoomX, zoomY, zoom, dx, dy, dw, dh, imageOnloadCount]);
|
|
83
|
+
}, [moveX, moveY, zoomX, zoomY, zoom, dx, dy, dw, dh, imageOnloadCount, canvasRef, imageRef]);
|
|
91
84
|
useEffect(() => {
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
setImageOnloadCount((prev) => prev + 1);
|
|
99
|
-
}
|
|
85
|
+
if (!imageRef?.current)
|
|
86
|
+
return;
|
|
87
|
+
const canvasEl = resolutionCanvas(canvasRef.current);
|
|
88
|
+
if (canvasEl && !resetOnImageChange) {
|
|
89
|
+
init(canvasEl, imageRef.current);
|
|
90
|
+
setImageOnloadCount((prev) => prev + 1);
|
|
100
91
|
}
|
|
101
|
-
}, [width, height]);
|
|
92
|
+
}, [width, height, resetOnImageChange, canvasRef, imageRef]);
|
|
102
93
|
const handleWheel = (event) => {
|
|
103
|
-
if (!panZoomable)
|
|
94
|
+
if (!panZoomable || !canvasRef.current || !imageRef?.current)
|
|
104
95
|
return;
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
setZoomY(zoomPoint.y);
|
|
115
|
-
setZoom(calc_zoom);
|
|
116
|
-
}
|
|
96
|
+
let calc_zoom = event.deltaY < 0 ? (zoom || 1) * (1 / ZOOM_UNIT) : (zoom || 1) * ZOOM_UNIT;
|
|
97
|
+
if (initZoom * MAX_ZOOM < zoom * ZOOM_UNIT)
|
|
98
|
+
calc_zoom = calc_zoom * ZOOM_UNIT;
|
|
99
|
+
if (initZoom * MIN_ZOOM > zoom * ZOOM_UNIT)
|
|
100
|
+
calc_zoom = calc_zoom * (1 / ZOOM_UNIT);
|
|
101
|
+
const zoomPoint = calculatorZoomPoint(canvasRef.current, moveX, moveY, dx, dy);
|
|
102
|
+
setZoomX(zoomPoint.x);
|
|
103
|
+
setZoomY(zoomPoint.y);
|
|
104
|
+
setZoom(calc_zoom);
|
|
117
105
|
};
|
|
118
106
|
const handleMouseMove = (event) => {
|
|
119
|
-
if (!panZoomable)
|
|
107
|
+
if (!panZoomable || status !== MouseStatus.MOVE || !canvasRef.current || !imageRef?.current)
|
|
120
108
|
return;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
x = x - startMousePoint.x;
|
|
132
|
-
y = y - startMousePoint.y;
|
|
133
|
-
}
|
|
134
|
-
setMoveX(moveX + x);
|
|
135
|
-
setMoveY(moveY + y);
|
|
136
|
-
const zoomPoint = calculatorZoomPoint(canvasEl, moveX + x, moveY + y, dx, dy);
|
|
137
|
-
setZoomX(zoomPoint.x);
|
|
138
|
-
setZoomY(zoomPoint.y);
|
|
139
|
-
}
|
|
109
|
+
const canvasEl = canvasRef.current;
|
|
110
|
+
const rect = canvasEl.getBoundingClientRect();
|
|
111
|
+
const mouseX = event.clientX - rect.left;
|
|
112
|
+
const mouseY = event.clientY - rect.top;
|
|
113
|
+
const mouse = getMousePointTransform({ x: mouseX, y: mouseY }, { x: moveX, y: moveY }, { x: zoomX, y: zoomY }, { x: dx, y: dy }, zoom || 1, canvasEl);
|
|
114
|
+
let x = mouse.x;
|
|
115
|
+
let y = mouse.y;
|
|
116
|
+
if (startMousePoint) {
|
|
117
|
+
x -= startMousePoint.x;
|
|
118
|
+
y -= startMousePoint.y;
|
|
140
119
|
}
|
|
120
|
+
setMoveX(moveX + x);
|
|
121
|
+
setMoveY(moveY + y);
|
|
122
|
+
const zoomPoint = calculatorZoomPoint(canvasEl, moveX + x, moveY + y, dx, dy);
|
|
123
|
+
setZoomX(zoomPoint.x);
|
|
124
|
+
setZoomY(zoomPoint.y);
|
|
141
125
|
event.preventDefault();
|
|
142
126
|
};
|
|
143
127
|
const handleMouseDown = (event) => {
|
|
144
|
-
if (!panZoomable)
|
|
145
|
-
return
|
|
128
|
+
if (!panZoomable || !canvasRef.current || !imageRef?.current)
|
|
129
|
+
return;
|
|
146
130
|
setStatus(MouseStatus.MOVE);
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const x = mouse.x;
|
|
154
|
-
const y = mouse.y;
|
|
155
|
-
setStartMousePoint({
|
|
156
|
-
x: x,
|
|
157
|
-
y: y,
|
|
158
|
-
});
|
|
159
|
-
}
|
|
131
|
+
const canvasEl = canvasRef.current;
|
|
132
|
+
const rect = canvasEl.getBoundingClientRect();
|
|
133
|
+
const mouseX = event.clientX - rect.left;
|
|
134
|
+
const mouseY = event.clientY - rect.top;
|
|
135
|
+
const mouse = getMousePointTransform({ x: mouseX, y: mouseY }, { x: moveX, y: moveY }, { x: zoomX, y: zoomY }, { x: dx, y: dy }, zoom || 1, canvasEl);
|
|
136
|
+
setStartMousePoint({ x: mouse.x, y: mouse.y });
|
|
160
137
|
event.preventDefault();
|
|
161
138
|
};
|
|
162
139
|
const handleMouseUp = (event) => {
|