Sauvegarde initiale de l'application

This commit is contained in:
2024-12-15 19:46:39 +01:00
commit 75dcd7df5a
25 changed files with 1108 additions and 0 deletions

387
static/js/script.js Normal file
View File

@@ -0,0 +1,387 @@
const modeDebug = false; // Passez à true pour activer le mode debug
document.addEventListener('DOMContentLoaded', () => {
toggleDebugMode(); // Appliquer le mode debug au chargement de la page
});
function toggleDebugMode() {
const debugElements = document.querySelectorAll('[data-debug="true"]');
debugElements.forEach(element => {
element.style.display = modeDebug ? 'block' : 'none';
});
console.log(`Mode debug ${modeDebug ? 'activé' : 'désactivé'}`);
}
document.addEventListener('DOMContentLoaded', () => {
// Votre code ici
});
let wakeLock = null;
async function enableWakeLock() {
try {
if ('wakeLock' in navigator) {
const wakeLock = await navigator.wakeLock.request('screen');
console.log('Verrouillage de lécran activé.');
return wakeLock;
} else {
console.warn('API Wake Lock non prise en charge par ce navigateur.');
}
} catch (error) {
console.error('Erreur lors de lactivation du verrouillage de lécran :', error);
}
}
// Fonction pour réactiver le Wake Lock si la page redevient visible
function handleVisibilityChange() {
if (wakeLock !== null && document.visibilityState === 'visible') {
enableWakeLock();
}
}
// Activer le Wake Lock au chargement de la page
document.addEventListener('DOMContentLoaded', () => {
enableWakeLock();
});
function showPopup(challenge) {
if (!challenge) {
console.error("Aucune donnée de défi actif !");
return;
}
const { image, textFound, mode } = challenge;
// Créer l'élément popup
const popup = document.createElement('div');
popup.id = 'popup';
popup.style.position = 'fixed';
popup.style.top = '50%';
popup.style.left = '50%';
popup.style.transform = 'translate(-50%, -50%)';
popup.style.padding = '20px';
popup.style.backgroundColor = '#fff';
popup.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
popup.style.zIndex = '1000';
// Ajouter l'image
const img = document.createElement('img');
img.src = image;
img.alt = 'Défi actif';
img.style.width = '100%';
popup.appendChild(img);
// Ajouter le texte trouvé
const text = document.createElement('p');
text.textContent = `Texte à trouver : ${textFound}`;
popup.appendChild(text);
// Ajouter une action en fonction du mode
if (mode === 'message') {
const message = document.createElement('p');
message.textContent = "Mode : Message";
popup.appendChild(message);
} else if (mode === 'reponse') {
const input = document.createElement('input');
input.type = 'text';
input.placeholder = 'Entrez votre réponse';
popup.appendChild(input);
const submitButton = document.createElement('button');
submitButton.textContent = 'Envoyer';
popup.appendChild(submitButton);
}
// Ajouter un bouton pour fermer
const closeButton = document.createElement('button');
closeButton.textContent = 'Fermer';
closeButton.onclick = () => document.body.removeChild(popup);
popup.appendChild(closeButton);
// Ajouter le popup au corps de la page
document.body.appendChild(popup);
}
// Fonction pour charger les données utilisateur
async function fetchUserData() {
try {
const response = await fetch(`/user/${username}`);
const userData = await response.json();
console.log("Données utilisateur :", userData);
// Mettre à jour l'interface avec les données
document.getElementById('user-name').textContent = userData.nom;
document.getElementById('user-avatar').src = userData.avatar;
document.getElementById('user-progression').textContent = userData.progression;
// Trouver le premier défi non résolu
let firstUnresolvedChallenge = null;
let challengeNumber = null;
for (let i = 1; i <= 6; i++) {
const challengeKey = `defi_${i}`;
const challenge = userData.defis[challengeKey];
if (challenge.resolu === "non") {
firstUnresolvedChallenge = challenge;
challengeNumber = i;
break; // On arrête dès qu'on trouve le premier défi non résolu
}
}
if (firstUnresolvedChallenge) {
const { latitude, longitude } = firstUnresolvedChallenge.geolocalisation;
// Mettre à jour la variable globale target
target = { latitude, longitude };
// Extraire les informations du défi actif
const { image_1, text_found_1, mode } = firstUnresolvedChallenge;
// Stocker les informations du défi actif dans une variable globale
window.activeChallenge = {
image: image_1,
textFound: text_found_1,
mode: mode,
};
// Mettre à jour l'interface avec les coordonnées du défi
document.getElementById('target-latitude').textContent = latitude.toFixed(6);
document.getElementById('target-longitude').textContent = longitude.toFixed(6);
document.getElementById('challenge-number').textContent = `défi n°${challengeNumber}`;
} else {
console.log("Tous les défis sont résolus !");
target = null; // Réinitialisation de la cible
}
} catch (error) {
console.error("Erreur lors du chargement des données utilisateur :", error);
}
}
// Charger les données utilisateur dès le chargement de la page
document.addEventListener('DOMContentLoaded', () => {
fetchUserData(); // Charger les données au démarrage
setInterval(fetchUserData, 10000); // Actualiser toutes les 10 secondes
});
// Coordonnées de la cible
//let target = { latitude: 45.141916, longitude: 4.075059 }; // Coordonnées de la cible
//let currentHeading = 0; // Orientation actuelle de l'appareil
let lastDistance = null;
// Variables pour les coins de la droite virtuelle
let topLeft = { x: 2, y: 2 }; // Coin supérieur gauche en pixels
let bottomRight = { x: window.innerWidth - 100, y: window.innerHeight - 250 }; // Coin inférieur droit en pixels
// Fonction pour recalculer les coins dynamiquement
function updateCorners() {
bottomRight = {
x: window.innerWidth - 100,
y: window.innerHeight - 250
};
}
window.addEventListener('resize', updateCorners);
// Fonction utilitaire pour définir le halo
function setHaloColor(element, color) {
element.style.boxShadow = `0 0 20px 10px ${color}`;
}
// Fonction pour mettre à jour le style de Avatar
function updateAvatarStyle(distance) {
const avatar = document.getElementById('user-avatar');
if (distance > 20) {
setHaloColor(avatar, 'rgba(0, 0, 255, 0.6)'); // Halo bleu
} else if (distance <= 10) {
setHaloColor(avatar, 'rgba(255, 0, 0, 0.6)'); // Halo rouge
} else {
setHaloColor(avatar, 'rgba(27, 28, 29, 0.6)'); // Halo gris
}
}
function positionAvatar(distance) {
const avatar = document.getElementById('user-avatar');
if (!avatar) {
console.error("L'élément 'user-avatar' n'existe pas dans le DOM.");
return;
}
if (distance > 25) {
avatar.style.left = `${topLeft.x}px`;
avatar.style.top = `${topLeft.y}px`;
} else if (distance <= 5) {
avatar.style.left = `${bottomRight.x}px`;
avatar.style.top = `${bottomRight.y}px`;
} else {
const ratio = (25 - distance) / 20;
const newX = topLeft.x + (bottomRight.x - topLeft.x) * ratio;
const newY = topLeft.y + (bottomRight.y - topLeft.y) * ratio;
avatar.style.left = `${newX}px`;
avatar.style.top = `${newY}px`;
}
}
// Fonction pour gérer les flèches directionnelles
function updateArrows(distance) {
const arrowApproaching = document.getElementById('arrow-approaching');
const arrowMovingAway = document.getElementById('arrow-moving-away');
if (lastDistance !== null) {
if (distance < lastDistance) {
arrowApproaching.style.display = 'block';
arrowMovingAway.style.display = 'none';
} else {
arrowApproaching.style.display = 'none';
arrowMovingAway.style.display = 'block';
}
}
}
// Fonction pour calculer la direction vers la cible (bearing)
function calculateBearing(lat1, lon1, lat2, lon2) {
const toRad = (value) => (value * Math.PI) / 180;
const toDeg = (value) => (value * 180) / Math.PI;
const dLon = toRad(lon2 - lon1);
const y = Math.sin(dLon) * Math.cos(toRad(lat2));
const x = Math.cos(toRad(lat1)) * Math.sin(toRad(lat2)) -
Math.sin(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.cos(dLon);
return (toDeg(Math.atan2(y, x)) + 360) % 360; // Angle en degrés, ajusté pour être positif
}
// Fonction pour mettre à jour l'orientation de la flèche
function updateCompass(bearing) {
const arrow = document.getElementById('arrow-black');
const angle = (bearing - currentHeading + 360) % 360; // Ajuste selon l'orientation actuelle
arrow.style.transform = `rotate(${angle}deg)`; // Applique la rotation
}
// Écoute les changements d'orientation de l'appareil
window.addEventListener('deviceorientation', (event) => {
currentHeading = event.alpha || 0; // Orientation absolue en degrés
});
// Fonction principale pour mettre à jour les éléments
function updatePosition(position) {
const { latitude, longitude } = position.coords;
document.getElementById('latitude').textContent = latitude.toFixed(6);
document.getElementById('longitude').textContent = longitude.toFixed(6);
if (!target) {
console.warn("Aucune cible définie. Impossible de calculer la distance ou la direction.");
return;
}
const distance = calculateDistance(latitude, longitude, target.latitude, target.longitude);
document.getElementById('distance').textContent = `${distance.toFixed(0)} m`;
const bearing = calculateBearing(latitude, longitude, target.latitude, target.longitude);
positionAvatar(distance);
updateAvatarStyle(distance);
updateArrows(distance);
updateCompass(bearing);
// Afficher le popup si distance < 5m
if (distance < 4) {
showPopup(window.activeChallenge);
}
lastDistance = distance;
}
// Fonction pour calculer la distance entre deux points GPS (Haversine Formula)
function calculateDistance(lat1, lon1, lat2, lon2) {
const R = 6371000; // Rayon de la Terre en mètres
const toRad = (value) => (value * Math.PI) / 180;
const dLat = toRad(lat2 - lat1);
const dLon = toRad(lon2 - lon1);
const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
// Gestion des erreurs de géolocalisation
function handleError(error) {
const errorMessages = {
1: "Permission refusée",
2: "Position indisponible",
3: "Délai dépassé"
};
alert("Erreur de géolocalisation : " + errorMessages[error.code] || "Erreur inconnue");
}
// Initialiser la géolocalisation en temps réel
function startTracking() {
if (!navigator.geolocation) {
alert("La géolocalisation n'est pas prise en charge par votre navigateur.");
return;
}
navigator.geolocation.watchPosition(updatePosition, handleError, {
enableHighAccuracy: true,
maximumAge: 0,
timeout: 5000
});
}
// Démarrer le suivi dès le chargement de la page
startTracking();
const positionUpdateInterval = 1000 * 5; // 5 secondes (à récupérer dynamiquement depuis config.yaml)
// Fonction pour envoyer les nouvelles coordonnées au serveur
async function updateServerPosition(latitude, longitude) {
const now = new Date().toISOString(); // Format ISO 8601 pour last_update
try {
const response = await fetch('/update-position', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
latitude: latitude,
longitude: longitude,
last_update: now // Inclure le champ last_update
})
});
const result = await response.json();
console.log("Position mise à jour :", result.message);
} catch (error) {
console.error("Erreur lors de la mise à jour de la position :", error);
}
}
// Mise à jour de la position toutes les X secondes
function startPositionUpdates() {
setInterval(() => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
const { latitude, longitude } = position.coords;
updateServerPosition(latitude, longitude);
});
} else {
console.error("La géolocalisation n'est pas prise en charge.");
}
}, positionUpdateInterval);
}
// Lancer le suivi dès le chargement de la page
document.addEventListener('DOMContentLoaded', () => {
startPositionUpdates();
startTracking(); // Fonction existante pour afficher les mises à jour côté client
});