Sauvegarde initiale de l'application
This commit is contained in:
387
static/js/script.js
Normal file
387
static/js/script.js
Normal 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 l’activation 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
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user