@capgo/camera-preview 7.4.0-beta.13 → 7.4.0-beta.16
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.
- package/README.md +19 -18
- package/android/.gradle/8.14.2/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.14.2/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.14.2/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.14.2/fileHashes/resourceHashesCache.bin +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/file-system.probe +0 -0
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +271 -20
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +816 -134
- package/android/src/main/java/com/ahm/capacitor/camera/preview/model/CameraSessionConfiguration.java +9 -0
- package/dist/docs.json +39 -23
- package/dist/esm/definitions.d.ts +20 -10
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +1 -0
- package/dist/esm/web.js +266 -38
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +266 -38
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +266 -38
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +430 -71
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +139 -114
- package/package.json +1 -1
package/dist/plugin.js
CHANGED
|
@@ -62,47 +62,57 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
62
62
|
this.videoElement.playsInline = true;
|
|
63
63
|
this.videoElement.muted = true;
|
|
64
64
|
this.videoElement.autoplay = true;
|
|
65
|
+
// Remove objectFit as we'll match camera's native aspect ratio
|
|
66
|
+
this.videoElement.style.backgroundColor = "transparent";
|
|
67
|
+
// Reset any default margins that might interfere
|
|
68
|
+
this.videoElement.style.margin = "0";
|
|
69
|
+
this.videoElement.style.padding = "0";
|
|
65
70
|
container.appendChild(this.videoElement);
|
|
66
71
|
if (options.toBack) {
|
|
67
72
|
this.videoElement.style.zIndex = "-1";
|
|
68
73
|
}
|
|
74
|
+
// Default to 16:9 vertical (9:16 for portrait) if no aspect ratio or size specified
|
|
75
|
+
const useDefaultAspectRatio = !options.aspectRatio && !options.width && !options.height;
|
|
76
|
+
const effectiveAspectRatio = options.aspectRatio || (useDefaultAspectRatio ? "16:9" : null);
|
|
69
77
|
if (options.width) {
|
|
70
78
|
this.videoElement.width = options.width;
|
|
79
|
+
this.videoElement.style.width = `${options.width}px`;
|
|
71
80
|
}
|
|
72
81
|
if (options.height) {
|
|
73
82
|
this.videoElement.height = options.height;
|
|
74
|
-
|
|
75
|
-
|
|
83
|
+
this.videoElement.style.height = `${options.height}px`;
|
|
84
|
+
}
|
|
85
|
+
// Handle positioning - center if x or y not provided
|
|
86
|
+
const centerX = options.x === undefined;
|
|
87
|
+
const centerY = options.y === undefined;
|
|
88
|
+
// Always set position to absolute for proper positioning
|
|
89
|
+
this.videoElement.style.position = "absolute";
|
|
90
|
+
console.log("Initial positioning flags:", {
|
|
91
|
+
centerX,
|
|
92
|
+
centerY,
|
|
93
|
+
x: options.x,
|
|
94
|
+
y: options.y,
|
|
95
|
+
});
|
|
96
|
+
if (options.x !== undefined) {
|
|
76
97
|
this.videoElement.style.left = `${options.x}px`;
|
|
77
98
|
}
|
|
99
|
+
if (options.y !== undefined) {
|
|
100
|
+
this.videoElement.style.top = `${options.y}px`;
|
|
101
|
+
}
|
|
78
102
|
// Create and add grid overlay if needed
|
|
79
103
|
if (gridMode !== "none") {
|
|
80
104
|
const gridOverlay = this.createGridOverlay(gridMode);
|
|
81
105
|
gridOverlay.id = "camera-grid-overlay";
|
|
82
106
|
parent === null || parent === void 0 ? void 0 : parent.appendChild(gridOverlay);
|
|
83
107
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
.map(Number);
|
|
91
|
-
const ratio = widthRatio / heightRatio;
|
|
92
|
-
if (options.width) {
|
|
93
|
-
this.videoElement.height = options.width / ratio;
|
|
94
|
-
}
|
|
95
|
-
else if (options.height) {
|
|
96
|
-
this.videoElement.width = options.height * ratio;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
else {
|
|
100
|
-
this.videoElement.style.objectFit = "cover";
|
|
101
|
-
}
|
|
108
|
+
// Aspect ratio handling is now done after getting camera stream
|
|
109
|
+
// Store centering flags for later use
|
|
110
|
+
const needsCenterX = centerX;
|
|
111
|
+
const needsCenterY = centerY;
|
|
112
|
+
console.log("Centering flags stored:", { needsCenterX, needsCenterY });
|
|
113
|
+
// First get the camera stream with basic constraints
|
|
102
114
|
const constraints = {
|
|
103
115
|
video: {
|
|
104
|
-
width: { ideal: this.videoElement.width || 640 },
|
|
105
|
-
height: { ideal: this.videoElement.height || window.innerHeight },
|
|
106
116
|
facingMode: this.isBackCamera ? "environment" : "user",
|
|
107
117
|
},
|
|
108
118
|
};
|
|
@@ -113,16 +123,182 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
113
123
|
if (!this.videoElement) {
|
|
114
124
|
throw new Error("video element not found");
|
|
115
125
|
}
|
|
126
|
+
// Get the actual camera dimensions from the video track
|
|
127
|
+
const videoTrack = stream.getVideoTracks()[0];
|
|
128
|
+
const settings = videoTrack.getSettings();
|
|
129
|
+
const cameraWidth = settings.width || 640;
|
|
130
|
+
const cameraHeight = settings.height || 480;
|
|
131
|
+
const cameraAspectRatio = cameraWidth / cameraHeight;
|
|
132
|
+
console.log("Camera native dimensions:", {
|
|
133
|
+
width: cameraWidth,
|
|
134
|
+
height: cameraHeight,
|
|
135
|
+
aspectRatio: cameraAspectRatio,
|
|
136
|
+
});
|
|
137
|
+
console.log("Container dimensions:", {
|
|
138
|
+
width: container.offsetWidth,
|
|
139
|
+
height: container.offsetHeight,
|
|
140
|
+
id: container.id,
|
|
141
|
+
});
|
|
142
|
+
// Now adjust video element size based on camera's native aspect ratio
|
|
143
|
+
if (!options.width && !options.height && !options.aspectRatio) {
|
|
144
|
+
// No size specified, fit camera view within container bounds
|
|
145
|
+
const containerWidth = container.offsetWidth || window.innerWidth;
|
|
146
|
+
const containerHeight = container.offsetHeight || window.innerHeight;
|
|
147
|
+
// Calculate dimensions that fit within container while maintaining camera aspect ratio
|
|
148
|
+
let targetWidth, targetHeight;
|
|
149
|
+
// Try fitting to container width first
|
|
150
|
+
targetWidth = containerWidth;
|
|
151
|
+
targetHeight = targetWidth / cameraAspectRatio;
|
|
152
|
+
// If height exceeds container, fit to height instead
|
|
153
|
+
if (targetHeight > containerHeight) {
|
|
154
|
+
targetHeight = containerHeight;
|
|
155
|
+
targetWidth = targetHeight * cameraAspectRatio;
|
|
156
|
+
}
|
|
157
|
+
console.log("Video element dimensions:", {
|
|
158
|
+
width: targetWidth,
|
|
159
|
+
height: targetHeight,
|
|
160
|
+
container: { width: containerWidth, height: containerHeight },
|
|
161
|
+
});
|
|
162
|
+
this.videoElement.width = targetWidth;
|
|
163
|
+
this.videoElement.height = targetHeight;
|
|
164
|
+
this.videoElement.style.width = `${targetWidth}px`;
|
|
165
|
+
this.videoElement.style.height = `${targetHeight}px`;
|
|
166
|
+
// Center the video element within its parent container
|
|
167
|
+
if (needsCenterX || options.x === undefined) {
|
|
168
|
+
const x = Math.round((containerWidth - targetWidth) / 2);
|
|
169
|
+
this.videoElement.style.left = `${x}px`;
|
|
170
|
+
}
|
|
171
|
+
if (needsCenterY || options.y === undefined) {
|
|
172
|
+
const y = Math.round((window.innerHeight - targetHeight) / 2);
|
|
173
|
+
this.videoElement.style.setProperty("top", `${y}px`, "important");
|
|
174
|
+
// Force a style recalculation
|
|
175
|
+
this.videoElement.offsetHeight;
|
|
176
|
+
console.log("Centering video:", {
|
|
177
|
+
viewportHeight: window.innerHeight,
|
|
178
|
+
targetHeight,
|
|
179
|
+
calculatedY: y,
|
|
180
|
+
actualTop: this.videoElement.style.top,
|
|
181
|
+
position: this.videoElement.style.position,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else if (effectiveAspectRatio && !options.width && !options.height) {
|
|
186
|
+
// Aspect ratio specified but no size
|
|
187
|
+
const [widthRatio, heightRatio] = effectiveAspectRatio
|
|
188
|
+
.split(":")
|
|
189
|
+
.map(Number);
|
|
190
|
+
const targetRatio = widthRatio / heightRatio;
|
|
191
|
+
const viewportWidth = window.innerWidth;
|
|
192
|
+
const viewportHeight = window.innerHeight;
|
|
193
|
+
let targetWidth, targetHeight;
|
|
194
|
+
// Try fitting to viewport width first
|
|
195
|
+
targetWidth = viewportWidth;
|
|
196
|
+
targetHeight = targetWidth / targetRatio;
|
|
197
|
+
// If height exceeds viewport, fit to height instead
|
|
198
|
+
if (targetHeight > viewportHeight) {
|
|
199
|
+
targetHeight = viewportHeight;
|
|
200
|
+
targetWidth = targetHeight * targetRatio;
|
|
201
|
+
}
|
|
202
|
+
this.videoElement.width = targetWidth;
|
|
203
|
+
this.videoElement.height = targetHeight;
|
|
204
|
+
this.videoElement.style.width = `${targetWidth}px`;
|
|
205
|
+
this.videoElement.style.height = `${targetHeight}px`;
|
|
206
|
+
// Center the video element within its parent container
|
|
207
|
+
if (needsCenterX || options.x === undefined) {
|
|
208
|
+
const parentWidth = container.offsetWidth || viewportWidth;
|
|
209
|
+
const x = Math.round((parentWidth - targetWidth) / 2);
|
|
210
|
+
this.videoElement.style.left = `${x}px`;
|
|
211
|
+
}
|
|
212
|
+
if (needsCenterY || options.y === undefined) {
|
|
213
|
+
const parentHeight = container.offsetHeight || viewportHeight;
|
|
214
|
+
const y = Math.round((parentHeight - targetHeight) / 2);
|
|
215
|
+
this.videoElement.style.top = `${y}px`;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
116
218
|
this.videoElement.srcObject = stream;
|
|
117
219
|
if (!this.isBackCamera) {
|
|
118
220
|
this.videoElement.style.transform = "scaleX(-1)";
|
|
119
221
|
}
|
|
222
|
+
// Set initial zoom level if specified and supported
|
|
223
|
+
if (options.initialZoomLevel && options.initialZoomLevel !== 1.0) {
|
|
224
|
+
// videoTrack already declared above
|
|
225
|
+
if (videoTrack) {
|
|
226
|
+
const capabilities = videoTrack.getCapabilities();
|
|
227
|
+
if (capabilities.zoom) {
|
|
228
|
+
const zoomLevel = options.initialZoomLevel;
|
|
229
|
+
const minZoom = capabilities.zoom.min || 1;
|
|
230
|
+
const maxZoom = capabilities.zoom.max || 1;
|
|
231
|
+
if (zoomLevel < minZoom || zoomLevel > maxZoom) {
|
|
232
|
+
stream.getTracks().forEach((track) => track.stop());
|
|
233
|
+
throw new Error(`Initial zoom level ${zoomLevel} is not available. Valid range is ${minZoom} to ${maxZoom}`);
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
await videoTrack.applyConstraints({
|
|
237
|
+
advanced: [{ zoom: zoomLevel }],
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
console.warn(`Failed to set initial zoom level: ${error}`);
|
|
242
|
+
// Don't throw, just continue without zoom
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
120
247
|
this.isStarted = true;
|
|
248
|
+
// Wait for video to be ready and get actual dimensions
|
|
249
|
+
await new Promise((resolve) => {
|
|
250
|
+
if (this.videoElement.readyState >= 2) {
|
|
251
|
+
resolve();
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
this.videoElement.addEventListener("loadeddata", () => resolve(), {
|
|
255
|
+
once: true,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
// Ensure centering is applied after DOM updates
|
|
260
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
261
|
+
console.log("About to re-center, flags:", { needsCenterX, needsCenterY });
|
|
262
|
+
// Re-apply centering with correct parent dimensions
|
|
263
|
+
if (needsCenterX) {
|
|
264
|
+
const parentWidth = container.offsetWidth;
|
|
265
|
+
const x = Math.round((parentWidth - this.videoElement.offsetWidth) / 2);
|
|
266
|
+
this.videoElement.style.left = `${x}px`;
|
|
267
|
+
console.log("Re-centering X:", {
|
|
268
|
+
parentWidth,
|
|
269
|
+
videoWidth: this.videoElement.offsetWidth,
|
|
270
|
+
x,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (needsCenterY) {
|
|
274
|
+
const y = Math.round((window.innerHeight - this.videoElement.offsetHeight) / 2);
|
|
275
|
+
this.videoElement.style.setProperty("top", `${y}px`, "important");
|
|
276
|
+
console.log("Re-centering Y:", {
|
|
277
|
+
viewportHeight: window.innerHeight,
|
|
278
|
+
videoHeight: this.videoElement.offsetHeight,
|
|
279
|
+
y,
|
|
280
|
+
position: this.videoElement.style.position,
|
|
281
|
+
top: this.videoElement.style.top,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
// Get the actual rendered dimensions after video is loaded
|
|
285
|
+
const rect = this.videoElement.getBoundingClientRect();
|
|
286
|
+
const computedStyle = window.getComputedStyle(this.videoElement);
|
|
287
|
+
console.log("Final video element state:", {
|
|
288
|
+
rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
289
|
+
style: {
|
|
290
|
+
position: computedStyle.position,
|
|
291
|
+
left: computedStyle.left,
|
|
292
|
+
top: computedStyle.top,
|
|
293
|
+
width: computedStyle.width,
|
|
294
|
+
height: computedStyle.height,
|
|
295
|
+
},
|
|
296
|
+
});
|
|
121
297
|
return {
|
|
122
|
-
width:
|
|
123
|
-
height:
|
|
124
|
-
x:
|
|
125
|
-
y:
|
|
298
|
+
width: Math.round(rect.width),
|
|
299
|
+
height: Math.round(rect.height),
|
|
300
|
+
x: Math.round(rect.x),
|
|
301
|
+
y: Math.round(rect.y),
|
|
126
302
|
};
|
|
127
303
|
}
|
|
128
304
|
stopStream(stream) {
|
|
@@ -156,14 +332,53 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
156
332
|
if (video && video.videoWidth > 0 && video.videoHeight > 0) {
|
|
157
333
|
const canvas = document.createElement("canvas");
|
|
158
334
|
const context = canvas.getContext("2d");
|
|
159
|
-
|
|
160
|
-
|
|
335
|
+
// Calculate capture dimensions
|
|
336
|
+
let captureWidth = video.videoWidth;
|
|
337
|
+
let captureHeight = video.videoHeight;
|
|
338
|
+
let sourceX = 0;
|
|
339
|
+
let sourceY = 0;
|
|
340
|
+
// Check for conflicting parameters
|
|
341
|
+
if (options.aspectRatio && (options.width || options.height)) {
|
|
342
|
+
reject(new Error("Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start."));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// Handle aspect ratio if no width/height specified
|
|
346
|
+
if (!options.width && !options.height && options.aspectRatio) {
|
|
347
|
+
const [widthRatio, heightRatio] = options.aspectRatio.split(':').map(Number);
|
|
348
|
+
if (widthRatio && heightRatio) {
|
|
349
|
+
// For capture in portrait orientation, swap the aspect ratio (16:9 becomes 9:16)
|
|
350
|
+
const isPortrait = video.videoHeight > video.videoWidth;
|
|
351
|
+
const targetAspectRatio = isPortrait ? heightRatio / widthRatio : widthRatio / heightRatio;
|
|
352
|
+
const videoAspectRatio = video.videoWidth / video.videoHeight;
|
|
353
|
+
if (videoAspectRatio > targetAspectRatio) {
|
|
354
|
+
// Video is wider than target - crop sides
|
|
355
|
+
captureWidth = video.videoHeight * targetAspectRatio;
|
|
356
|
+
captureHeight = video.videoHeight;
|
|
357
|
+
sourceX = (video.videoWidth - captureWidth) / 2;
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
// Video is taller than target - crop top/bottom
|
|
361
|
+
captureWidth = video.videoWidth;
|
|
362
|
+
captureHeight = video.videoWidth / targetAspectRatio;
|
|
363
|
+
sourceY = (video.videoHeight - captureHeight) / 2;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
else if (options.width || options.height) {
|
|
368
|
+
// If width or height is specified, use them
|
|
369
|
+
if (options.width)
|
|
370
|
+
captureWidth = options.width;
|
|
371
|
+
if (options.height)
|
|
372
|
+
captureHeight = options.height;
|
|
373
|
+
}
|
|
374
|
+
canvas.width = captureWidth;
|
|
375
|
+
canvas.height = captureHeight;
|
|
161
376
|
// flip horizontally back camera isn't used
|
|
162
377
|
if (!this.isBackCamera) {
|
|
163
|
-
context === null || context === void 0 ? void 0 : context.translate(
|
|
378
|
+
context === null || context === void 0 ? void 0 : context.translate(captureWidth, 0);
|
|
164
379
|
context === null || context === void 0 ? void 0 : context.scale(-1, 1);
|
|
165
380
|
}
|
|
166
|
-
context === null || context === void 0 ? void 0 : context.drawImage(video, 0, 0,
|
|
381
|
+
context === null || context === void 0 ? void 0 : context.drawImage(video, sourceX, sourceY, captureWidth, captureHeight, 0, 0, captureWidth, captureHeight);
|
|
167
382
|
if (options.saveToGallery) ;
|
|
168
383
|
if (options.withExifLocation) ;
|
|
169
384
|
if ((options.format || "jpeg") === "jpeg") {
|
|
@@ -395,6 +610,7 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
395
610
|
throw new Error("zoom not supported by this device");
|
|
396
611
|
}
|
|
397
612
|
const zoomLevel = Math.max(capabilities.zoom.min || 1, Math.min(capabilities.zoom.max || 1, options.level));
|
|
613
|
+
// Note: autoFocus is not supported on web platform
|
|
398
614
|
try {
|
|
399
615
|
await videoTrack.applyConstraints({
|
|
400
616
|
advanced: [{ zoom: zoomLevel }],
|
|
@@ -517,21 +733,25 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
517
733
|
video.style.left = `${x}px`;
|
|
518
734
|
video.style.top = `${y}px`;
|
|
519
735
|
video.style.position = "absolute";
|
|
736
|
+
const offsetX = newWidth / 8;
|
|
737
|
+
const offsetY = newHeight / 8;
|
|
520
738
|
return {
|
|
521
739
|
width: Math.round(newWidth),
|
|
522
740
|
height: Math.round(newHeight),
|
|
523
|
-
x: Math.round(x),
|
|
524
|
-
y: Math.round(y),
|
|
741
|
+
x: Math.round(x + offsetX),
|
|
742
|
+
y: Math.round(y + offsetY),
|
|
525
743
|
};
|
|
526
744
|
}
|
|
527
745
|
else {
|
|
528
746
|
video.style.objectFit = "cover";
|
|
529
747
|
const rect = video.getBoundingClientRect();
|
|
748
|
+
const offsetX = rect.width / 8;
|
|
749
|
+
const offsetY = rect.height / 8;
|
|
530
750
|
return {
|
|
531
751
|
width: Math.round(rect.width),
|
|
532
752
|
height: Math.round(rect.height),
|
|
533
|
-
x: Math.round(rect.left),
|
|
534
|
-
y: Math.round(rect.top),
|
|
753
|
+
x: Math.round(rect.left + offsetX),
|
|
754
|
+
y: Math.round(rect.top + offsetY),
|
|
535
755
|
};
|
|
536
756
|
}
|
|
537
757
|
}
|
|
@@ -590,9 +810,11 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
590
810
|
if (!video) {
|
|
591
811
|
throw new Error("camera is not running");
|
|
592
812
|
}
|
|
813
|
+
const offsetX = video.width / 8;
|
|
814
|
+
const offsetY = video.height / 8;
|
|
593
815
|
return {
|
|
594
|
-
x: video.offsetLeft,
|
|
595
|
-
y: video.offsetTop,
|
|
816
|
+
x: video.offsetLeft + offsetX,
|
|
817
|
+
y: video.offsetTop + offsetY,
|
|
596
818
|
width: video.width,
|
|
597
819
|
height: video.height,
|
|
598
820
|
};
|
|
@@ -606,14 +828,20 @@ var capacitorCapacitorCameraView = (function (exports, core) {
|
|
|
606
828
|
video.style.top = `${options.y}px`;
|
|
607
829
|
video.width = options.width;
|
|
608
830
|
video.height = options.height;
|
|
831
|
+
const offsetX = options.width / 8;
|
|
832
|
+
const offsetY = options.height / 8;
|
|
609
833
|
return {
|
|
610
834
|
width: options.width,
|
|
611
835
|
height: options.height,
|
|
612
|
-
x: options.x,
|
|
613
|
-
y: options.y,
|
|
836
|
+
x: options.x + offsetX,
|
|
837
|
+
y: options.y + offsetY,
|
|
614
838
|
};
|
|
615
839
|
}
|
|
616
840
|
async setFocus(options) {
|
|
841
|
+
// Reject if values are outside 0-1 range
|
|
842
|
+
if (options.x < 0 || options.x > 1 || options.y < 0 || options.y > 1) {
|
|
843
|
+
throw new Error("Focus coordinates must be between 0 and 1");
|
|
844
|
+
}
|
|
617
845
|
const video = document.getElementById(DEFAULT_VIDEO_ID);
|
|
618
846
|
if (!(video === null || video === void 0 ? void 0 : video.srcObject)) {
|
|
619
847
|
throw new Error("camera is not running");
|