TP 4 UrbeXplorer
Dans ce TP, nous allons réaliser une application web pour trouver des lieux abandonnés à explorer. Le but est de pouvoir filtrer les lieux par type, d’ajouter une recherche, et de mettre en place des tris par difficulté d’accès et par avis des utilisateurs, à partir d’une page html existante.
Mise en place
- Cloner le projet en utilisant la commande suivante
git clone https://sources.univ-jfc.fr/techno-web-2/tp-4.git
Vous utiliserez les identifiants de votre compte universitaire pour vous connecter.
Important : Cette étape est obligatoire pour ce TP. En effet, vous sauvegarderez votre travail sur le dépôt gitlab de l’université. Vous pourrez ainsi récupérer votre travail à la prochaine séance beaucoup plus facilement. Si vous ne parvenez pas à cloner le projet, demandez de l’aide à votre enseignant.
- Ouvrez le dossier
tp-4
dans votre éditeur de code (VSCode par exemple).
Ce projet contient un fichier index.html
et un fichier script.js
. Le fichier script.js
est vide. C’est dans ce fichier que vous allez écrire votre code JavaScript.
Vous pouvez ouvrir le fichier index.html
dans votre navigateur pour voir le rendu de la page. Elle contient une liste de lieux abandonnés à explorer, avec des images, des descriptions, des avis, etc.
- En fin de TP, pensez à sauvegarder votre travail sur le dépôt gitlab de l’université. Pour cela, ouvrez un terminal dans le dossier
tp-4
et tapez les commandes suivantes, en remplaçant<branch>
par le nom votre prénom et nom, en remplacant les espace par des tiret :prenom.nom
.
git checkout -b <branch>
git add .
git commit -m "TP 4 - seance 1"
git push origin <branch>
- Pour récupérer votre travail à la prochaine séance, vous pourrez utiliser la commande suivante :
git config --global user.name "prenom.nom"
git config --global user.email "votremail@univ-jfc.fr"
git clone https://sources.univ-jfc.fr/techno-web-2/tp-4.git
cd tp-4
git checkout <branch>
en remplaçant <branch>
par le nom de votre branche sauvegardée au TP précédent.
Exercice 1 : Ajouter et enlever la modale d’avertissement
Au tout début du fichier index.html
, vous trouverez le code de la modale d’avertissement. Une modale est une fenêtre qui s’affiche par dessus le reste de la page. Ici, elle est implémentée en utilisant l’élément HTML <dialog>
, qui est celui à utiliser pour implémenter une modale.
Faire en sorte que la modale s’affiche au chargement de la page :
- Créer une fonction
renderModal
dans le fichierscript.js
. - Dans cette fonction, récupérez l’élément
<dialog>
dans une variablemodal
. - Utilisez la méthode
showModal()
de l’élément<dialog>
pour afficher la modale. - Appelez cette fonction
- Créer une fonction
Faire en sorte que la modale se ferme quand on clique sur le bouton “J’ai compris”
- Dans la même fonction, récupérez le bouton “J’ai compris” dans une variable
button
. - Ajoutez un écouteur d’événement “click” sur le bouton (avec la méthode
addEventListener
). - Dans la fonction de rappel de l’écouteur d’événement, utilisez la méthode
close()
de l’élément<dialog>
pour fermer la modale.
- Dans la même fonction, récupérez le bouton “J’ai compris” dans une variable
Tester que tout fonctionne correctement : la modale doit s’afficher au chargement de la page, et se fermer quand on clique sur le bouton “J’ai compris”.
Astuce : pour éviter d’avoir à refermer la modale à chaque fois que vous rechargez la page pour les exercices suivants, vous pouvez commenter l’appel à la fonction renderModal
.
Exercice 2 : faire défiler les images au hover
Dans le fichier index.html
, vous pourrez voir que chaque lieu est représenté par un élément <article>
. Chaque article contient un titre, ainsi que plusieurs images. Seule l’image avec la classe displayed
est visible. L’objectif de cet exercice est de faire défiler les images au survol de la souris.
Première étape : créer la fonction de défilement
- Créer une fonction
loopImage
dans le fichierscript.js
. - Cette fonction prendra en paramètre un élément
<article>
. - Lorsque cette fonction est appelée, elle doit faire en sorte que l’image suivante s’affiche. Pour cela, il faudra déplacer la classe
displayed
. Si l’image affichée est la dernière, elle doit revenir à la première. - Testez que cette fonction fonctionne en appelant
loopImage
dans la console de votre navigateur.
- Créer une fonction
Deuxième étape : appeler la fonction sur chaque élément
<article>
- Pour chaque élément
<article>
, appelez-la fonctionloopImage
toute les secondes avecsetInterval
- Testez que les images défilent correctement.
- Pour chaque élément
Troisième étape : faire en sorte que les images défilent seulement au survol de la souris
- Ajoutez un écouteur d’événement “mouseenter” sur chaque élément
<article>
, et déplacez l’appel àsetInterval
dans la fonction de rappel de cet écouteur. Stockez l’identifiant de l’intervalle dans une variableintervalId
pour pouvoir l’arrêter plus tard. L’identifiant de l’intervalle est retourné par la fonctionsetInterval
. - Ajoutez un écouteur d’événement “mouseleave” sur chaque élément
<article>
, et utilisez la méthodeclearInterval
avec l’identifiant de l’intervalle pour arrêter le défilement. - Bonus : pour plus de réactivité, vous pouvez faire en sorte que la fonction
loopImage
soit appelée immédiatement au survol de la souris, et non pas après une seconde.
- Ajoutez un écouteur d’événement “mouseenter” sur chaque élément
Tester que tout fonctionne correctement : les images doivent défiler au survol de la souris, et s’arrêter quand la souris quitte l’élément
<article>
.
Exercice 3 : Filtrer par type de lieu
Chaque lieu a un type, qui est indiqué dans le dataset de l’élément <article>
. L’objectif de cet exercice est de faire en sorte que l’utilisateur puisse filtrer les lieux par type.
Le bouton de filtre est déjà présent dans le fichier index.html
. Il est représenté par un élément <select>
qui a comme id category
.
Créer une fonction
filterByCategory
dans le fichierscript.js
. Cette fonction prendra le type de lieu à filtrer en paramètre. Elle devra cacher les lieux qui ne correspondent pas et afficher ceux qui correspondent.filterByCategory("industriel")
doit cacher les lieux qui ne sont pas de type “industriel” et afficher ceux qui le sont.filterByCategory("all")
doit afficher tous les lieux.
Pour cacher un élément, vous pouvez utiliser la méthode
style.display = "none"
. Pour le réafficher, on utiliserastyle.display = ""
.Tester cette fonction en appelant
filterByCategory
dans la console de votre navigateur.Ajouter un écouteur d’événement “change” sur l’élément
<select>
. Dans la fonction de rappel de cet écouteur, appelez la fonctionfilterByCategory
avec la valeur de l’élément<select>
en paramètre.Tester que tout fonctionne correctement : les lieux doivent se filtrer en fonction du type sélectionné.
Exercice 4 : implémenter le tri
Les boutons de tri sont déjà présents dans le fichier index.html
.
Retrouvez l’endroit où ils sont définis. Quel élément est utilisé ? Comment sont-ils liés entre eux ?
CorrigéCréer une fonction
sortBy
dans le fichierscript.js
. Cette fonction prendra le type de tri à effectuer en paramètre (on ne prend pas en compte l’ordre croissant ou décroissant pour commencer)// Exemple d'appel sortBy('difficulty'); // tri par difficulté d'accès
A noter : un élément du DOM ne peut pas se retrouver à deux endroits en même temps. Pour le déplacer, il suffit juste de l’insérer à un autre endroit (il sera automatiquement retiré de son emplacement précédent).
Tester cette fonction en appelant
sortBy
dans la console de votre navigateur. **A noter : il y a une erreur dans le code HTML : la riziere n’a pas la bonne valeur pour le data-diffultyAjouter un écouteur d’événement “change” pour les boutons de selection du tri.
Dans la fonction de rappel de cet écouteur, récupérez la nature du tri a effectuer (difficulté ou avis)
Pour cela, vous pouvez utiliser le selecteur
input[name="sort"]:checked
.Ce dernier récupère le premier élément
<input>
de type “radio” qui a comme attributname
la valeur “sort” et qui est sélectionné.Tester que tout fonctionne correctement : les lieux doivent se trier en fonction du type sélectionné.
CorrigéFaire en sorte que les boutons pour sélectionner l’ordre croissant ou décroissant fonctionnent.
Exercice 5 : Ajouter une recherche
Pour la recherche, nous allons ajouter un élément <input>
de type “text” qui a comme id search
.
L’objectif est de faire en sorte que l’utilisateur puisse taper un mot dans cet élément, et que les lieux qui ne contiennent pas ce mot dans leur titre soient cachés.
Créer une fonction search
dans le fichier script.js
. Cette fonction prendra le mot à rechercher en paramètre, et cachera les lieux qui ne contiennent pas ce mot dans leur titre.
Cette fonction doit être appelée à chaque fois que l’utilisateur tape une lettre dans l’élément <input>
. Pour cela, ajoutez un écouteur d’événement “input” sur cet élément.
Exercice 6 : Ajouter la distance entre l’utilisateur et le lieu et ajouter un tri par distance
- Créer une fonction qui récupère la position de l’utilisateur en utilisant la méthode
navigator.geolocation.getCurrentPosition
. Cette méthode prend en paramètre une fonction de callback qui sera appelée avec la position de l’utilisateur en paramètre. - Modifier les lieux pour ajouter la distance entre l’utilisateur et le lieu. Pour cela, vous pouvez utiliser la méthode
haversine
(ci-dessous) qui prend en paramètre deux coordonnées géographiques et retourne la distance en kilomètres. Les coordonnées de chaque lieu sont stockées dans le dataset de l’élément<article>
.
function haversine([lat1, lon1], [lat2, lon2]) {
toRad = function (n) {
return (n * Math.PI) / 180;
};
const R = 6371; // km
const x1 = lat2 - lat1;
const dLat = toRad(x1);
const x2 = lon2 - lon1;
const dLon = toRad(x2);
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));
const d = R * c;
return d;
}
- Ajouter une option de tri par distance dans le groupe de boutons radio. Quand cette option est sélectionnée, les lieux doivent être triés par distance croissante par rapport à la position de l’utilisateur.