@deepnoid/canvas 0.1.27 → 0.1.28
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.
|
@@ -6,8 +6,9 @@ import { useImageLoader } from '../hooks/useImageLoader';
|
|
|
6
6
|
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
|
+
const imageRef = useRef(new Image());
|
|
9
10
|
const [displayCoordinates, setDisplayCoordinates] = useState();
|
|
10
|
-
const { image: loadedImage, isLoading, error,
|
|
11
|
+
const { image: loadedImage, isLoading, error, } = useImageLoader(image, imageRef, 10000, onImageLoadSuccess, onImageLoadError);
|
|
11
12
|
const { moveX, moveY, zoom, initZoom, zoomX, zoomY, dx, dy, dw, dh, handleWheel, handleMouseDown, handleMouseMove, handleMouseUp, handleMouseLeave, initCanvas, } = usePanZoom({
|
|
12
13
|
canvasRef,
|
|
13
14
|
imageRef,
|
|
@@ -17,7 +18,7 @@ const AnnotatedCanvas = ({ image, coordinates, panZoomable = false, ZoomButton,
|
|
|
17
18
|
const loaded = loadedImage && !isLoading;
|
|
18
19
|
useEffect(() => {
|
|
19
20
|
if (loaded) {
|
|
20
|
-
setDisplayCoordinates(
|
|
21
|
+
setDisplayCoordinates(coordinates);
|
|
21
22
|
}
|
|
22
23
|
}, [loaded, coordinates]);
|
|
23
24
|
if (!image || error)
|
|
@@ -26,6 +27,6 @@ const AnnotatedCanvas = ({ image, coordinates, panZoomable = false, ZoomButton,
|
|
|
26
27
|
flex: 1,
|
|
27
28
|
position: 'relative',
|
|
28
29
|
cursor: panZoomable ? 'grab' : 'default',
|
|
29
|
-
}, children: loaded && (_jsxs(_Fragment, { children: [_jsx("canvas", { ref: canvasRef, style: { position: 'absolute', width: '100%', height: '100%', left: 0, top: 0 } }), _jsx(Canvas, { moveX: moveX, moveY: moveY, zoomX: zoomX, zoomY: zoomY, zoom: zoom, dx: dx, dy: dy, dw: dw, dh: dh, coordinates: displayCoordinates, editable: editable }), ZoomButton && initZoom > 0 && (_jsx(ZoomButton, { onClick: initCanvas, children: `${Math.round((zoom / initZoom) * 100)}%` }))] })) }) }));
|
|
30
|
+
}, children: loaded && (_jsxs(_Fragment, { children: [_jsx("canvas", { ref: canvasRef, style: { position: 'absolute', width: '100%', height: '100%', left: 0, top: 0 } }), _jsx(Canvas, { moveX: moveX, moveY: moveY, zoomX: zoomX, zoomY: zoomY, zoom: zoom, dx: dx, dy: dy, dw: dw, dh: dh, coordinates: displayCoordinates, editable: editable }), ZoomButton && initZoom > 0 && zoom > 0 && (_jsx(ZoomButton, { onClick: initCanvas, children: `${Math.round((zoom / initZoom) * 100)}%` }))] })) }) }));
|
|
30
31
|
};
|
|
31
32
|
export default AnnotatedCanvas;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export declare const useImageLoader: (src: string, imageRef: RefObject<HTMLImageElement>, timeout?: number, onLoadSuccess?: () => void, onLoadError?: (error: Error) => void) => {
|
|
2
3
|
image: HTMLImageElement | null;
|
|
3
4
|
isLoading: boolean;
|
|
4
5
|
error: string | null;
|
|
5
|
-
imageRef: import("react").RefObject<HTMLImageElement>;
|
|
6
6
|
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useEffect,
|
|
3
|
-
export const useImageLoader = (src, timeout = 10000, onLoadSuccess, onLoadError) => {
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
export const useImageLoader = (src, imageRef, timeout = 10000, onLoadSuccess, onLoadError) => {
|
|
4
4
|
const [image, setImage] = useState(null);
|
|
5
5
|
const [isLoading, setIsLoading] = useState(false);
|
|
6
6
|
const [error, setError] = useState(null);
|
|
7
|
-
const imageRef = useRef(new Image());
|
|
8
7
|
useEffect(() => {
|
|
9
8
|
if (!src || src.trim() === '') {
|
|
10
9
|
setImage(null);
|
|
@@ -12,46 +11,61 @@ export const useImageLoader = (src, timeout = 10000, onLoadSuccess, onLoadError)
|
|
|
12
11
|
setError(null);
|
|
13
12
|
return;
|
|
14
13
|
}
|
|
14
|
+
const controller = new AbortController();
|
|
15
|
+
const { signal } = controller;
|
|
15
16
|
setIsLoading(true);
|
|
16
17
|
setError(null);
|
|
17
18
|
setImage(null);
|
|
18
19
|
const img = new Image();
|
|
19
20
|
img.crossOrigin = 'anonymous';
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
setIsLoading(false);
|
|
26
|
-
}, timeout);
|
|
27
|
-
img.onload = () => {
|
|
28
|
-
clearTimeout(timer);
|
|
29
|
-
if (img.naturalWidth === 0 || img.naturalHeight === 0) {
|
|
30
|
-
const e = new Error(`Invalid image dimensions: ${src}`);
|
|
21
|
+
img.src = src;
|
|
22
|
+
const timeoutId = setTimeout(() => {
|
|
23
|
+
if (!signal.aborted) {
|
|
24
|
+
controller.abort();
|
|
25
|
+
const e = new Error(`Image load timeout: ${src}`);
|
|
31
26
|
setError(e.message);
|
|
32
|
-
|
|
27
|
+
setIsLoading(false);
|
|
33
28
|
onLoadError?.(e);
|
|
29
|
+
}
|
|
30
|
+
}, timeout);
|
|
31
|
+
const load = async () => {
|
|
32
|
+
try {
|
|
33
|
+
await img.decode();
|
|
34
|
+
if (signal.aborted)
|
|
35
|
+
return;
|
|
36
|
+
if (img.naturalWidth === 0 || img.naturalHeight === 0) {
|
|
37
|
+
throw new Error(`Invalid image dimensions: ${src}`);
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
imageRef.current = img;
|
|
41
|
+
}
|
|
42
|
+
catch { }
|
|
43
|
+
setImage(img);
|
|
34
44
|
setIsLoading(false);
|
|
35
|
-
|
|
45
|
+
setError(null);
|
|
46
|
+
onLoadSuccess?.();
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (signal.aborted)
|
|
50
|
+
return;
|
|
51
|
+
const e = new Error(`Failed to load image: ${src}`);
|
|
52
|
+
setError(e.message);
|
|
53
|
+
setIsLoading(false);
|
|
54
|
+
onLoadError?.(err instanceof Error ? err : e);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
clearTimeout(timeoutId);
|
|
36
58
|
}
|
|
37
|
-
imageRef.current = img;
|
|
38
|
-
setImage(img);
|
|
39
|
-
setError(null);
|
|
40
|
-
onLoadSuccess?.();
|
|
41
|
-
setIsLoading(false);
|
|
42
59
|
};
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
load();
|
|
61
|
+
return () => {
|
|
62
|
+
controller.abort();
|
|
63
|
+
clearTimeout(timeoutId);
|
|
64
|
+
try {
|
|
65
|
+
img.src = '';
|
|
66
|
+
}
|
|
67
|
+
catch { }
|
|
50
68
|
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}, 0);
|
|
54
|
-
return () => clearTimeout(timer);
|
|
55
|
-
}, [src, timeout, onLoadError, onLoadSuccess]);
|
|
56
|
-
return { image, isLoading, error, imageRef };
|
|
69
|
+
}, [src, timeout, onLoadError, onLoadSuccess, imageRef]);
|
|
70
|
+
return { image, isLoading, error };
|
|
57
71
|
};
|
package/dist/hooks/usePanZoom.js
CHANGED
|
@@ -8,7 +8,6 @@ export const usePanZoom = ({ canvasRef, imageRef, panZoomable = false, resetOnIm
|
|
|
8
8
|
const MAX_ZOOM = 4;
|
|
9
9
|
const MIN_ZOOM = 0.5;
|
|
10
10
|
const { width, height } = useResizeObserver({ ref: canvasRef });
|
|
11
|
-
console.log('> width', width, ', height :', height);
|
|
12
11
|
const [initZoom, setInitZoom] = useState(0);
|
|
13
12
|
const [zoom, setZoom] = useState(0);
|
|
14
13
|
const [zoomX, setZoomX] = useState(0);
|
|
@@ -55,9 +54,7 @@ export const usePanZoom = ({ canvasRef, imageRef, panZoomable = false, resetOnIm
|
|
|
55
54
|
setZoomX(zoomPoint.x);
|
|
56
55
|
setZoomY(zoomPoint.y);
|
|
57
56
|
};
|
|
58
|
-
console.log('. imageOnloadCount ', imageOnloadCount);
|
|
59
57
|
const initCanvas = () => {
|
|
60
|
-
console.log('> initCanvas !!!!!!!!! imageRef?.current : ', imageRef?.current);
|
|
61
58
|
if (imageRef?.current) {
|
|
62
59
|
const canvasEl = resolutionCanvas(canvasRef.current);
|
|
63
60
|
if (canvasEl)
|
|
@@ -138,7 +135,12 @@ export const usePanZoom = ({ canvasRef, imageRef, panZoomable = false, resetOnIm
|
|
|
138
135
|
if (!canvasEl)
|
|
139
136
|
return;
|
|
140
137
|
const isFirstLoad = imageOnloadCount === 0;
|
|
141
|
-
if (isFirstLoad
|
|
138
|
+
if (isFirstLoad) {
|
|
139
|
+
init(canvasEl, imageRef.current);
|
|
140
|
+
setImageOnloadCount((prev) => prev + 1);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (resetOnImageChange) {
|
|
142
144
|
init(canvasEl, imageRef.current);
|
|
143
145
|
}
|
|
144
146
|
else {
|