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:
parent
f250d015b8
commit
5cacde11b1
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in New Issue