select für kamera-input
This commit is contained in:
parent
60fbe46fbf
commit
6158c9d9e0
@ -24,6 +24,11 @@
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="camera-select-wrap" class="mt-3 w-full max-w-xs hidden">
|
||||
<select id="camera-select"
|
||||
class="w-full rounded-full bg-black/50 text-white border border-white/20 px-5 py-3 text-sm focus:outline-none focus:ring-2 focus:ring-white/40 appearance-none text-center"></select>
|
||||
</div>
|
||||
|
||||
<button id="capture-btn"
|
||||
wire:loading.attr="disabled"
|
||||
@disabled($hasProcessing)
|
||||
@ -101,20 +106,73 @@
|
||||
const flash = document.getElementById('flash');
|
||||
const countdown = document.getElementById('countdown');
|
||||
const countdownNum = document.getElementById('countdown-num');
|
||||
const cameraSelectWrap = document.getElementById('camera-select-wrap');
|
||||
const cameraSelect = document.getElementById('camera-select');
|
||||
|
||||
const CAMERA_STORAGE_KEY = 'photobox_camera_id';
|
||||
|
||||
function videoConstraints(deviceId) {
|
||||
const base = { width: { ideal: 4096 }, height: { ideal: 2160 } };
|
||||
return deviceId ? { ...base, deviceId: { exact: deviceId } } : base;
|
||||
}
|
||||
|
||||
async function startCamera(deviceId) {
|
||||
if (video.srcObject) {
|
||||
video.srcObject.getTracks().forEach(track => track.stop());
|
||||
}
|
||||
|
||||
async function startCamera() {
|
||||
try {
|
||||
const stream = await navigator.mediaDevices.getUserMedia({
|
||||
video: { width: { ideal: 4096 }, height: { ideal: 2160 } },
|
||||
video: videoConstraints(deviceId),
|
||||
audio: false,
|
||||
});
|
||||
video.srcObject = stream;
|
||||
} catch {
|
||||
btn.disabled = false;
|
||||
} catch (err) {
|
||||
if (deviceId && err.name === 'OverconstrainedError') {
|
||||
localStorage.removeItem(CAMERA_STORAGE_KEY);
|
||||
return startCamera(null);
|
||||
}
|
||||
$wire.set('status', 'Camera access denied or unavailable.');
|
||||
btn.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
async function populateCameraList() {
|
||||
let devices;
|
||||
try {
|
||||
devices = await navigator.mediaDevices.enumerateDevices();
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
const cameras = devices.filter(d => d.kind === 'videoinput');
|
||||
if (cameras.length < 2) {
|
||||
cameraSelectWrap.classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
cameraSelect.innerHTML = '';
|
||||
cameras.forEach((cam, index) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = cam.deviceId;
|
||||
option.textContent = cam.label || `Camera ${index + 1}`;
|
||||
cameraSelect.appendChild(option);
|
||||
});
|
||||
|
||||
const storedId = localStorage.getItem(CAMERA_STORAGE_KEY);
|
||||
if (storedId && cameras.some(cam => cam.deviceId === storedId)) {
|
||||
cameraSelect.value = storedId;
|
||||
}
|
||||
|
||||
cameraSelectWrap.classList.remove('hidden');
|
||||
}
|
||||
|
||||
cameraSelect.addEventListener('change', () => {
|
||||
localStorage.setItem(CAMERA_STORAGE_KEY, cameraSelect.value);
|
||||
startCamera(cameraSelect.value);
|
||||
});
|
||||
|
||||
function triggerFlash() {
|
||||
flash.style.opacity = '0.8';
|
||||
setTimeout(() => flash.style.opacity = '0', 150);
|
||||
@ -149,7 +207,10 @@
|
||||
await $wire.capture(imageData);
|
||||
});
|
||||
|
||||
startCamera();
|
||||
(async () => {
|
||||
await startCamera(localStorage.getItem(CAMERA_STORAGE_KEY));
|
||||
await populateCameraList();
|
||||
})();
|
||||
</script>
|
||||
@endscript
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user