1
0
forked from orson/bachemap
bachemap/templates/camera.html
2025-03-14 18:00:31 -06:00

188 lines
6.5 KiB
HTML

{% extends 'base.html' %}
{% block head %}
<title>Take a Photo with Geolocation</title>
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
#camera-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#video {
width: 100%;
height: 100%;
object-fit: cover;
}
#canvas {
display: none;
width: 100%;
height: 100%;
object-fit: cover;
}
#file-fallback {
display: none;
position: fixed;
bottom: 100px;
left: 50%;
transform: translateX(-50%);
z-index: 100;
background: rgba(255, 255, 255, 0.8);
padding: 10px;
border-radius: 10px;
color: black;
}
</style>
{% endblock %}
{% block content %}
<div id="camera-container">
<video id="video" autoplay playsinline></video>
<canvas id="canvas"></canvas>
</div>
<div style="position: absolute; bottom: 0; width: 100%; display: flex; flex-direction: column; padding: 10px; box-sizing: border-box;">
<button id="capture-btn" class="control-button" style="margin: 10px;">Tomar foto</button>
<div style="display: flex; justify-content: space-between; width: 100%; box-sizing: border-box;">
<button id="retake-btn" class="control-button" style="display: none; margin: 10px 5px 10px 10px; flex: 1; left:20%; background-color: rgba(180,0,0,0.6);">Nueva foto</button>
<button id="send-btn" class="control-button" style="display: none; margin: 10px 10px 10px 5px; flex: 1;">Enviar foto</button>
</div>
</div>
<form id="camera-form" action="{{ url_for('camera') }}" method="POST" enctype="multipart/form-data" style="display:none;">
<input type="hidden" name="latitude" id="latitude" value="">
<input type="hidden" name="longitude" id="longitude" value="">
<input type="hidden" name="has_image" id="has_image" value="false">
<!-- Fallback file input for unsupported browsers -->
<div id="file-fallback">
<label for="photo">Take/Choose a Photo:</label>
<input type="file" name="photo" id="photo" accept="image/*" capture="environment" required>
<button type="submit">Upload</button>
</div>
</form>
<script>
// Get DOM elements
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const captureBtn = document.getElementById('capture-btn');
const retakeBtn = document.getElementById('retake-btn');
const sendBtn = document.getElementById('send-btn');
const form = document.getElementById('camera-form');
const fallbackInput = document.getElementById('file-fallback');
const hasImageInput = document.getElementById('has_image');
// Set up camera stream
async function setupCamera() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: {
facingMode: 'environment',
width: { ideal: window.innerWidth },
height: { ideal: window.innerHeight }
},
audio: false
});
video.srcObject = stream;
} catch (err) {
console.error('Error accessing camera:', err);
fallbackInput.style.display = 'block';
}
}
// Initialize camera if supported
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
setupCamera();
} else {
console.error('getUserMedia not supported');
fallbackInput.style.display = 'block';
}
// Capture photo from video feed
captureBtn.addEventListener('click', function() {
const context = canvas.getContext('2d');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
context.drawImage(video, 0, 0, canvas.width, canvas.height);
// Stop camera stream
video.srcObject.getTracks().forEach(track => track.stop());
video.style.display = 'none';
canvas.style.display = 'block';
// Update controls
captureBtn.style.display = 'none';
retakeBtn.style.display = 'inline-block';
sendBtn.style.display = 'inline-block';
// Mark that we have an image
hasImageInput.value = 'true';
});
// Retake photo
retakeBtn.addEventListener('click', function() {
canvas.style.display = 'none';
video.style.display = 'block';
captureBtn.style.display = 'inline-block';
retakeBtn.style.display = 'none';
sendBtn.style.display = 'none';
hasImageInput.value = 'false';
setupCamera();
});
// Send photo
sendBtn.addEventListener('click', function() {
if (hasImageInput.value === 'true') {
// Convert canvas to blob and append to FormData
canvas.toBlob(function(blob) {
const formData = new FormData(form);
formData.delete('photo'); // Remove any file input value
formData.append('photo', blob, 'camera-capture.jpg');
// Submit form data via fetch
fetch(form.action, {
method: 'POST',
body: formData
}).then(response => {
if (response.redirected) {
window.location.href = response.url;
} else (response.ok) {
console.log('Success:', response);
window.location.href = '{{ url_for('dashboard') }}';
}
}).catch(error => console.error('Error:', error));
}, 'image/jpeg', 0.9);
}
});
// Request Geolocation Permission and Set Form Fields
if ('geolocation' in navigator) {
navigator.geolocation.getCurrentPosition(
(position) => {
document.getElementById('latitude').value = position.coords.latitude;
document.getElementById('longitude').value = position.coords.longitude;
},
(error) => {
console.error('Error getting location:', error);
},
{
enableHighAccuracy: true,
timeout: 5000
}
);
} else {
console.error('Geolocation not supported in this browser.');
}
</script>
{% endblock %}