Sujet 3

  1. Bienvenue au 3e sujet
  2. Révisions
    1. relâche une touche
    2. Entre deux balises
    3. Lire élément formulaire
    4. querySelectorAll NodeList
    5. Liste
    6. fonction anonyme
    7. Fonction anonyme variable
    8. setTimeout
    9. class
    10. classList
    11. Sélecteurs
    12. Sélecteurs
    13. Sélecteurs
    14. Élément courant
  3. Événements
    1. Ordre d'appel
    2. Ordre exécution: fct anonyme
    3. Ordre exécution: rendre la main navigateur
    4. Vocabulaire
  4. Jeu Tux : déplacement
    1. Création HTML + CSS + JS
    2. Correction HTML + CSS + JS
    3. addEventListener
    4. Réagir à une touche du clavier
    5. Correction: clavier
    6. Correction: event.key
    7. event.key
    8. Rappel : chercher élément
    9. getElementById
    10. getBoundingClientRect
    11. left
    12. Déplacer
    13. Fin déplacement
    14. Correction: déplacement
  5. Jeu Tux: splat et score
    1. Correction: fusion
    2. Splat: limiter au cadre
    3. Correction: Splat: limiter au cadre
    4. Tux: limiter au cadre
    5. Correction: tux: limiter au cadre
    6. setTimeout
    7. Fin animation
    8. Correction: fin animation
    9. Touché ?
    10. Correction : touché ?
    11. Score
    12. Correction: score
    13. Supprimer un élément
    14. Correction: Supprimer un élément
    15. Fin Tux: fichier jeu.js complet
    16. Améliorations
    17. Correction: Améliorations
  6. JavaScript et développement web
    1. JS questions
    2. Page HTML statique
    3. Page HTML statique: questions
    4. Page dynamique
    5. Page dynamique : questions
    6. Technologies client / serveur
    7. Client / serveur
    8. Dans ce cours
  7. Objets et tableaux
    1. Objets : Pas de classe
    2. Objets: questions
    3. Créer un objet
    4. Création d'objet
    5. Propriétés dynamiques
    6. Ajouter une propriété
    7. Objets et fonctions
    8. Tableaux
    9. Création tableau
    10. Tableaux ajout
    11. Tableau taille
    12. Tableau: boucle for
  8. Panier
    1. Correction: panier.html : HTML et CSS
    2. JavaScript
    3. Selecteur
    4. Réagir click
    5. Correction: réagir click
    6. Créer une ligne
    7. Élément cliqué
    8. Copier le contenu
    9. Ajouter la ligne
    10. Correction

1. Bienvenue au 3e sujet

1.1 Bienvenue au 3e sujet

Pour votre progression, c'est très important de finir le sujet précédent avant de commencer celui-ci.

Vous devez travailler connectés (lien « Connexion » en haut à droite de la page). Sinon, vous rencontrerez des problèmes d'avancement et vous risquez d'être comptés absent. En étant connectés vous retrouverez l'endroit où vous en étiez à la séance suivante.


2. Révisions

2.1 Révisions

Commençons par une rapide révision des notions des sujets précédents.

Révisions

2.2 relâche une touche

Comment s'appelle le type d'événement qui survient lorsque l'utilisateur relâche une touche du clavier ?

Révisions

2.3 Entre deux balises

HTML

<body>
    <p>bonjour</p>
<body>

JS:

document.querySelector('p').XYZ='coucou';

Que faut-il écrire à la place de XYZ pour remplacer 'bonjour' par 'coucou' ?

Dans le doute regardez le JS que vous avez écrit.
Par exemple,

Révisions

2.4 Lire élément formulaire

HTML

<body>
   <input type="text" />
</body>

JS

let s=document.querySelector('input').XYZ;

Que faut-il écrire à la place de XYZ pour mettre dans la variable "s" ce que l'utilisateur a tapé dans le input ?

Indice:
Dans texte.html, comment avez vous fait pour lire le contenu des input ?

Révisions

2.5 querySelectorAll NodeList


let liste=document.querySelectorAll('.abc');
console.log(liste.XYZ);
Que faut-il écrire à la place de XYZ pour afficher le nombre d'éléments ayant la classe abc ?
(Dans le doute, regardez comment querySelectorAll a été utilisé dans les TP précédents, par exemple dans morpion.html)

Révisions

2.6 Liste


HTML:

<ul>
<li class="joueur">Wang</li>
<li class="joueur">Alaoui</li>
<li class="joueur">Saidi</li>
</ul>

JS:

let liste=document.querySelectorAll('.joueur');
console.log(XYZ.textContent);
Que faut-il écrire à la place de XYZ pour afficher "Saidi" dans la console ?
Indice:
querySelectorAll renvoie un NodeList qui contient plusieurs éléments, comme un tableau. Voir aussi: morpion.html

Révisions

2.7 fonction anonyme

Réécrivez, en une seule ligne, le programme suivant en utilisant une fonction anonyme

document.addEventListener('click',exemple);
function exemple(){console.log('coucou');}

Faites bien attention aux parenthèses et accolades, particulièrement à la fin.

Révisions

2.8 Fonction anonyme variable


let a = function(){return 456;}

Que contient la variable a ?

Révisions

2.9 setTimeout


setTimeout(exemple,3000);
function exemple() { return 100; }

Ici, quel est le premier paramètre de la fonction setTimeout ?

Révisions

2.10 class

Que faut-il écrire en JS pour transformer ceci:

<body>
<p>bonjour</p>
</body>

en ceci:

<body>
<p class="encart">bonjour</p>
</body>


Révisions

2.11 classList

En utilisant classList, que faut-il écrire en JS pour transformer ceci:

<body>
<p class="encart important actu">bonjour</p>
</body>

en ceci:

<body>
<p class="encart actu">bonjour</p>
</body>

Révisions

2.12 Sélecteurs

HTML:

<p id="ahmed">Ahmed</p>
<p id="leo">Léo</p>

CSS:

XYZ
{
background-color: green;
}

Que faut-il écrire à la place de XYZ pour afficher uniquement "Léo" en fond vert ?


Révisions

2.13 Sélecteurs

HTML:

<p><span class="nom">Ahmed</span> a marqué <span class="points">321</span> points</p>

CSS:

XYZ
{
background-color: green;
}

Que faut-il écrire à la place de XYZ pour afficher uniquement "321" en fond vert ?


Révisions

2.14 Sélecteurs

HTML:

<div id="tom">
<p>Tom:</p>
<p class="score">Score: 123</p>
</div>
<div id="joe">
<p>Joe:</p>
<p class="score">Score: 456</p>
</div>

CSS:

XYZ
{
background-color: green;
}

Que faut-il écrire à la place de XYZ pour afficher "Score: 456" en fond vert ? (uniquement "Score: 456")


Révisions

2.15 Élément courant


<ul>
    <li>Chocolat </li>
    <li>Fraise   </li>
    <li>Praliné  </li>
    ...
</ul>
<script>
let lis=document.querySelectorAll('li');
for(let i=0;i<lis.length;i++){
lis[i].addEventListener('click',function(){
XYZ.style.color='green';
});
}
</script>
Quand l'utilisateur clique sur un <li>, il devient vert.
Que faut-il écrire à la place de XYZ ?
Attention : lis[i] ne fonctionne pas
Indice: c'est une variable un peu particulière

3. Événements

3.1 ¤ Événements

Les événements sont des actions de l'utilisateur. Par exemple: bouton de souris enfoncé, touche de clavier relâchée,  etc.
Presque tous les programmes qu'on écrit dans ce cours réagissent à des événements.
La gestion d'événements est un des aspects les plus difficiles à comprendre de ce cours.

Déroulement:

  1.  Au chargement de la page, le navigateur exécute notre programme JS.
  2. Notre JS dit au navigateur « enregistre une fonction sur un élément »
    Exemple:
    b.addEventListener("click",fonction_a_appeler); (voir illustration ci-desous)
    veut dire « Enregistre "fonction_a_appeler" sur le bouton »
    Important: "fonction_a_appeler" n'est pas appelée au chargement de la page... elle est juste enregistrée sur le bouton.
  3. Plus tard, à chaque fois que l'utilisateur clique sur le bouton, le navigateur s’aperçoit qu'une fonction est enregistrée sur le bouton et l'appelle.

Vocabulaire:
La fonction (ici fonction_a_appeler) en paramètre de addEventListener est appelée « Gestionnaire d'événements » (« event listener » en anglais).
Cette fonction est appelée par le navigateur quand survient l'événement.

Rappel:


Événements

3.2 Ordre d'appel


...
<input type="button" value="Appuyer"/>
<script>
console.log('A');
let bouton=document.querySelector('input');
console.log('B');
bouton.addEventListener('click',fonction_a_appeler);
console.log('C');
function fonction_a_appeler()
{
console.log('D');
}
console.log('E');
</script>
...
L'utilisateur ouvre la page puis clique sur le bouton.
Dans quel ordre sont affichés A,B,C,D et E ?

Événements

3.3 Ordre exécution: fct anonyme

Utilisons maintenant une fonction anonyme:

...
<input type="button" value="Appuyer"/>
<script>
console.log('A');
let bouton=document.querySelector('input');
console.log('B');
bouton.addEventListener('click',function()
{
console.log('C');
});
console.log('D');
</script>
...
L'utilisateur ouvre la page puis clique sur le bouton.
Dans quel ordre sont affichés A,B,C et D ?

Événements

3.4 ¤ Ordre exécution: rendre la main navigateur

L'ordre est bien A,B,D,C
bouton.addEventListener() ne fait qu'enregistrer la fonction anonyme sur le bouton. Il n’appelle pas la fonction anonyme.

Essayons maintenant de comprendre ce qui se passe entre D et C:
Après D, notre JS dans <script> a fini de s’exécuter. Notre JS rend la main au navigateur.
Le navigateur doit en permanence gérer plein de choses (rafraîchissement de l'affichage, interactions avec l'utilisateur, ...).
Si on ne rendait pas la main au navigateur, il resterait bloqué ... inutilisable !
Le navigateur continue donc son travail.
Si l'utilisateur clique sur le bouton, alors le navigateur s’aperçoit qu'il y a une fonction (notre fct anonyme) enregistrée sur ce bouton et l’appelle.

...
<input type="button" value="Appuyer"/>
<script>
console.log('A');
let bouton=document.querySelector('input');
console.log('B');
bouton.addEventListener('click',function()
{
console.log('C');
});
console.log('D');
</script>
...
L'utilisateur ouvre la page puis clique sur le bouton.
Déterminez l'ordre.


Événements

3.5 Vocabulaire


...
<input type="button" value="Appuyer"/>
<script>
console.log('A');
let bouton=document.querySelector('input');
console.log('B');
bouton.addEventListener('click',function()
{
console.log('C');
});
console.log('D');
</script>
...

4. Jeu Tux : déplacement

4.1 Jeu Tux : déplacement

Dans les pages suivantes, on va programmer, ensemble, un petit jeu comme celui-ci:

Un joueur déplace le pingouin (Tux), avec les flèches du clavier.
L'autre joueur essaie de l'atteindre avec la souris.

Jeu Tux : déplacement

4.2 Création HTML + CSS + JS

Fichiers

N'hésitez pas à vous inspirer des fichiers écrits précédemment
Créez un fichier HTML complet appelé jeu.html
Créez un fichier séparé jeu.js
Créez un fichier séparé jeu.css
Assurez vous que ces deux fichiers sont bien pris en compte dans le HTML.

jeu.html

Dans le body, créez un div ayant pour id "cadre" et contenant juste l'image suivante: https://moodle.iutv.univ-paris13.fr/img/bjs/tux.png
L'image doit avoir pour id "tux"
Créez un paragraphe. A l'intérieur de celui-ci, créez un span ayant pour id "score", qui affichera la valeur du score.

jeu.css

Dans le CSS créez une bordure pour le cadre et donnez lui une taille de 500x500.
Donnez une marge de 10px au body.
Positionnez tux au centre, en vous inspirant du positionnement utilisé pour le splat vert au sujet-1

jeu.js

Pour l'instant, laissez le JS vide.

 


Jeu Tux : déplacement

4.3 Correction HTML + CSS + JS

jeu.html
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu</title>
<link href="jeu.css" rel="stylesheet" />
</head>
<body>
<div id="cadre">
<img id="tux" src="https://moodle.iutv.univ-paris13.fr/img/bjs/tux.png" alt="tux"/>
</div>
<p>Score: <span id="score">---</span></p>

<script src="jeu.js"></script>
</body>
</html>
jeu.css
body
{
margin: 10px;
}

#cadre
{
width: 500px;
height: 500px;
border: 1px solid black;
}

#tux
{
position: absolute;
top: 100px;
left: 100px;
}
jeu.js
(vide)

Jeu Tux : déplacement

4.4 addEventListener

Comment s'appelle la fonction qui permet d'enregistrer sur un élément une autre fonction, qui devra être appelée lorsqu'un événement surviendra ?
(on veut uniquement le nom)
Indice: on a utilisé cette fonction dans presque tous nos programmes.

Jeu Tux : déplacement

4.5 Réagir à une touche du clavier

Oui, quand on fait :

abc.addEventListener('click',def)  
function def() {
  ...
}

on dit au navigateur « Enregistre la fonction def sur l'élément abc. Plus tard, si l'utilisateur clique sur abc, il faudra appeler def. »

Habituellement, on réagit sur un élément (abc) particulier, par exemple un paragraphe, un titre, un bouton ...
Ici on veut réagir aux des touches du clavier partout sur la page. On va donc enregistrer notre fonction sur le document lui même.
Par ailleurs, pour capter les répétitions des flèches quand on les laisse enfoncées, on va utiliser  'keydown' au lieu de 'keyup'.

Écrivez le JS nécessaire pour afficher 'bonjour' dans la console chaque fois que l'utilisateur appuie sur une touche n'importe où sur la page.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Jeu Tux : déplacement

4.6 Correction: clavier

jeu.js

document.addEventListener('keydown',function(){
console.log('bonjour');
});

Comme on l'a vu précédemment, quand le navigateur appelle notre fonction anonyme, il lui donne un paramètre qu'on peut appeler "event".
"event" décrit l'événement clavier qui vient de survenir. event.key décrit quelle touche a été enfoncée.
Dans votre programme, affichez sur la console event.key

Si vous ne vous souvenez pas comment utiliser event, regardez dans vos fichiers précédents, ou l'aide mémoire


Jeu Tux : déplacement

4.7 Correction: event.key

jeu.js

document.addEventListener('keydown',function(event){
console.log('Touche:',event.key);
});

Jeu Tux : déplacement

4.8 event.key

Rechargez jeu.html dans votre navigateur pour exécuter jeu.js et regardez dans la console.

Que vaut event.key quand l'utilisateur appuie sur la flèche vers le bas ?

Jeu Tux : déplacement

4.9 Rappel : chercher élément

let tux=XYZ;

Que faut-il écrire à la place de XYZ pour mettre dans tux l'élément DOM ayant id="tux" ?

Jeu Tux : déplacement

4.10 getElementById

La ligne suivante fonctionne:

let tux=document.querySelector('#tux');

mais dans ce cas, on peut utiliser une fonction plus simple getElementById (qui se traduit par "Chercher élement par son id):

let tux=document.getElementById('tux');

Dorénavant, on utilisera getElementById si on connaît le id de l'élément.


Jeu Tux : déplacement

4.11 getBoundingClientRect

Pour pouvoir déplacer Tux, il faut d'abord connaître les coordonnées de l'endroit où il se trouve actuellement.

Dans la fonction anonyme, il faut tout d'abord obtenir l'image

let tux=document.getElementById('tux');

Puis ajoutez la ligne suivante:

let rect=tux.getBoundingClientRect();

Après cette ligne, affichez rect dans la console.

Quelles informations trouve-t-on dans rect ?


Jeu Tux : déplacement

4.12 left

Mettons les coordonnées left et top dans des variables que l'on va pouvoir manipuler:

let left=rect.left;
let top=rect.top;
XYZ

Que faut-il écrire à la place de XYZ pour modifier la variable left de manière à indiquer un déplacement de 30 pixels vers la gauche ?
Rappel: left est un nombre
Attention: "left" est la même chose qu'une coordonnée x. Réfléchissez bien à ce que veut dire augmenter ou diminuer cette coordonnée

Jeu Tux : déplacement

4.13 Déplacer

Supposons qu'on ait le code suivant:

let tux=document.getElementById('tux');
let rect=tux.getBoundingClientRect();
let left=rect.left;
let top=rect.top;
left-=30;
XYZ

Que faut-il écrire à la place de XYZ pour réellement modifier la position left de tux (en utilisant la variable tux et la variable left).
Indication: n'oubliez pas les unités (px)
En cas de doute, regardez comment on a fait pour positionner le splat vert au Sujet-1

Jeu Tux : déplacement

4.14 Fin déplacement

On a écrit le code suivant:

let tux=document.getElementById('tux');
let rect=tux.getBoundingClientRect();
let left=rect.left;
let top=rect.top;
left-=30;
tux.style.left=left+'px';
Par ailleurs, on sait, avec event.key quelle touche a été enfoncée
On a donc tout ce qu'il faut pour déplacer l'image avec les flèches !
Essayez de le faire vous mêmes.

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Jeu Tux : déplacement

4.15 Correction: déplacement

jeu.js

let tux=document.getElementById('tux');

document.addEventListener('keydown',function(event){
console.log('Touche enfoncée:',event.key);
let rect=tux.getBoundingClientRect();
console.log(rect);
let d=300;
let left=rect.left;
let top=rect.top;
if(event.key==='ArrowRight'){left+=d;}
if(event.key==='ArrowLeft' ){left-=d;}
if(event.key==='ArrowDown' ){top+=d;}
if(event.key==='ArrowUp' ){top-=d;}
tux.style.left=left+"px";
tux.style.top=top+"px";
});

Ça y est ... on a réussi à faire déplacer le pingouin !

Pour rendre les déplacements plus fluides on peut utiliser des transitions CSS.
Dans jeu.css, ajoutez la lige suivante à #tux:

    transition: top .3s, left .3s; 

Cette ligne veut dire « Les changements de top et left prennent 0,3 secondes »


5. Jeu Tux: splat et score

5.1 Jeu Tux: splat et score

On a réussi à faire déplacer le pingouin.
Maintenant pour avancer sur le jeu, il va falloir ajouter les splats verts vus au Sujet-1.

Fusionnez le CSS et JS du splat vert du SUjet-1 dans les fichiers CSS et JS du programme actuel.

Voici le résultat souhaité:

Et voici la correction du splat vert vu au Sujet-1:


<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Pingouin</title>
<style>
.splat
{
position: absolute;
/* La position de départ: en bas, au centre */
top: 500px;
left: 100px;
/* Agrandir 4 fois l'image */
transform: scale(4);
/* Définir les propriétés CSS à animer. Toutes en 1 seconde */
transition: top 1s,left 1s,transform 1s;
}
</style>
</head>
<body>
<img src="https://moodle.iutv.univ-paris13.fr/img/bjs/tux.png" alt="tux"/>
<script>
document.addEventListener('mousedown',ajouter_splat);
function ajouter_splat(event)
{
// Petit détail: éviter la sélection
event.preventDefault();
let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
// Forcer le navigateur à prendre en compte la situation actuelle (position, scale).
// Ceci permettra au navigateur de s'apercevoir d'un changement futur des propriétés CSS.
window.getComputedStyle(i).top;
// Changer les propriétés CSS qui transitionnent.
// Le navigateur s'aperçoit du changement et déclenche la transition.
i.style.top =(event.pageY-16)+'px';
i.style.left=(event.pageX-16)+'px';
i.style.transform='scale(1)';
}
</script>
</body>
</html>



Jeu Tux: splat et score

5.2 Correction: fusion

jeu.css
body
{
margin: 10px;
}

#cadre
{
width: 500px;
height: 500px;
border: 1px solid black;
}

#tux
{
position: absolute;
top: 100px;
left: 100px;
}

.splat
{
/* Ceci permet de placer les splats avec top et left */
position: absolute;
/* La position de départ: en bas, au centre */
top: 500px;
left: 100px;
/* Agrandir 4 fois l'image */
transform: scale(4);
/* Définir les propriétés CSS à animer. Toutes en 1 seconde */
transition: top 1s,left 1s,transform 1s;
}
jeu.js

let tux=document.getElementById('tux');

document.addEventListener('keydown',function(event){
console.log('Touche enfoncée:',event.key);
let rect=tux.getBoundingClientRect();
console.log(rect);
let d=300;
let left=rect.left;
let top=rect.top;
if(event.key==='ArrowRight'){left+=d;}
if(event.key==='ArrowLeft' ){left-=d;}
if(event.key==='ArrowDown' ){top+=d;}
if(event.key==='ArrowUp' ){top-=d;}
tux.style.left=left+"px";
tux.style.top=top+"px";
});

document.addEventListener('mousemove',ajouter_splat);
function ajouter_splat(event)
{
// Petit détail: éviter la sélection
event.preventDefault();
let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
// Forcer le navigateur à prendre en compte la situation actuelle (position, scale).
// Ceci permettra au navigateur de s'apercevoir d'un changement futur des propriétés CSS.
window.getComputedStyle(i).top;
// Changer les propriétés CSS qui transitionnent.
// Le navigateur s'aperçoit du changement et déclenche la transition.
i.style.top =(event.pageY-16)+'px';
i.style.left=(event.pageX-16)+'px';
i.style.transform='scale(1)';
}


Jeu Tux: splat et score

5.3 Splat: limiter au cadre

A l'intérieur de la fonction qui gère le bouton de la souris, ajoutez une condition sur event.pageX et event.pageY qui vérifie si l'image est bien à l'intérieur du cadre.
Si ce n'est pas le cas, vous pouvez quitter la fonction avec return.

Indications pour être précis:


Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Jeu Tux: splat et score

5.4 Correction: Splat: limiter au cadre


Condition:

...
document.addEventListener('mousedown',function (event)
{
// Petit détail: éviter la sélection
event.preventDefault();

if(event.pageX-16<10 ||
event.pageY-16<10 ||
event.pageX-16+32>500+10 ||
event.pageY-16+40>500+10 ){return;}

let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
...


Jeu Tux: splat et score

5.5 Tux: limiter au cadre

Maintenant, il s'agit de limiter les déplacements de Tux au cadre.

Dans le gestionnaire d'événements keydown, bloquez le coordonnées left et right pour que l'image ne puisse pas sortir du cadre.

Indications:

Jeu Tux: splat et score

5.6 Correction: tux: limiter au cadre


...
document.addEventListener('keydown',function(event){
console.log('Touche enfoncée:',event.key);
let rect=tux.getBoundingClientRect();
console.log(rect);
let d=100;
let left=rect.left;
let top=rect.top;
if(event.key==='ArrowRight'){left+=d;}
if(event.key==='ArrowLeft' ){left-=d;}
if(event.key==='ArrowDown' ){top+=d;}
if(event.key==='ArrowUp' ){top-=d;}
left=Math.max(10,left);
top =Math.max(10,top);
left=Math.min(510-rect.width ,left);
top =Math.min(510-rect.height,top);
tux.style.left=left+"px";
tux.style.top=top+"px";
});
...


Jeu Tux: splat et score

5.7 setTimeout

La fonction setTimeout permet d’exécuter une fonction après un délai donné en paramètre.
Elle s'utilise comme ceci:

setTimeout( fonction à exécuter , délai en millisecondes )

Que faut-il écrire pour afficher un alert avec 'coucou' après 2000 millisecondes ?
Essayez dans la console avant de répondre ici.
Utilisez une fonction anonyme.

Jeu Tux: splat et score

5.8 Fin animation

Dans le CSS on avait écrit:

.splat
{
/* Ceci permet de placer les splats avec top et left */
position: absolute;
/* La position de départ: en bas, au centre */
top: 500px;
left: 100px;
/* Agrandir 4 fois l'image */
transform: scale(4);
/* Définir les propriétés CSS à animer. Toutes en 1 seconde */
transition: top 1s,left 1s,transform 1s;
}

La ligne "transition" dit au CSS d'animer les propriétés top et left de leur position initiale (top=500, left=100) à l'endroit cliqué en 1 seconde.
On voudra vérifier si le splat a touché le pingouin à la fin de l'animation, c'est à dire, après 1000 millisecondes.
Pour l'instant, utilisez setTimeout juste pour afficher 'fin animation' dans la console au bon moment.
(on verra ensuite comment vérifier si le splat a touché)

Jeu Tux: splat et score

5.9 Correction: fin animation


document.addEventListener('mousedown',function (event) 
{
// Petit détail: éviter la sélection
event.preventDefault();

if(event.pageX-16<10 ||
event.pageY-16<10 ||
event.pageX-16+32>500+10 ||
event.pageY-16+40>500+10 ){return;}

let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
// Forcer le navigateur à prendre en compte la situation actuelle (position, scale).
// Ceci permettra au navigateur de s'apercevoir d'un changement futur des propriétés CSS.
window.getComputedStyle(i).top;
// Changer les propriétés CSS qui transitionnent.
// Le navigateur s'aperçoit du changement et déclenche la transition.
i.style.top =(event.pageY-16)+'px';
i.style.left=(event.pageX-16)+'px';
i.style.transform='scale(1)';
setTimeout(function(){
console.log('fin animation');
},1000);

});


Jeu Tux: splat et score

5.10 Touché ?

On voudrait vérifier si les images de tux et splat se touchent.
Pour ça, on va utiliser leurs rectangles:

	let rectTux=tux.getBoundingClientRect();
let rectSplat=i.getBoundingClientRect();

on peut utiliser les propriétés  des rectangles top, left, width et height pour construire une condition (assez compliquée) qui permette de vérifier s'il y a une collision entre ces deux rectangles.

Essayez de trouver par vous mêmes, éventuellement en faisant un dessin des rectangles dans différentes configurations.

Jeu Tux: splat et score

5.11 Correction : touché ?


  setTimeout(function(){
let rectTux=tux.getBoundingClientRect();
let rectSplat=i.getBoundingClientRect();
let touche=
rectSplat.top +rectSplat.height >= rectTux.top &&
rectSplat.top < rectTux.top +rectTux.height &&
rectSplat.left+rectSplat.width >= rectTux.left &&
rectSplat.left < rectTux.left +rectTux.width ;

...

la variable "touche" vaut true seulement si les rectangles se touchent

Jeu Tux: splat et score

5.12 Score

Déclarez une variable score au tout début de votre fichier et initialisez-la à 0.
Ensuite, augmentez le score de 10 quand les rectangles se touchent et diminuez de 5 quand ils ne se touchent pas.
Utilisez textContent pour afficher le score dans l'élément qui a id="score"


Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Jeu Tux: splat et score

5.13 Correction: score


  setTimeout(function(){
let rectTux=tux.getBoundingClientRect();
let rectSplat=i.getBoundingClientRect();
let touche=
rectSplat.top +rectSplat.height >= rectTux.top &&
rectSplat.top < rectTux.top +rectTux.height &&
rectSplat.left+rectSplat.width >= rectTux.left &&
rectSplat.left < rectTux.left +rectTux.width ;
if(touche){
score+=10;
}
else
{
score-=5;
}

document.getElementById('score').textContent=score;
},1000);


Jeu Tux: splat et score

5.14 Supprimer un élément

Pour supprimer un élément on utilise la méthode element.remove()
Faites en sorte que l'image splat soit supprimée lorsqu'elle a touché le pingouin.

Par ailleurs, on voudrait que les images qui n'ont pas touché soient affichées derrière le pingouin, pas devant.
Pour ça, on peut utiliser la propriété CSS z-index (en JS elle s'écrit zIndex).
Faites en sorte que l'image splat prenne un zIndex de -1 quand elle n'a pas touché.

Jeu Tux: splat et score

5.15 Correction: Supprimer un élément


  setTimeout(function(){
let rectTux=tux.getBoundingClientRect();
let rectSplat=i.getBoundingClientRect();
let touche=
rectSplat.top +rectSplat.height >= rectTux.top &&
rectSplat.top < rectTux.top +rectTux.height &&
rectSplat.left+rectSplat.width >= rectTux.left &&
rectSplat.left < rectTux.left +rectTux.width ;
if(touche){
i.remove();
score+=10;
}
else
{
i.style.zIndex=-1;
score-=5;
}
document.getElementById('score').textContent=score;
},1000);



Jeu Tux: splat et score

5.16 Fin Tux: fichier jeu.js complet

jeu.js


let score=0;
let tux=document.getElementById('tux');

document.addEventListener('keydown',function(event){
console.log('Touche enfoncée:',event.key);
let rect=tux.getBoundingClientRect();
console.log(rect);
let d=100;
let left=rect.left;
let top=rect.top;
if(event.key==='ArrowRight'){left+=d;}
if(event.key==='ArrowLeft' ){left-=d;}
if(event.key==='ArrowDown' ){top+=d;}
if(event.key==='ArrowUp' ){top-=d;}
left=Math.max(10,left);
top =Math.max(10,top);
left=Math.min(510-rect.width ,left);
top =Math.min(510-rect.height,top);
tux.style.left=left+"px";
tux.style.top=top+"px";
});

document.addEventListener('mousedown',function (event)
{
// Petit détail: éviter la sélection
event.preventDefault();

if(event.pageX-16<10 ||
event.pageY-16<10 ||
event.pageX-16+32>500+10 ||
event.pageY-16+40>500+10 ){return;}

let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
// Forcer le navigateur à prendre en compte la situation actuelle (position, scale).
// Ceci permettra au navigateur de s'apercevoir d'un changement futur des propriétés CSS.
window.getComputedStyle(i).top;
// Changer les propriétés CSS qui transitionnent.
// Le navigateur s'aperçoit du changement et déclenche la transition.
i.style.top =(event.pageY-16)+'px';
i.style.left=(event.pageX-16)+'px';
i.style.transform='scale(1)';
setTimeout(function(){
let rectTux=tux.getBoundingClientRect();
let rectSplat=i.getBoundingClientRect();
let touche=
rectSplat.top +rectSplat.height >= rectTux.top &&
rectSplat.top < rectTux.top +rectTux.height &&
rectSplat.left+rectSplat.width >= rectTux.left &&
rectSplat.left < rectTux.left +rectTux.width ;
if(touche){
i.remove();
score+=10;
}
else
{
i.style.zIndex=-1;
score-=5;
}
document.getElementById('score').textContent=score;
},1000);
});


Jeu Tux: splat et score

5.17 Améliorations

Ceci n'est pas indispensable. C'est uniquement pour s'amuser.
Vous pouvez passer çà la page suivante si vous n'êtes pas en avance.

Au lieu de supprimer le splat qui a touché, changez son image et utilisez:
https://moodle.iutv.univ-paris13.fr/img/bjs/splat2.png

En utilisant un autre setTimeout, faites disparaître le splat  qui a touché après 3000 millisecondes

La disparition est un peu brusque. On peut utiliser les transitions CSS. Dans jeu.css ajoutez opacité à la transition dans .splat:
transition: top 1s,left 1s,transform 1s,opacity 3s;
Comme on 'a fait ailleurs dans jeu.css
Appelez  window.getComputedStyle(i).top; pour que le navigateur prenne acte de l'opacité actuelle (par défaut 1)
Ensuite, mettez l'opacité à 0.

Vous pouvez aussi faire quelque-chose de similaire pour les splat qui n'ont pas touché.

Jeu Tux: splat et score

5.18 Correction: Améliorations


let score=0;
let tux=document.getElementById('tux');

document.addEventListener('keydown',function(event){
console.log('Touche enfoncée:',event.key);
let rect=tux.getBoundingClientRect();
console.log(rect);
let d=100;
let left=rect.left;
let top=rect.top;
if(event.key==='ArrowRight'){left+=d;}
if(event.key==='ArrowLeft' ){left-=d;}
if(event.key==='ArrowDown' ){top+=d;}
if(event.key==='ArrowUp' ){top-=d;}
left=Math.max(10,left);
top =Math.max(10,top);
left=Math.min(510-rect.width ,left);
top =Math.min(510-rect.height,top);
tux.style.left=left+"px";
tux.style.top=top+"px";
});

document.addEventListener('mousedown',function (event)
{
// Petit détail: éviter la sélection
event.preventDefault();

if(event.pageX-16<10 ||
event.pageY-16<10 ||
event.pageX-16+32>500+10 ||
event.pageY-16+40>500+10 ){return;}

let i=document.createElement('img');
i.src='https://moodle.iutv.univ-paris13.fr/img/bjs/splat.png';
i.className='splat';
document.body.append(i);
// Forcer le navigateur à prendre en compte la situation actuelle (position, scale).
// Ceci permettra au navigateur de s'apercevoir d'un changement futur des propriétés CSS.
window.getComputedStyle(i).top;
// Changer les propriétés CSS qui transitionnent.
// Le navigateur s'aperçoit du changement et déclenche la transition.
i.style.top =(event.pageY-16)+'px';
i.style.left=(event.pageX-16)+'px';
i.style.transform='scale(1)';
setTimeout(function(){
let rectTux=tux.getBoundingClientRect();
let rectSplat=i.getBoundingClientRect();
let touche=
rectSplat.top +rectSplat.height >= rectTux.top &&
rectSplat.top < rectTux.top +rectTux.height &&
rectSplat.left+rectSplat.width >= rectTux.left &&
rectSplat.left < rectTux.left +rectTux.width ;
if(touche){
i.src="https://moodle.iutv.univ-paris13.fr/img/bjs/splat2.png";
getComputedStyle(i).top;
i.style.opacity=0;
setTimeout(function(){i.remove();},3000);
score+=10;
}
else
{
i.style.zIndex=-1;
score-=5;
}
document.getElementById('score').textContent=score;
},1000);
});


6. JavaScript et développement web

6.1 ¤ JavaScript et développement web

Le JavaScript (JS) est un langage de programmation, initialement  développé pour le navigateur, mais maintenant aussi utilisé dans d'autres contextes. Il suit un standard appelé ECMAScript (ES). Le langage JavaScript n'a aucun lien avec le Java. Son nom a été choisi pour des raisons commerciales.

Le JavaScript est souvent utilisé dans le navigateur. Il est, en pratique, le langage qui permet d’interagir directement avec le navigateur. L’interaction avec le navigateur se fait à travers le DOM. C'est ce qu'on fait depuis le début de ce cours.

Le JavaScript peut aussi être utilisé en dehors du navigateur, principalement avec Node.js
De nombreux logiciels et librairies utilisant Node.js sont disponible par npm. Node.js est souvent utilisé coté serveur.

JavaScript et développement web

6.2 JS questions

Quelles affirmations sont vraies ?

JavaScript et développement web

6.3 ¤ Page HTML statique

Le "serveur" musique.org est une machine dans un Datacenter distant.
Sur cette machine tourne un logiciel appelé un "serveur web".
Remarquez que le terme "serveur" peut avoir deux sens: la machine et le logiciel

1) Le navigateur demande au serveur web la page.html. C'est ce qu'on appelle une "requête"
2) Sur la machine tourne un logiciel appelé serveur web qui, reçoit la demande.
Le serveur web trouve le fichier page.html
3) Le serveur envoie page.html au navigateur. C'est ce qu'on appelle une "réponse"
4) Le navigateur reçoit page.html et l'affiche.

Ensuite, le navigateur va recommencer la même opération pour les fichiers CSS, JS, images, etc. référencés dans page.html

JavaScript et développement web

6.4 Page HTML statique: questions

Pour une page HTML statique, quelles affirmations sont vraies ?

JavaScript et développement web

6.5 ¤ Page dynamique

1) Le navigateur (le client) demande une page en précisant ce qu'il cherche dans la requête
2) Le serveur web reçoit la requête et exécute un logiciel. Ce logiciel peut-être écrit dans différents langages de programmation (PHP, Python, Java, JS+Node.js, ...)
3) Le logiciel demande des informations à la base de données
4) A l'aide de ces informations le logiciel génère une page HTML
5) Le HTML est envoyé au navigateur
6) Le navigateur affiche le HTML

La distinction statique / dynamique est uniquement faite coté serveur. Dans les deux cas, le navigateur reçoit du HTML et ne voit pas la différence.

JavaScript et développement web

6.6 Page dynamique : questions

Pour une page dynamique, quelles affirmations sont vraies ?

JavaScript et développement web

6.7 ¤ Technologies client / serveur

En pratique, les interactions client/serveur peuvent devenir complexes. De nombreuses requêtes se font du navigateur au serveur. Les informations et même les logiciels couvrent l'un et l'autre. Pour ne pas se perdre, il est important de bien garder en tête où est employée chaque technologie (client ou serveur ?).
Pour le web, le terme "client" veut dire la même chose que "navigateur".

JavaScript et développement web

6.8 Client / serveur

Quelles technologies s'ont principalement employées coté serveur ?

JavaScript et développement web

6.9 Dans ce cours

Jusqu'à présent, dans ce cours, on a manipulé des fichiers HTML, CSS et JS. On n'a donc pas eu besoin de serveur.
Plus tard, on verra une technologie appelée AJAX, qui permet au JS de faire des requêtes au serveur.
Ce cours étant orienté IHM, on ne verra pas Node.js

7. Objets et tableaux

7.1 Objets et tableaux

Dans cette partie, on va apprendre à utiliser les objets et les tableaux.


Objets et tableaux

7.2 ¤ Objets : Pas de classe

En Java:

  •  on crée une classe
  •  on instancie un objet de cette classe (new)
  •  on accède à une propriété de l’objet

En JavaScript

  • on crée directement un objet (ici, il est vide, mais il pourrait-être initialisé)
  • on peut ajouter des propriétés simplement

Objets et tableaux

7.3 Objets: questions

Quelles affirmations sont vraies ?

Objets et tableaux

7.4 ¤ Créer un objet

En JavaScript, on peut créer un objet en utilisant les accolades "{", "}", et en spécifiant directement des propriétés et leurs valeurs.

Cette syntaxe est très utilisée en pratique.

Elle sert aussi comme un format d'échange de données appelé JSON. JSON est utilisé, entre autres, pour la communication entre le navigateur et le serveur. On étudiera JSON dans un autre cours.

Objets et tableaux

7.5 Création d'objet

let pos=XXXXX;

Que faut-il écrire à la place de XXXXX pour créer un objet ayant les propriétés top et left respectivement associées aux valeurs 100 et 200 ?

Objets et tableaux

7.6 ¤ Propriétés dynamiques

En Java on ne peut pas utiliser une propriété qui n'a pas été déclarée dans la classe.

En JavaScript on peut ajouter des propriétés dynamiquement. Il n'y a pas de classe.


Objets et tableaux

7.7 Ajouter une propriété

let joueur={pseudo: "Joe"};
XXXXX

 
Que faut-il écrire à la place de XXXXX pour ajouter à joueur la propriété score associée à la valeur 100 ?


Objets et tableaux

7.8 ¤ Objets et fonctions

En JavaScript, les fonctions sont des valeurs comme les autres (number, String, object...). On peut les attribuer à des variables. On peut aussi les attribuer aux propriétés d'un objet.

Donc, pour créer une méthode, il suffit de créer une propriété dont la valeur est de type "function".

Le JS ne fait rien de spécial pour gérer la méthode. afficherNotes est juste une propriété de l'objet, dont la valeur se trouve être de type "function".


Objets et tableaux

7.9 ¤ Tableaux

Les tableaux JavaScript se déclarent avec des crochets [ ... ]. Les tableaux sont indexés par un entier et sont numérotés à partir de 0.

De nombreuses méthodes sont associées aux tableaux. Par exemple :

.push(v) permet d'ajouter une valeur à la fin d'un tableau.

.indexOf(v) renvoi l'indice de la première valeur v trouvée dans le tableau

Pour parcourir un tableau, utilisez une boucle for

.length permet d'obtenir la taille d'un tableau.


Objets et tableaux

7.10 Création tableau

let parfums=XXXXX;
 Que faut-il écrire à la place de XXXXX pour créer un tableau contenant les chaînes suivantes : fraise, chocolat et vanille ?

Objets et tableaux

7.11 Tableaux ajout

let parfums=["fraise","chocolat","vanille"];
XXXXX

Que faut-il écrire à la place de XXXXX pour ajouter la valeur framboise à la fin du tableau parfums ?

Objets et tableaux

7.12 Tableau taille

let parfums=["fraise","chocolat","vanille"];
console.log(XXXXX);
 Que faut-il écrire à la place de XXXXX pour afficher la taille du tableau dans la console ?

Objets et tableaux

7.13 Tableau: boucle for

let parfums=['fraise','chocolat','vanille','framboise'];
XXXXX
Que faut-il écrire à la place de XXXXX pour créer une boucle for sur une variable numérique i qui affiche tous les éléments du tableau dans la console ?

8. Panier

8.1 Panier

On veut  créer un panier comme ceci:

Voici le HTML à l'intérieur de <body>

		<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p> 
<h4>Panier:</h4>
<ul id="panier">
</ul>

Complétez le fichier panier.html
On mettra le CSS et le JS dans ce même fichier panier.html
Ajustez le CSS pour obtenir l'affichage ci-dessus.


Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Panier

8.2 Correction: panier.html : HTML et CSS


<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu</title>
<style type=>
#parfums span
{
padding: .5em;
margin: 1em;
border: 1px solid blue;
}
#parfums span:hover
{
background-color: #ffa;
}
</style>
</head>
<body>
<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p>
<h4>Panier:</h4>
<ul id="panier">
</ul>
<script>
</script>
</body>
</html>
 


Panier

8.3 JavaScript

Essayez de faire le JavaScript par vous même.
Vous pouvez vous inspirer de ce qui a été vu dans morpion.html pour réagir au click.
Vous pouvez vous inspirer de la création des images splat pour la création des li.

Si vous y arrivez, félicitations !

Dans tous les cas, on va le faire (ou refaire) ensemble, étape par étape, dans les pages suivantes.

Panier

8.4 Selecteur

Écrivez le sélecteur CSS permettant de désigner tous les span contenus dans l'élément ayant id="parfums"

Panier

8.5 Réagir click

Affichez 'click' sur la console chaque fois que l'utilisateur clique sur un des span dans parfums.

Indices:

Écrivez le code, vérifiez qu'il fonctionne dans votre navigateur, puis copiez-le ici pour que votre enseignant puisse le relire plus tard:

Panier

8.6 Correction: réagir click


			let parfums=document.querySelectorAll('#parfums span');
for(let i=0;i<parfums.length;i++)
{
parfums[i].addEventListener('click',function(){
console.log('click');
});
}


Panier

8.7 Créer une ligne

Créer une ligne


Rappel

Voyons comment créer puis ajouter un élément.

On le fait généralement en plusieurs étapes, comme le montre le schéma:
  1. La situation initiale
  2. Création d'un élément en mémoire, mais pas encore dans le document (la page)
  3. Changement des propriétés de cet élément que l'on vient de créer
  4. Insertion de l'élément crée dans le document (la page)

---

On va suivre les étapes ci-dessus, mais pas pour créer une image. On veut (2) créer une ligne <li>, puis (3) remplir son contenu, puis (4) l'ajouter au <ul id="panier"> (et non pas au body)

Commençons par l'étape (2) création:
Que faut-il écrire pour créer un élément li et le mettre dans une variable appelée « ligne » ?

Panier

8.8 Élément cliqué


			let parfums=document.querySelectorAll('#parfums span');
for(let i=0;i<parfums.length;i++)
{
parfums[i].addEventListener('click',function(){
ICI
});
}
Notre fonction anonyme (« gestionnaire d'événements ») est appelée quelque soit le span cliqué.
Une fois dans le gestionnaire d'événements, on veut savoir quel span, précisément a été cliqué, pour pouvoir récupérer son contenu (le parfum).
Quel est le nom de la variable permettant d'obtenir le span cliqué (à l'endroit "ICI") ?
C'est une variable un peu particulière, renseignée par le navigateur lorsqu'il appelle votre fonction lors d'un click...
(dans le doute, voir morpion.html)

Panier

8.9 Copier le contenu

On a donc maintenant un <li> dans la variable « ligne » et on a le span cliqué dans la variable « this »

On voudrait copier ce qui est écrit dans le span cliqué vers ce qui sera écrit dans la ligne.

Que faut-il écrire ?

Panier

8.10 Ajouter la ligne

Rappel:

On a donc

			let parfums=document.querySelectorAll('#parfums span');
for(let i=0;i<parfums.length;i++)
{
parfums[i].addEventListener('click',function(){
console.log(this);
let ligne=document.createElement('li');
ligne.textContent=this.textContent;
let panier=document.getElementById('panier');
...
});
}
En vous inspirant du rappel ci-dessus, et en utilisant la variable panier (voir ci-dessus), que faut-il écrire pour ajouter la ligne crée au panier.

Attention: ici on veut ajouter la ligne au panier, pas au body.

Essayez avant de répondre. Votre programme devrait fonctonner.

Panier

8.11 Correction

<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8"/>
<title>Jeu</title>
<style type=>
#parfums span
{
padding: .5em;
margin: 1em;
border: 1px solid blue;
}
#parfums span:hover
{
background-color: #ffa;
}
</style>
</head>
<body>
<p id="parfums"><span>Fraise</span><span>Chocolat</span><span>Vanille</span><span>Framboise</span></p>
<h4>Panier:</h4>
<ul id="panier">
</ul>
<script>
let parfums=document.querySelectorAll('#parfums span');
for(let i=0;i<parfums.length;i++)
{
parfums[i].addEventListener('click',function(){
console.log(this);
let ligne=document.createElement('li');
ligne.textContent=this.textContent;
let panier=document.getElementById('panier');
panier.append(ligne);
});
}
</script>
</body>
</html>