Tina Tarighian
commited on
Commit
·
5f82b57
1
Parent(s):
c5e133c
mobile ratio
Browse files- components/CameraSetup.js +40 -26
- components/MainContent.js +1 -4
- hooks/useDeviceAndCanvas.js +24 -6
components/CameraSetup.js
CHANGED
@@ -16,6 +16,20 @@ const CameraSetup = ({
|
|
16 |
// Track if camera is currently being set up
|
17 |
const isSettingUpCamera = useRef(false);
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
// Set up the webcam
|
20 |
useEffect(() => {
|
21 |
// Set mounted flag
|
@@ -35,17 +49,24 @@ const CameraSetup = ({
|
|
35 |
tracks.forEach(track => track.stop());
|
36 |
}
|
37 |
|
38 |
-
// Get camera
|
39 |
-
const
|
40 |
-
video: {
|
41 |
facingMode: facingMode,
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
},
|
45 |
audio: false
|
46 |
-
}
|
|
|
|
|
47 |
|
48 |
-
// Check if component is still mounted before continuing
|
49 |
if (!isMounted.current) {
|
50 |
stream.getTracks().forEach(track => track.stop());
|
51 |
return;
|
@@ -53,30 +74,20 @@ const CameraSetup = ({
|
|
53 |
|
54 |
videoRef.current.srcObject = stream;
|
55 |
|
56 |
-
//
|
|
|
|
|
57 |
try {
|
58 |
await videoRef.current.play();
|
|
|
|
|
59 |
} catch (playError) {
|
60 |
console.log("Play interrupted, this is normal if component remounted:", playError);
|
61 |
-
// Don't treat play interruptions as fatal errors
|
62 |
if (playError.name !== "AbortError") {
|
63 |
throw playError;
|
64 |
}
|
65 |
}
|
66 |
|
67 |
-
// Get the actual video dimensions once metadata is loaded
|
68 |
-
videoRef.current.onloadedmetadata = () => {
|
69 |
-
if (!isMounted.current) return;
|
70 |
-
|
71 |
-
const videoWidth = videoRef.current.videoWidth;
|
72 |
-
const videoHeight = videoRef.current.videoHeight;
|
73 |
-
const aspectRatio = videoWidth / videoHeight;
|
74 |
-
setVideoAspectRatio(aspectRatio);
|
75 |
-
|
76 |
-
// Update canvas size with the correct aspect ratio
|
77 |
-
updateCanvasSize(aspectRatio);
|
78 |
-
};
|
79 |
-
|
80 |
if (isMounted.current) {
|
81 |
setCameraError(false);
|
82 |
console.log("Camera set up successfully");
|
@@ -98,12 +109,15 @@ const CameraSetup = ({
|
|
98 |
// Set mounted flag to false to prevent state updates after unmount
|
99 |
isMounted.current = false;
|
100 |
|
101 |
-
if (videoRef.current
|
102 |
-
|
103 |
-
|
|
|
|
|
|
|
104 |
}
|
105 |
};
|
106 |
-
}, [videoRef, canvasRef, containerRef, facingMode
|
107 |
|
108 |
// Function to switch camera
|
109 |
const switchCamera = async () => {
|
|
|
16 |
// Track if camera is currently being set up
|
17 |
const isSettingUpCamera = useRef(false);
|
18 |
|
19 |
+
const updateDimensions = () => {
|
20 |
+
if (!videoRef.current || !isMounted.current) return;
|
21 |
+
|
22 |
+
const videoWidth = videoRef.current.videoWidth;
|
23 |
+
const videoHeight = videoRef.current.videoHeight;
|
24 |
+
|
25 |
+
// Only update if we have valid dimensions
|
26 |
+
if (videoWidth && videoHeight) {
|
27 |
+
const aspectRatio = videoWidth / videoHeight;
|
28 |
+
setVideoAspectRatio(aspectRatio);
|
29 |
+
updateCanvasSize(aspectRatio);
|
30 |
+
}
|
31 |
+
};
|
32 |
+
|
33 |
// Set up the webcam
|
34 |
useEffect(() => {
|
35 |
// Set mounted flag
|
|
|
49 |
tracks.forEach(track => track.stop());
|
50 |
}
|
51 |
|
52 |
+
// Get camera constraints based on device
|
53 |
+
const constraints = {
|
54 |
+
video: {
|
55 |
facingMode: facingMode,
|
56 |
+
// For mobile, prioritize height to prevent letterboxing
|
57 |
+
...(isMobile ? {
|
58 |
+
height: { ideal: 1080, min: 720 },
|
59 |
+
width: { ideal: 1920, min: 1280 }
|
60 |
+
} : {
|
61 |
+
width: { ideal: 1920 },
|
62 |
+
height: { ideal: 1080 }
|
63 |
+
})
|
64 |
},
|
65 |
audio: false
|
66 |
+
};
|
67 |
+
|
68 |
+
const stream = await navigator.mediaDevices.getUserMedia(constraints);
|
69 |
|
|
|
70 |
if (!isMounted.current) {
|
71 |
stream.getTracks().forEach(track => track.stop());
|
72 |
return;
|
|
|
74 |
|
75 |
videoRef.current.srcObject = stream;
|
76 |
|
77 |
+
// Add loadeddata event listener for more reliable dimension detection
|
78 |
+
videoRef.current.addEventListener('loadeddata', updateDimensions);
|
79 |
+
|
80 |
try {
|
81 |
await videoRef.current.play();
|
82 |
+
// Double check dimensions after a short delay to ensure they're correct
|
83 |
+
setTimeout(updateDimensions, 100);
|
84 |
} catch (playError) {
|
85 |
console.log("Play interrupted, this is normal if component remounted:", playError);
|
|
|
86 |
if (playError.name !== "AbortError") {
|
87 |
throw playError;
|
88 |
}
|
89 |
}
|
90 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
if (isMounted.current) {
|
92 |
setCameraError(false);
|
93 |
console.log("Camera set up successfully");
|
|
|
109 |
// Set mounted flag to false to prevent state updates after unmount
|
110 |
isMounted.current = false;
|
111 |
|
112 |
+
if (videoRef.current) {
|
113 |
+
videoRef.current.removeEventListener('loadeddata', updateDimensions);
|
114 |
+
if (videoRef.current.srcObject) {
|
115 |
+
const tracks = videoRef.current.srcObject.getTracks();
|
116 |
+
tracks.forEach(track => track.stop());
|
117 |
+
}
|
118 |
}
|
119 |
};
|
120 |
+
}, [videoRef, canvasRef, containerRef, facingMode]);
|
121 |
|
122 |
// Function to switch camera
|
123 |
const switchCamera = async () => {
|
components/MainContent.js
CHANGED
@@ -63,10 +63,7 @@ const MainContent = ({
|
|
63 |
<canvas
|
64 |
ref={canvasRef}
|
65 |
className="rounded-lg shadow-lg w-full"
|
66 |
-
style={{
|
67 |
-
height: `${canvasHeight}px`,
|
68 |
-
...(isMobile && { margin: '0 auto', display: 'block' })
|
69 |
-
}}
|
70 |
width={canvasWidth}
|
71 |
height={canvasHeight}
|
72 |
/>
|
|
|
63 |
<canvas
|
64 |
ref={canvasRef}
|
65 |
className="rounded-lg shadow-lg w-full"
|
66 |
+
style={{ height: `${canvasHeight}px` }}
|
|
|
|
|
|
|
67 |
width={canvasWidth}
|
68 |
height={canvasHeight}
|
69 |
/>
|
hooks/useDeviceAndCanvas.js
CHANGED
@@ -43,14 +43,32 @@ const useDeviceAndCanvas = () => {
|
|
43 |
if (!isComponentMounted.current) return;
|
44 |
|
45 |
const containerWidth = document.querySelector('.canvas-container')?.clientWidth || window.innerWidth;
|
46 |
-
|
|
|
|
|
47 |
const maxWidth = Math.min(containerWidth, isMobile ? 640 : 960);
|
48 |
-
//
|
49 |
-
const
|
50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
-
|
53 |
-
|
|
|
54 |
}, [isMobile]);
|
55 |
|
56 |
return {
|
|
|
43 |
if (!isComponentMounted.current) return;
|
44 |
|
45 |
const containerWidth = document.querySelector('.canvas-container')?.clientWidth || window.innerWidth;
|
46 |
+
const windowHeight = window.innerHeight;
|
47 |
+
|
48 |
+
// Set maximum dimensions for the canvas
|
49 |
const maxWidth = Math.min(containerWidth, isMobile ? 640 : 960);
|
50 |
+
// For mobile, limit height to 70% of viewport height to prevent excessive scrolling
|
51 |
+
const maxHeight = isMobile ? windowHeight * 0.7 : windowHeight * 0.8;
|
52 |
+
|
53 |
+
// Calculate dimensions maintaining aspect ratio within constraints
|
54 |
+
let width = maxWidth;
|
55 |
+
let height = width / aspectRatio;
|
56 |
+
|
57 |
+
// If height exceeds max height, recalculate width to maintain aspect ratio
|
58 |
+
if (height > maxHeight) {
|
59 |
+
height = maxHeight;
|
60 |
+
width = height * aspectRatio;
|
61 |
+
}
|
62 |
+
|
63 |
+
// Ensure width doesn't exceed container
|
64 |
+
if (width > containerWidth) {
|
65 |
+
width = containerWidth;
|
66 |
+
height = width / aspectRatio;
|
67 |
+
}
|
68 |
|
69 |
+
// Round dimensions to prevent subpixel rendering issues
|
70 |
+
setCanvasWidth(Math.round(width));
|
71 |
+
setCanvasHeight(Math.round(height));
|
72 |
}, [isMobile]);
|
73 |
|
74 |
return {
|