feat: Add countdown timer to photo taking button

NEW FEATURE: Photo Countdown Timer
 Added 3-second countdown timer before photo capture
 Large visual countdown overlay on camera preview
 Animated countdown numbers with pulse effect
 Cancel button to abort photo capture during countdown
 Button state management during countdown process

TECHNICAL IMPLEMENTATION:
- startPhotoTimer() method with configurable duration (default 3 seconds)
- Full-screen countdown overlay with large numbers
- Pulse animation for visual feedback
- Cancel functionality to abort countdown
- Proper cleanup of timers and UI elements
- Integration with both regular and progress photo sessions

USER EXPERIENCE:
- Click 'Take Photo'  3-second countdown begins
- Large countdown numbers (3, 2, 1) display over camera feed
- Cancel button available during countdown
- Automatic photo capture after countdown
- Visual feedback with 'Get Ready' and 'Capturing' states

BENEFITS:
 Gives users time to position themselves properly
 Reduces camera shake from button press
 Professional photo session feel
 Option to cancel if not ready
 Clear visual feedback during countdown

Works with all photo capture scenarios including interactive tasks!
This commit is contained in:
dilgenfritz 2025-10-28 08:17:19 -05:00
parent f250d015b8
commit 5cacde11b1
1 changed files with 127 additions and 2 deletions

View File

@ -164,7 +164,7 @@ class WebcamManager {
*/
bindCameraControlsWithProgress() {
document.getElementById('capture-photo').addEventListener('click', () => {
this.capturePhoto();
this.startPhotoTimer();
});
document.getElementById('retake-photo').addEventListener('click', () => {
@ -438,7 +438,7 @@ class WebcamManager {
*/
bindCameraControls() {
document.getElementById('capture-photo').addEventListener('click', () => {
this.capturePhoto();
this.startPhotoTimer();
});
document.getElementById('retake-photo').addEventListener('click', () => {
@ -472,6 +472,131 @@ class WebcamManager {
console.log('📸 Photo captured');
}
/**
* Start photo countdown timer
*/
startPhotoTimer(duration = 3) {
const captureBtn = document.getElementById('capture-photo');
const originalText = captureBtn.innerHTML;
let timeLeft = duration;
let cancelled = false;
// Disable capture button and show cancel option
captureBtn.disabled = true;
captureBtn.style.opacity = '0.7';
// Create large countdown overlay
const cameraPreview = document.querySelector('.camera-preview');
const countdownOverlay = document.createElement('div');
countdownOverlay.id = 'countdown-overlay';
countdownOverlay.style.cssText = `
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
border-radius: 10px;
`;
const countdownText = document.createElement('div');
countdownText.id = 'countdown-text';
countdownText.style.cssText = `
font-size: 72px;
font-weight: bold;
color: white;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
animation: pulse 1s infinite;
margin-bottom: 20px;
`;
const cancelBtn = document.createElement('button');
cancelBtn.textContent = '❌ Cancel';
cancelBtn.style.cssText = `
background: rgba(220, 53, 69, 0.8);
color: white;
border: none;
padding: 10px 20px;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
transition: all 0.3s;
`;
cancelBtn.addEventListener('click', () => {
cancelled = true;
countdownOverlay.remove();
captureBtn.innerHTML = originalText;
captureBtn.disabled = false;
captureBtn.style.opacity = '1';
console.log('📱 Photo timer cancelled');
});
countdownOverlay.appendChild(countdownText);
countdownOverlay.appendChild(cancelBtn);
cameraPreview.style.position = 'relative';
cameraPreview.appendChild(countdownOverlay);
// Add pulse animation
if (!document.getElementById('pulse-animation-style')) {
const style = document.createElement('style');
style.id = 'pulse-animation-style';
style.textContent = `
@keyframes pulse {
0% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.1); opacity: 0.8; }
100% { transform: scale(1); opacity: 1; }
}
`;
document.head.appendChild(style);
}
// Create countdown display
const updateCountdown = () => {
if (cancelled) return; // Stop if cancelled
if (timeLeft > 0) {
captureBtn.innerHTML = `📷 Get Ready...`;
countdownText.textContent = timeLeft;
timeLeft--;
setTimeout(updateCountdown, 1000);
} else {
// Show capture indicator
countdownText.textContent = '📸';
countdownText.style.fontSize = '96px';
cancelBtn.style.display = 'none'; // Hide cancel button
captureBtn.innerHTML = '📸 Capturing...';
setTimeout(() => {
if (!cancelled) {
// Take the photo
this.capturePhoto();
// Remove countdown overlay
countdownOverlay.remove();
// Reset button after capture
setTimeout(() => {
captureBtn.innerHTML = originalText;
captureBtn.disabled = false;
captureBtn.style.opacity = '1';
}, 500);
}
}, 500);
}
};
// Start countdown
updateCountdown();
console.log(`📱 Photo timer started: ${duration} seconds`);
}
/**
* Show captured photo preview
*/