inclus page final

This commit is contained in:
2024-12-24 00:52:14 +01:00
parent 1b12f3f732
commit ec777f133f
115 changed files with 6712 additions and 194 deletions

64
static/css/carte_b.css Normal file
View File

@@ -0,0 +1,64 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
overscroll-behavior: none; /* Empêche les glissements */
touch-action: none; /* Désactive les gestes tactiles */
}
html, body {
height: 100%;
width: 100%;
overflow: hidden; /* Bloque le défilement */
font-family: Arial, sans-serif;
}
.fullscreen-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 100%;
width: 100%;
background-color: black;
position: relative;
}
.fullscreen-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.header-text {
position: absolute;
top: 20px;
text-align: center;
color: red;
font-size: 2.5rem;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
background-color: rgba(255, 255, 255, 0.8);
padding: 10px 20px;
border-radius: 10px;
}
.button-container {
position: absolute;
bottom: 20px;
right: 20px;
}
.continue-button {
text-decoration: none;
color: white;
background-color: #79d2d8;
padding: 10px 20px;
border-radius: 5px;
font-size: 1.2rem;
box-shadow: 2px 2px 5px #000;
}
.continue-button:hover {
background-color: #79d2d8;
}

64
static/css/carte_j.css Normal file
View File

@@ -0,0 +1,64 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
overscroll-behavior: none; /* Empêche les glissements */
touch-action: none; /* Désactive les gestes tactiles */
}
html, body {
height: 100%;
width: 100%;
overflow: hidden; /* Bloque le défilement */
font-family: Arial, sans-serif;
}
.fullscreen-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 100%;
width: 100%;
background-color: black;
position: relative;
}
.fullscreen-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.header-text {
position: absolute;
top: 20px;
text-align: center;
color: red;
font-size: 2.5rem;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
background-color: rgba(255, 255, 255, 0.8);
padding: 10px 20px;
border-radius: 10px;
}
.button-container {
position: absolute;
bottom: 20px;
right: 20px;
}
.continue-button {
text-decoration: none;
color: white;
background-color: #b19cd5;
padding: 10px 20px;
border-radius: 5px;
font-size: 1.2rem;
box-shadow: 2px 2px 5px #000;
}
.continue-button:hover {
background-color: #b19cd5;
}

25
static/css/gagne.css Normal file
View File

@@ -0,0 +1,25 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body {
height: 100%;
width: 100%;
}
.fullscreen-container {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
overflow: hidden;
}
.fullscreen-container img {
width: 100%;
height: 100%;
object-fit: cover;
}

64
static/css/gagne_b.css Normal file
View File

@@ -0,0 +1,64 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
overscroll-behavior: none; /* Empêche les glissements */
touch-action: none; /* Désactive les gestes tactiles */
}
html, body {
height: 100%;
width: 100%;
overflow: hidden; /* Bloque le défilement */
font-family: Arial, sans-serif;
}
.fullscreen-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 100%;
width: 100%;
background-color: black;
position: relative;
}
.fullscreen-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.header-text {
position: absolute;
top: 20px;
text-align: center;
color: red;
font-size: 2.5rem;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
background-color: rgba(255, 255, 255, 0.8);
padding: 10px 20px;
border-radius: 10px;
}
.button-container {
position: absolute;
bottom: 20px;
right: 20px;
}
.continue-button {
text-decoration: none;
color: white;
background-color: #79d2d8;
padding: 10px 20px;
border-radius: 5px;
font-size: 1.2rem;
box-shadow: 2px 2px 5px #000;
}
.continue-button:hover {
background-color: #79d2d8;
}

64
static/css/gagne_j.css Normal file
View File

@@ -0,0 +1,64 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
overscroll-behavior: none; /* Empêche les glissements */
touch-action: none; /* Désactive les gestes tactiles */
}
html, body {
height: 100%;
width: 100%;
overflow: hidden; /* Bloque le défilement */
font-family: Arial, sans-serif;
}
.fullscreen-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 100%;
width: 100%;
background-color: black;
position: relative;
}
.fullscreen-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.header-text {
position: absolute;
top: 20px;
text-align: center;
color: red;
font-size: 2.5rem;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
background-color: rgba(255, 255, 255, 0.8);
padding: 10px 20px;
border-radius: 10px;
}
.button-container {
position: absolute;
bottom: 20px;
right: 20px;
}
.continue-button {
text-decoration: none;
color: white;
background-color: #b19cd5;
padding: 10px 20px;
border-radius: 5px;
font-size: 1.2rem;
box-shadow: 2px 2px 5px #000;
}
.continue-button:hover {
background-color: #b19cd5;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/E_b.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/E_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/I_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/L_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/O_b.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/P_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/R_b.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/R_b2.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/S_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/T_b.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/U_b.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

BIN
static/css/img/cartes/X_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 359 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

BIN
static/css/img/gagne.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 679 KiB

BIN
static/css/img/perdu.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 KiB

147
static/css/mystere_b.css Normal file
View File

@@ -0,0 +1,147 @@
/* Style global */
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background-color: #000;
color: #fff;
overflow: hidden;
}
/* Conteneur principal */
.fullscreen-container {
position: relative;
width: 100%;
height: 100vh;
background-image: url('../img/fond_mystere_b.webp'); /* Corrigez le chemin ici */
background-size: cover;
background-position: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* Texte en haut */
.header-text {
position: absolute;
top: 240px;
width: 350px;
left: 50%;
transform: translateX(-50%);
text-align: center;
font-size: 1.2rem;
font-weight: bold;
color: white;
text-shadow: 2px 2px 4px #000;
background-color: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 10px;
display: none; /* Masqué par défaut */
}
/* Conteneur des défis */
.defis-container {
position: absolute;
top: 10px;
width: 100%;
height: 80%; /* Ajustez la hauteur du conteneur */
}
/* Style des images des défis */
.defi-image {
position: absolute;
top: 10px;
width: 120px;
height: auto;
border: 2px solid white;
border-radius: 5px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
}
/* Exemple de positionnement des défis */
.defi-1 { top: 00px; left: 50px; }
.defi-2 { top: 00px; left: 180px; }
.defi-3 { top: 00px; left: 300px; }
.defi-4 { top: 120px; left: 50px; }
.defi-5 { top: 120px; left: 180px; }
.defi-6 { top: 120px; left: 300px; }
/* Champ de réponse */
#reponse {
position: absolute;
bottom: 200px;
left: 50%;
transform: translateX(-50%);
width: 80%;
padding: 10px;
font-size: 1.2rem;
border-radius: 5px;
border: none;
outline: none;
display: none; /* Masqué par défaut */
}
/* Bouton de validation */
#valide {
position: absolute;
bottom: 150px;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
font-size: 1.2rem;
color: white;
background-color: #007BFF;
border: none;
border-radius: 5px;
cursor: pointer;
display: none; /* Masqué par défaut */
}
/* Style de la popup */
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
text-align: center;
color: white;
z-index: 1000;
}
.popup img {
width: 350px;
height: auto;
}
.popup .close {
margin-top: 10px;
padding: 10px 20px;
background-color: #FF5722;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
/* Adaptations pour écrans mobiles */
@media (max-width: 768px) {
.defi-image {
width: 60px;
}
#reponse {
font-size: 1rem;
}
#valide {
font-size: 1rem;
}
}

147
static/css/mystere_j.css Normal file
View File

@@ -0,0 +1,147 @@
/* Style global */
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
background-color: #000;
color: #fff;
overflow: hidden;
}
/* Conteneur principal */
.fullscreen-container {
position: relative;
width: 100%;
height: 100vh;
background-image: url('../img/fond_mystere_j.webp'); /* Corrigez le chemin ici */
background-size: cover;
background-position: center;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* Texte en haut */
.header-text {
position: absolute;
top: 240px;
width: 350px;
left: 50%;
transform: translateX(-50%);
text-align: center;
font-size: 1.2rem;
font-weight: bold;
color: white;
text-shadow: 2px 2px 4px #000;
background-color: rgba(0, 0, 0, 0.7);
padding: 10px;
border-radius: 10px;
display: none; /* Masqué par défaut */
}
/* Conteneur des défis */
.defis-container {
position: absolute;
top: 10px;
width: 100%;
height: 80%; /* Ajustez la hauteur du conteneur */
}
/* Style des images des défis */
.defi-image {
position: absolute;
top: 10px;
width: 120px;
height: auto;
border: 2px solid white;
border-radius: 5px;
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.5);
}
/* Exemple de positionnement des défis */
.defi-1 { top: 00px; left: 50px; }
.defi-2 { top: 00px; left: 180px; }
.defi-3 { top: 00px; left: 300px; }
.defi-4 { top: 120px; left: 50px; }
.defi-5 { top: 120px; left: 180px; }
.defi-6 { top: 120px; left: 300px; }
/* Champ de réponse */
#reponse {
position: absolute;
bottom: 200px;
left: 50%;
transform: translateX(-50%);
width: 80%;
padding: 10px;
font-size: 1.2rem;
border-radius: 5px;
border: none;
outline: none;
display: none; /* Masqué par défaut */
}
/* Bouton de validation */
#valide {
position: absolute;
bottom: 150px;
left: 50%;
transform: translateX(-50%);
padding: 10px 20px;
font-size: 1.2rem;
color: white;
background-color: #007BFF;
border: none;
border-radius: 5px;
cursor: pointer;
display: none; /* Masqué par défaut */
}
/* Style de la popup */
.popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
background-color: rgba(0, 0, 0, 0.8);
padding: 20px;
border-radius: 10px;
text-align: center;
color: white;
z-index: 1000;
}
.popup img {
width: 350px;
height: auto;
}
.popup .close {
margin-top: 10px;
padding: 10px 20px;
background-color: #FF5722;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
/* Adaptations pour écrans mobiles */
@media (max-width: 768px) {
.defi-image {
width: 60px;
}
#reponse {
font-size: 1rem;
}
#valide {
font-size: 1rem;
}
}

64
static/css/perdu.css Normal file
View File

@@ -0,0 +1,64 @@
* {
margin: 0;
padding: 0;
box-sizing: border-box;
overscroll-behavior: none; /* Empêche les glissements */
touch-action: none; /* Désactive les gestes tactiles */
}
html, body {
height: 100%;
width: 100%;
overflow: hidden; /* Bloque le défilement */
font-family: Arial, sans-serif;
}
.fullscreen-container {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
height: 100%;
width: 100%;
background-color: black;
position: relative;
}
.fullscreen-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.header-text {
position: absolute;
top: 20px;
text-align: center;
color: red;
font-size: 2.5rem;
font-weight: bold;
text-shadow: 2px 2px 4px #000;
background-color: rgba(255, 255, 255, 0.8);
padding: 10px 20px;
border-radius: 10px;
}
.button-container {
position: absolute;
bottom: 20px;
right: 20px;
}
.continue-button {
text-decoration: none;
color: rgb(148, 163, 206);
background-color: #141414;
padding: 5px 5px;
border-radius: 2px;
font-size: 0.5rem;
box-shadow: 2px 2px 5px #000;
}
.continue-button:hover {
background-color: #f8f9fa;
}

View File

@@ -0,0 +1,134 @@
body {
font-family: Arial, sans-serif;
text-align: center;
margin: 0;
padding: 0;
height: 100vh;
width: 100vw;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
/* Fond d'écran */
background: url('img/fond.jpg') no-repeat center center;
background-size: cover; /* Adapte l'image à la taille de l'écran */
}
#content0 {
position: fixed; /* Fixe le conteneur en haut de la page */
top: 0; /* Place l'élément tout en haut */
margin: 0; /* Supprime les marges par défaut */
right: 0; /* Aligne à gauche */
width: 50%; /* Prend toute la largeur */
background: rgba(255, 255, 255, 0.8); /* Fond semi-transparent pour un effet header */
padding: 10px 10px; /* Espacement intérieur */
border-radius: 15px; /* Arrondit les angles */
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); /* Ajoute une légère ombre */
text-align: center; /* Centrage du texte */
border-bottom: 2px solid rgba(0, 0, 0, 0.1); /* Légère bordure en bas */
z-index: 1000; /* Assure que le header est au-dessus des autres éléments */
}
#content {
position: relative; /* Nécessaire pour positionner des éléments enfants absolument */
background: rgba(255, 255, 255, 0.8); /* Fond semi-transparent */
padding: 20px;
border-radius: 10px;
text-align: center;
}
#position {
font-size: 1.2em;
margin-top: 10px;
}
#distance {
margin-top: 10px;
font-size: 1.5em;
}
/* Style des flèches */
.arrow {
position: absolute;
width: 100px;
height: 100px;
display: none; /* Masqué par défaut */
}
#arrow-approaching {
bottom: 10px;
left: 10px;
}
#arrow-moving-away {
bottom: 10px;
right: 10px;
}
/* Style de Avatar */
#avatar {
position: absolute;
width: 130px;
height: 130px;
background-color: rgba(27, 28, 29, 0.6); /* Couleur de remplissage interne */
border-radius: 50%; /* Pour arrondir l'intérieur */
box-shadow: 0 0 20px 10px rgba(27, 28, 29, 0.6); /* Halo par défaut */
transition: all 0.5s ease-in-out; /* Transition douce pour les changements */
}
/* Conteneur de la flèche */
#arrow-container {
position: relative;
width: 100px; /* Taille de la boîte de la flèche */
height: 100px;
margin: 20px auto; /* Centre horizontalement dans le div #content */
}
/* Flèche noire */
#arrow-black {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transform-origin: center center; /* Centre de rotation */
transform: rotate(0deg); /* Rotation initiale */
transition: transform 0.1s linear; /* Animation fluide pour les rotations */
}
#user-avatar {
position: absolute; /* Permet de positionner avec left et top */
width: 100px;
height: 100px;
border-radius: 50%; /* Cercle */
object-fit: cover; /* Ajuste l'image */
transition: left 0.2s ease, top 0.2s ease; /* Animation fluide */
}
[data-debug="true"] {
display: none;
}
#user-name {
font-weight: bold; /* Rend le texte en gras */
margin: 0; /* Supprime les marges par défaut */
}
#challenge-number , #distance {
margin: 0; /* Supprime les marges par défaut */
}
#arrow-approaching, #arrow-moving-away {
position: fixed; /* Fixe le conteneur en haut de la page */
bottom: 0; /* Place l'élément tout en haut */
margin: 0; /* Supprime les marges par défaut */
left: 0; /* Aligne à gauche */
width: 25%; /* Prend toute la largeur */
background: rgba(255, 255, 255, 0.8); /* Fond semi-transparent pour un effet header */
padding: 10px 10px; /* Espacement intérieur */
border-radius: 15px; /* Arrondit les angles */
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); /* Ajoute une légère ombre */
text-align: center; /* Centrage du texte */
border-bottom: 2px solid rgba(0, 0, 0, 0.1); /* Légère bordure en bas */
z-index: 1000; /* Assure que le header est au-dessus des autres éléments */
}

View File

@@ -0,0 +1,58 @@
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: url('./img/fond_mystere2_b.webp') no-repeat center center;
background-size: 100% 100%;
overflow: hidden;
}
#zone_cartes {
position: relative;
width: 100%;
height: 100%;
}
.carte {
position: absolute;
width: 15vw; /* Taille des cartes */
height: calc(15vw * 1.4); /* Respecte le ratio */
background-size: cover;
z-index: 10; /* Au-dessus des ronds */
cursor: grab;
touch-action: none;
}
#emplacements {
position: absolute;
bottom: 150px; /* Augmente la distance par rapport au bas de l'écran */
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: space-between;
width: 80%; /* Largeur totale de la rangée */
height: 50px; /* Hauteur totale */
z-index: 1; /* Sous les cartes */
}
.emplacement {
width: 5vw; /* Taille des ronds */
height: 5vw;
background-color: #34b115; /* Nouvelle couleur */
border: 2px solid black;
border-radius: 50%; /* Forme ronde */
position: relative;
box-sizing: border-box;
}
.zone-blanche {
position: absolute;
top: 0;
right: 0;
width: 100px; /* Ajustez la taille selon vos besoins */
height: 100px; /* Ajustez la taille selon vos besoins */
background-color: white;
border: 2px solid black;
z-index: 5;
}

View File

@@ -82,8 +82,8 @@ html, body {
#user-avatar {
display: block;
margin: 10px auto;
border: 2px solid #333;
margin: 5px auto;
border: 0px solid #333;
}
/* Section 2 - Organisation en colonne */
#section-top-right, #section-top-right-baptiste, #section-top-right-julien {
@@ -104,13 +104,21 @@ html, body {
}
#user-avatar {
width: 50px;
height: 50px;
width: 70px;
height: 70px;
border-radius: 50%; /* Avatar en forme de cercle */
object-fit: cover;
border: 2px solid #333; /* Bordure autour de l'avatar */
/* border: 2px solid #333; /* Bordure autour de l'avatar */
}
#map {
width: 100%;
height: 100%;
}
#user-avatar-julien {
width: 70px;
height: 70px;
border-radius: 50%; /* Avatar en forme de cercle */
object-fit: cover;
/*border: 2px solid #333; /* Bordure autour de l'avatar */
}

BIN
static/img/bat.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

BIN
static/img/bat.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
static/img/cryptex.jpg Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
static/img/julien - Copie.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 127 KiB

BIN
static/img/julien.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
static/img/photo_b_1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

BIN
static/img/photo_b_2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 KiB

BIN
static/img/photo_b_3.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

BIN
static/img/photo_b_4.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

BIN
static/img/photo_b_5.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

BIN
static/img/photo_b_6.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 KiB

BIN
static/img/photo_j_1.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 KiB

BIN
static/img/photo_j_2.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 885 KiB

BIN
static/img/photo_j_3.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 KiB

BIN
static/img/photo_j_4.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 KiB

BIN
static/img/photo_j_5.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 KiB

BIN
static/img/photo_j_6.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 864 KiB

BIN
static/img/pin1.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
static/img/pin1_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/img/pin2.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
static/img/pin2_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/img/pin3.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
static/img/pin3_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/img/pin4.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
static/img/pin4_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/img/pin5.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
static/img/pin5_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/img/pin6.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
static/img/pin6_j.webp Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/img/tas_cadeaux1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

21
static/js/final_b.js Normal file
View File

@@ -0,0 +1,21 @@
function myFunction() {
var reponse = document.getElementById("reponse").value;
if (reponse.toLowerCase() === "expert") {
var popup = document.getElementById("popup");
popup.style.display = "block";
var img = document.getElementById("img");
img.src = "static/img/tas_cadeaux1.jpg"; // Chemin de l'image
var popupMessage = document.getElementById("popup-message");
popupMessage.textContent = "Vous pouvez aller chercher les cadeaux !!!"; // Message personnalisé
var closeButton = popup.querySelector(".close");
closeButton.onclick = function () {
popup.style.display = "none";
};
} else {
alert("Désolé! ce n'est pas la bonne réponse");
}
}

21
static/js/final_j.js Normal file
View File

@@ -0,0 +1,21 @@
function myFunction() {
var reponse = document.getElementById("reponse").value;
if (reponse.toLowerCase() === "roulis") {
var popup = document.getElementById("popup");
popup.style.display = "block";
var img = document.getElementById("img");
img.src = "static/img/tas_cadeaux1.jpg"; // Chemin de l'image
var popupMessage = document.getElementById("popup-message");
popupMessage.textContent = "Vous pouvez aller chercher les cadeaux !!!"; // Message personnalisé
var closeButton = popup.querySelector(".close");
closeButton.onclick = function () {
popup.style.display = "none";
};
} else {
alert("Désolé! ce n'est pas la bonne réponse");
}
}

View File

@@ -1,5 +1,5 @@
const modeDebug = false; // Passez à true pour activer le mode debug
const challengeKey = null
document.addEventListener('DOMContentLoaded', () => {
toggleDebugMode(); // Appliquer le mode debug au chargement de la page
});
@@ -47,7 +47,7 @@ document.addEventListener('DOMContentLoaded', () => {
enableWakeLock();
});
function showPopup(challenge) {
function showPopup(challenge, currentDefiKey) {
if (!challenge) {
console.error("Aucune donnée de défi actif !");
return;
@@ -66,6 +66,7 @@ function showPopup(challenge) {
popup.style.backgroundColor = '#fff';
popup.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)';
popup.style.zIndex = '1000';
popup.style.textAlign = 'center';
// Ajouter l'image
const img = document.createElement('img');
@@ -76,35 +77,42 @@ function showPopup(challenge) {
// Ajouter le texte trouvé
const text = document.createElement('p');
text.textContent = `Texte à trouver : ${textFound}`;
text.textContent = `Texte : ${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
// Ajouter un bouton "Fermer"
const closeButton = document.createElement('button');
closeButton.textContent = 'Fermer';
closeButton.onclick = () => document.body.removeChild(popup);
closeButton.onclick = () => {
document.body.removeChild(popup); // Supprimer la popup
markChallengeAsResolved(currentDefiKey); // Mettre à jour le défi
};
popup.appendChild(closeButton);
// Ajouter le popup au corps de la page
document.body.appendChild(popup);
}
// Fonction pour envoyer la requête POST au serveur
async function markChallengeAsResolved(defiKey) {
try {
const response = await fetch('/mark-challenge-resolved', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'baptiste',
challengeKey: defiKey
}),
});
const result = await response.json();
console.log("Défi marqué comme résolu :", result.message);
} catch (error) {
console.error("Erreur lors de la mise à jour du défi :", error);
}
}
// Fonction pour charger les données utilisateur
async function fetchUserData() {
try {
@@ -293,8 +301,8 @@ function updatePosition(position) {
updateCompass(bearing);
// Afficher le popup si distance < 5m
if (distance < 4) {
showPopup(window.activeChallenge);
if (distance < 4000) {
showPopup(window.activeChallenge, challengeKey);
}
lastDistance = distance;

View File

@@ -0,0 +1,253 @@
async function chargerCartes() {
try {
const response = await fetch('/data/baptiste_final.yaml');
const data = await response.json();
const zoneCartes = document.getElementById('zone_cartes');
const emplacements = document.getElementById('emplacements');
// Charger les cartes de `liste_carte_defaut` où donné = "non"
if (Array.isArray(data.liste_carte_defaut)) {
data.liste_carte_defaut.forEach((carte) => {
if (carte.donné === "non") {
creerCarte(zoneCartes, carte.image);
}
});
}
// Charger les cartes de `liste_carte_échangé` où recupéré = "oui"
if (Array.isArray(data.liste_carte_échangé)) {
data.liste_carte_échangé.forEach((carte) => {
if (carte.recupéré === "oui") {
creerCarte(zoneCartes, carte.image);
}
});
}
} catch (error) {
console.error("Erreur lors du chargement des cartes :", error);
}
}
// Fonction pour créer une carte
function creerCarte(zone, image) {
const carte = document.createElement('div');
carte.className = 'carte';
carte.style.backgroundImage = `url(${image})`;
positionAleatoire(zone, carte); // Positionner aléatoirement dans la partie haute
rendreDeplacable(carte); // Rendre la carte déplaçable
zone.appendChild(carte);
}
function positionAleatoire(zone, carte) {
const zoneRect = zone.getBoundingClientRect();
const minMargin = 80; // Marge minimale pour éviter les bordures
// Calculer les limites du tiers central verticalement
const topLimit = zoneRect.height / 3; // Début du tiers central
const bottomLimit = (zoneRect.height * 2) / 3 - carte.offsetHeight;
// Calculer les limites horizontalement (avec marge)
const leftLimit = minMargin; // Marge gauche
const rightLimit = zoneRect.width - carte.offsetWidth - minMargin; // Marge droite
// Générer une position aléatoire dans les limites définies
const top = Math.random() * (bottomLimit - topLimit) + topLimit; // Position verticale dans le tiers central
const left = Math.random() * (rightLimit - leftLimit) + leftLimit; // Position horizontale avec marges
// Orientation aléatoire
const rotation = Math.random() * 30 - 15; // Entre -15° et 15°
carte.style.top = `${top}px`;
carte.style.left = `${left}px`;
carte.style.transform = `rotate(${rotation}deg)`;
}
function rendreDeplacable(carte) {
let offsetX, offsetY;
carte.addEventListener('pointerdown', (e) => {
offsetX = e.clientX - carte.getBoundingClientRect().left;
offsetY = e.clientY - carte.getBoundingClientRect().top;
carte.style.cursor = 'grabbing';
const pointerMove = (e) => {
carte.style.left = `${e.clientX - offsetX}px`;
carte.style.top = `${e.clientY - offsetY}px`;
};
const pointerUp = () => {
carte.style.cursor = 'grab';
// Vérifier si la carte est dans la zone blanche
if (isInZoneBlanche(carte)) {
supprimerCarte(carte); // Supprimer la carte
}
window.removeEventListener('pointermove', pointerMove);
window.removeEventListener('pointerup', pointerUp);
};
window.addEventListener('pointermove', pointerMove);
window.addEventListener('pointerup', pointerUp);
});
}
function isInZoneBlanche(carte) {
// Sélectionner la zone blanche
const zoneBlanche = document.querySelector('.zone-blanche');
if (!zoneBlanche) {
console.error("Zone blanche non trouvée dans le DOM.");
return false; // Retourne false si la zone blanche n'existe pas
}
// Obtenir les dimensions et la position de la zone blanche
const zoneRect = zoneBlanche.getBoundingClientRect();
const carteRect = carte.getBoundingClientRect();
// Vérifier si la carte est entièrement dans la zone blanche
return (
carteRect.left >= zoneRect.left &&
carteRect.right <= zoneRect.right &&
carteRect.top >= zoneRect.top &&
carteRect.bottom <= zoneRect.bottom
);
}
// Supprimer la carte et mettre à jour le fichier YAML
async function supprimerCarte(carte) {
const carteImage = carte.style.backgroundImage.match(/url\(["']?(.*?)["']?\)/)?.[1];
const response = await fetch('/data/baptiste_final.yaml');
const data = await response.json();
// Vérifier si la carte est dans liste_carte_defaut
const carteDefaut = data.liste_carte_defaut.find((c) => c.image === carteImage);
if (carteDefaut) {
carteDefaut.donné = "oui";
} else {
// Sinon, vérifier si elle est dans liste_carte_échangé
const carteEchange = data.liste_carte_échangé.find((c) => c.image === carteImage);
if (carteEchange) {
carteEchange.recupéré = "non";
}
}
// Mettre à jour le fichier YAML
await fetch('/update_yaml', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),
});
// Supprimer la carte du DOM
carte.remove();
}
// Vérifier si une carte est au-dessus d'un rond
function verifierAimantation(carte) {
const emplacements = document.querySelectorAll('.emplacement');
const aimantationDistance = 20;
let aimantationEffectuee = false;
emplacements.forEach((rond) => {
const rondRect = rond.getBoundingClientRect();
const carteRect = carte.getBoundingClientRect();
const tampon = {
left: rondRect.left - aimantationDistance,
right: rondRect.right + aimantationDistance,
top: rondRect.top - aimantationDistance,
bottom: rondRect.bottom + aimantationDistance,
};
if (
carteRect.left + carteRect.width / 2 > tampon.left &&
carteRect.left + carteRect.width / 2 < tampon.right &&
carteRect.top + carteRect.height / 2 > tampon.top &&
carteRect.top + carteRect.height / 2 < tampon.bottom
) {
ajusterRotation(carte);
aimanterCarte(carte, rond);
aimantationEffectuee = true;
}
});
return aimantationEffectuee;
}
// Faire glisser et pivoter une carte relâchée en dehors des zones d'aimantation
function lancerCarte(carte) {
const zone = document.getElementById('zone_cartes');
const zoneRect = zone.getBoundingClientRect();
const vitesseX = (Math.random() - 0.5) * 10;
const vitesseY = (Math.random() - 0.5) * 10;
let dureeGlissement = 100; // Durée maximale de glissement en ms
const startTime = Date.now();
const interval = setInterval(() => {
const carteRect = carte.getBoundingClientRect();
let top = parseFloat(carte.style.top || 0) + vitesseY;
let left = parseFloat(carte.style.left || 0) + vitesseX;
if (Date.now() - startTime > dureeGlissement) {
clearInterval(interval);
return;
}
if (
carteRect.left + vitesseX < 0 ||
carteRect.right + vitesseX > zoneRect.width ||
carteRect.top + vitesseY < 0 ||
carteRect.bottom + vitesseY > zoneRect.height
) {
clearInterval(interval);
} else {
carte.style.top = `${top}px`;
carte.style.left = `${left}px`;
// Rotation relative
const currentRotation = parseFloat(
carte.style.transform.replace(/[^-0-9.]/g, '') || 0
);
const rotation = currentRotation + (Math.random() * 10 - 5); // Variation relative
carte.style.transform = `rotate(${rotation}deg)`;
}
}, 10);
}
// Ajuster progressivement la rotation vers zéro
function ajusterRotation(carte) {
let currentRotation = parseFloat(
getComputedStyle(carte).transform.match(/matrix.*\((.+)\)/)?.[1]?.split(', ')[1] || 0
);
const targetRotation = 0;
const step = (targetRotation - currentRotation) / 10;
const interval = setInterval(() => {
if (Math.abs(currentRotation - targetRotation) <= Math.abs(step)) {
carte.style.transform = `rotate(0deg)`;
clearInterval(interval);
} else {
currentRotation += step;
carte.style.transform = `rotate(${currentRotation}deg)`;
}
}, 50);
}
// Aimanter une carte sur un rond
function aimanterCarte(carte, rond) {
const rondRect = rond.getBoundingClientRect();
const zoneRect = document.getElementById('zone_cartes').getBoundingClientRect();
carte.style.left = `${rondRect.left - zoneRect.left + rondRect.width / 2 - carte.offsetWidth / 2}px`;
carte.style.top = `${rondRect.top - zoneRect.top + rondRect.height / 2 - carte.offsetHeight / 2}px`;
}
// Charger les cartes au démarrage
document.addEventListener('DOMContentLoaded', chargerCartes);

View File

@@ -1,4 +1,4 @@
const modeDebug = true; // Passez à true pour activer le mode debug
const modeDebug = false; // Passez à true pour activer le mode debug
document.addEventListener('DOMContentLoaded', () => {
toggleDebugMode(); // Appliquer le mode debug au chargement de la page
@@ -53,7 +53,7 @@ function showPopup(challenge) {
return;
}
const { image, textFound, mode } = challenge;
const { image, textFound } = challenge;
// Créer l'élément popup
const popup = document.createElement('div');
@@ -76,35 +76,59 @@ function showPopup(challenge) {
// Ajouter le texte trouvé
const text = document.createElement('p');
text.textContent = `Texte à trouver : ${textFound}`;
text.textContent = textFound;
text.style.marginTop = '10px';
text.style.fontSize = '1.2rem';
text.style.textAlign = 'center';
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);
closeButton.style.marginTop = '10px';
closeButton.style.padding = '10px 20px';
closeButton.style.backgroundColor = '#b19cd5';
closeButton.style.color = '#fff';
closeButton.style.border = 'none';
closeButton.style.cursor = 'pointer';
closeButton.onclick = async () => {
document.body.removeChild(popup);
await markChallengeResolved(challenge.key);
};
popup.appendChild(closeButton);
// Ajouter le popup au corps de la page
document.body.appendChild(popup);
}
async function markChallengeResolved(challengeKey) {
try {
// cache la popup
const popup = document.getElementById('popup');
popup.style.display = 'none';
const response = await fetch('/mark-challenge-resolved', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'julien',
challengeKey: challengeKey,
state: 'oui'
})
});
const result = await response.json();
if (result.success) {
console.log(`Défi ${challengeKey} marqué comme résolu.`);
} else {
console.error(`Erreur lors de la résolution du défi :`, result.error);
}
} catch (error) {
console.error("Erreur lors de la mise à jour du défi :", error);
}
}
// Fonction pour charger les données utilisateur
async function fetchUserData() {
try {
@@ -139,19 +163,21 @@ async function fetchUserData() {
target = { latitude, longitude };
// Extraire les informations du défi actif
const { image_1, text_found_1, mode } = firstUnresolvedChallenge;
const { image_1, text_found_1, mode, key, key_number } = firstUnresolvedChallenge;
// Stocker les informations du défi actif dans une variable globale
window.activeChallenge = {
image: image_1,
textFound: text_found_1,
mode: mode,
key: `defi_${challengeNumber}`,
key_number: challengeNumber
};
// 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}`;
document.getElementById('user-progression').textContent = challengeNumber;
} else {
console.log("Tous les défis sont résolus !");
target = null; // Réinitialisation de la cible
@@ -228,34 +254,9 @@ function positionAvatar(distance) {
}
}
// 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) {
@@ -293,7 +294,7 @@ function updatePosition(position) {
updateCompass(bearing);
// Afficher le popup si distance < 5m
if (distance < 4) {
if (distance < 4000) {
showPopup(window.activeChallenge);
}

289
static/js/script_julien2.js Normal file
View File

@@ -0,0 +1,289 @@
let target = null; // Variable globale pour stocker la cible
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();
});
// 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, key, key_number } = firstUnresolvedChallenge;
// Stocker les informations du défi actif dans une variable globale
window.activeChallenge = {
image: image_1,
textFound: text_found_1,
mode: mode,
key: `defi_${challengeNumber}`,
key_number: challengeNumber
};
// 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('user-progression').textContent = 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 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 < 4000) {
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
const username = 'julien'; // Spécifiez le nom de l'utilisateur pour Julien
try {
const response = await fetch('/update-position', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: username, // Inclure le champ username
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
});

View File

@@ -26,11 +26,11 @@ function addCustomPin(coordinates, iconUrl, popupText, offsetX = 20, offsetY = 4
}
// Initialisation de la carte
function initializeMap(centerCoordinates = [45.141998, 4.0750724]) {
function initializeMap(centerCoordinates = [ 45.142066, 4.076664]) {
// Initialiser la carte
map = L.map('map', {
center: centerCoordinates, // Coordonnées du centre
zoom: 18, // Niveau de zoom par défaut
zoom: 20, // Niveau de zoom par défaut
minZoom: 15, // Zoom minimum autorisé
maxZoom: 20 // Zoom maximum autorisé
});
@@ -128,11 +128,21 @@ async function loadChallengePins(username) {
const defiMarker = addCustomPin(
[defi.geolocalisation.latitude, defi.geolocalisation.longitude],
defi.pin || 'default-pin.png',
`Défi ${i} - ${defi.contenu_reception}`,
`Défi ${i} - trouvé ${defi.resolu}`,
offsetX,
offsetY
);
defiMarker.addTo(map);
// Ajouter le label "option" si résolu est "oui"
if (defi.resolu === "oui") {
defiMarker.bindTooltip(`Défi ${i}`, {
permanent: true, // Affiche le label en permanence
direction: "bottom", // Positionne le label au-dessus du marqueur
offset: [0, -5] // Ajuste l'offset pour éviter que le label chevauche le marqueur
});
}
}
console.log(`Pins des défis pour ${username} chargés avec succès.`);
@@ -177,7 +187,8 @@ document.addEventListener("DOMContentLoaded", async () => {
// Planifier les mises à jour des positions des utilisateurs
setInterval(() => updateAvatarPosition('baptiste', 'baptiste'), 3000);
setInterval(() => updateAvatarPosition('julien', 'julien'), 3000);
setInterval(() =>loadChallengePins('baptiste'), 3000);
setInterval(() =>loadChallengePins('julien'), 3000);
// Mettre à jour les avatars et les données utilisateur
setInterval(() => updateAvatarPosition('baptiste', { value: baptisteMarker }), 3000);
setInterval(() => updateAvatarPosition('julien', { value: julienMarker }), 3000);