Files
nexus-timer/src/services/CameraService.js
cpu e8db2d4701 PWA fixed
added systemd service howto

traefik

nginix set_real_ip_from

improved readme

visuals fixed on mobile

labels removed

updated readme

fixed visuals

overlay for the hotkey

disable screen lock

clean up

git precommit hooks

clean up

clean up

update

check for update feature

added build-time information

fixed date
2025-05-09 23:29:44 +02:00

69 lines
3.1 KiB
JavaScript

export const CameraService = {
async getPhoto() {
return new Promise(async (resolve, reject) => {
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
reject(new Error('Camera API not available.'));
return;
}
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: "user" }, audio: false });
// Create a modal or an overlay to show the video stream and a capture button
const videoElement = document.createElement('video');
videoElement.srcObject = stream;
videoElement.setAttribute('playsinline', ''); // Required for iOS
videoElement.style.cssText = "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); max-width: 90%; max-height: 70vh; z-index: 1001; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.2);";
const captureButton = document.createElement('button');
captureButton.textContent = 'Capture';
captureButton.style.cssText = "position: fixed; bottom: 10%; left: 50%; transform: translateX(-50%); z-index: 1002; padding: 12px 24px; background-color: #3b82f6; color: white; border: none; border-radius: 8px; font-size: 16px; cursor: pointer;";
const closeButton = document.createElement('button');
closeButton.textContent = 'Cancel';
closeButton.style.cssText = "position: fixed; top: 10px; right: 10px; z-index: 1002; padding: 8px 12px; background-color: #ef4444; color: white; border: none; border-radius: 8px; font-size: 14px; cursor: pointer;";
const overlay = document.createElement('div');
overlay.style.cssText = "position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0,0,0,0.7); z-index: 1000;";
document.body.appendChild(overlay);
document.body.appendChild(videoElement);
document.body.appendChild(captureButton);
document.body.appendChild(closeButton);
videoElement.onloadedmetadata = () => {
videoElement.play();
};
const cleanup = () => {
stream.getTracks().forEach(track => track.stop());
document.body.removeChild(videoElement);
document.body.removeChild(captureButton);
document.body.removeChild(closeButton);
document.body.removeChild(overlay);
};
captureButton.onclick = () => {
const canvas = document.createElement('canvas');
canvas.width = videoElement.videoWidth;
canvas.height = videoElement.videoHeight;
const context = canvas.getContext('2d');
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/png');
cleanup();
resolve(dataUrl);
};
closeButton.onclick = () => {
cleanup();
reject(new Error('User cancelled photo capture.'));
};
} catch (err) {
console.error("Error accessing camera: ", err);
reject(err);
}
});
}
};