Infoforall

Javascript 09 : Click, this et hasard

Dans l'activité précédente, vous avez appris à placer les éléments directement via le javascript.

Nous allons continuer avec un peu plus d'interactivité avec l'utilisation des fonctions-événements prédéfinis pour certaines balises. Vous verrez plus tard qu'on peut tout gérer en réalité (quand on clique, quand on survole, quand on quitte la zone...), mais pour l'instant gérer les clicks sera déjà bien.

De la même manière, nous allons rajouter une petite partie sur la gestion du hasard, de façon à pouvoir produire des effets utilisables pour réaliser des jeux.

Si vous n'avez pas encore été voir l'activité CSS ci-dessous (celle où on positionne les animaux féroces !), commencez par repartir là-bas. L'activité javascript proposé ici est la continuité de celle-ci.

1 - Les événements basiques

Nous avons vu (lorsque nous avons parlé des balises input) qu'il existe déjà beaucoup d'événements qu'on peut rajouter facilement sur les balises : lorsque l'événement survient, on lance l'appel à une fonction.

Souvenir souvenir de l'activité 2 :

<input type="number" id="age" min="0" max="100" step="1" value="17" onchange="changerAge()">

Cela permet d'obtenir un champ numérique. L'utilisation de onchange suivi d'un string contenant le nom d'une fonction javascript permet de coder simplement l'événement "lorsque la valeur de la balise change, déclenche cette fonction".

Cet événement peut être associé à toutes les balises input, mais pas aux balises div par exemple.

De la même façon, nous avons déjà géré des événements de type "click" : les clics sur les boutons (encore des balises input) :

<p><input type="button" onclick="mise_a_jour()" value="Click Me!"></p>

Cette fois, nous associons la fonction mise_a_jour à l'événement "on clique sur le bouton".

Pour savoir si on peut l'associer à d'autres balises, il suffit d'aller se renseigner.

01° Faire une recherche dans un moteur de recherche avec une requête du type "javascript onclick". Trouvez sur quels types de balises on peut utiliser cet attribut.

Sur w3school, on trouve une page dédiée à cet attribut. On trouve ainsi en bas de page :

...CORRECTION...

All HTML elements, EXCEPT: <base>, <bdo>, <br>, <head>, <html>, <iframe>, <meta>, <param>, <script>, <style>, and <title

aller voir sur cette page de w3schools.com

Bref, c'est pratique. Ca fonctionne sur une majorité des balises courantes, dont la balise div.

Nous allons donc pouvoir l'utiliser pour changer la couleur des balises sur lesquelles on clique.

Autres événements codables directement dans HTML : aller voir sur cette page de w3schools.com

Nous allons commencer par reprendre l'interface de l'activité précédente et nous allons la modifier via un script au lancement de la page.

interface voulue

Voici la partie HTML :

<!DOCTYPE html>

<html>

    <head>

        <meta charset="UTF-8" />

        <title>ONCLICK, THIS ET HASARD</title>

        <meta http-equiv="content-Language" content="fr" />

        <link rel="stylesheet" href="interface3.css" />


        <script type="text/javascript" src="interface3.js"></script>


    </head>

    <body>


        <header>

            <h3>MON TEST D'INTERFACE</h3>

        </header>


        <section>


            <div id="js07_test1">

                <div id="a11"></div>

                <div id="a12"></div>

                <div id="a13"></div>


                <div id="b21"></div>

                <div id="b22"></div>

                <div id="b23"></div>


                <div id="c31"></div>

                <div id="c32"></div>

                <div id="c33"></div>

            </div>


        </section>


    </body>

</html>

Remarquez les noms des fichiers CSS et JS.

Et le CSS : (qu'on nommera interface3.css)

On commence avec la div-conteneur :

#js07_test1{

    margin: 0px;

    padding: 0px;

    border: 1px solid #660000;

    width: 800px;

    height: 650px;

    position: relative;

}

Je définis une balise div-conteneur en lui donnant la bonne largeur (800px) et hauteur(650px), ainsi qu'une propriété position de façon à pouvoir gérer les positions absolues des div qu'elle contient.

On passe maintenant au CSS commun des div de couleurs contenues dans la div-conteneur. Nous créons des carrés de 150px de côté :

#js07_test1 div {

    display: inline-block;

    margin: 0px;

    padding: 0px;

    width: 150px;

    height: 150px;

    border: 1px solid #777777;

}

Et pour le fichier javascript : (qu'on nommera interface3.js)

var tCouleurs = [ 'blue', 'orange', 'green', 'red', 'yellow', 'black', 'purple', 'cyan', 'grey' ];


function demarrage(){

    var listeDiv = document.querySelectorAll("#js07_test1 div");

    for (var i = 0; i < listeDiv.length; i++) {

        listeDiv[i].style.backgroundColor = tCouleurs[i];

        listeDiv[i].style.position = 'absolute';

        listeDiv[i].style.top = (50+200*parseInt(i/3))+'px';

        listeDiv[i].style.left = (parseInt(50+250*(i%3)))+'px';

    }

}


window.addEventListener("load",demarrage);

02° Télécharger le fichier HTML, le fichier CSS, et le fichier Javascript (vide). Placez le tout dans un même dossier.

03° Rajouter un attribut onclick sur la balise d'id a11 qui fait référence à une fonction change_couleur. Rajouter cette fonction dans le fichier javascript. Il devra changer la couleur de la div en rose (pink) par exemple.

Quelques aides ou conseils :

Et voilà. C'est bien, ça devrait fonctionner mais bon, créer autant de fonctions que de balises, ça peut rapidement devenir lassant, surtout avec 200 balises par exemple...

Nous allons donc voir dans la partie suivante un moyen d'utiliser une fonction unique pour toutes les balises : ce moyen permettra de savoir sur quelle balise l'utilisateur vient de cliquer.

En attendant, voici une correction :

Une modification à apporter sur le HTML :

<div id="a11" onclick="change_couleur()" ></div>

On rajoute bien l'attribut onclick qui lancera l'appel à la fonction change_couleur.

Voilà cette fameuse fonction, à rajouter à la suite de vos autres fonctions :

function change_couleur() {

    var balise1 = document.getElementById("a11");

    balise1.style.backgroundColor = "pink";

}

2 - Utiliser this lors d'un événement

Lors d'un événement, on lance l'appel à une fonction depuis le HTML. On ne peut pas transmettre d'argument. Cela semble limitant. En réalité, on transmet beaucoup beaucoup de choses sur l'événement : la position de la souris, la touche qui a été utilisée... Nous verrons lors de l'activité sur les événements comme gérer tout cela. En attendant, sachez qu'on peut utiliser le noeud/node/référence de la balise html sur laquelle on a cliqué. Comment ?

Graçe à l'objet this.

Lorsqu'on utilise this, on obtient donc la référence, le noeud, de la balise, même si elle ne possède pas d'id, de classe ou quoi que ce soit : vous obtenez simplement la référence de l'élément cliqué. Lorsque votre programme est bien configuré, c'est aussi simple que cela.

04° Tentons la manière naïve en remplaçant la fonction par ceci :

function change_couleur() {

    this.style.backgroundColor = "pink";

}

Vous vous en doutez, cela ne fonctionne pas.

Pourquoi ? Vous ne pouvez pas le savoir pour l'instant.

Il faut comprendre la façon dont le navigateur travaille : this fait référence à l'objet qui lance la fonction. Or ici, on n'attribue pas directement la fonction change_couleur à la balise depuis javascript. L'association est faite dans le code HTML.

Ainsi, lorsqu'on clique sur une balise, la balise informe votre gestionnaire de fenêtre (l'objet window) qu'on doit faire appel à la fonction. C'est donc window qui fait appel à la fonction : this contient dans ce cas window, quelque soit la balise sur laquelle vous avez réellement cliqué.

Il va donc falloir créer le lien entre les div et l'événement 'click' depuis javascript.

Voici la méthode que je propose ici (nous en verrons une autre lors de l'activité sur les événements).

Elle est simple : nous n'allons pas rajouter les attributs onclick dans le code HTML mais directement dans le javascript. Faisons cela lors de l'appel à demarrage par exemple.

05° Faire disparaitre les attributs onclick de l'HTML.

06° Modifier le javascript pour intégrer ces nouvelles versions des fonctions :

var tCouleurs = [ 'blue', 'orange', 'green', 'red', 'yellow', 'black', 'purple', 'cyan', 'grey' ];


function change_couleur() {

    this.style.backgroundColor = "pink";

}


function demarrage() {

    var listeDiv = document.querySelectorAll("#js07_test1 div");

    for (var i = 0; i < listeDiv.length; i++) {

        listeDiv[i].style.backgroundColor = tCouleurs[i];

        listeDiv[i].style.position = 'absolute';

        listeDiv[i].style.top = (50+200*parseInt(i/3))+'px';

        listeDiv[i].style.left = (parseInt(50+250*(i%3)))+'px';

        listeDiv[i].onclick = change_couleur ; // LE RAJOUT EST ICI< * * * * * * *

    }

}


window.addEventListener("load",demarrage);

Et voilà : normalement, ça fonctionne parfaitement. Les balises devienent roses lorsqu'on clique dessus.

Tout ça avec une nouvelle fonction de UNE ligne et un rajout de UNE ligne dans la fonction demarrage.

Pas mal, non ?

3 - Gestion du hasard : l'objet Math

Puisqu'on parle de jeu, il est temps de voir comment obtenir un nombre aléatoire (ou presque) à l'aide d'un script Javascript.

Pour l'essentiel, il va s'agit d'utiliser une méthode de Javascript qui s'applique sur l'objet Math : la méthode random.

Cette méthode renvoie un nombre réel compris entre 0 (inclus) et 1 (exlu).

07° Modifier la fonction change_couleur pour qu'elle affiche (en plus) un nombre aléatoire de ce type : (vous pouvez relancer la page pour voir apparaitre d'autres nombres)

function change_couleur(){

    . . .

    alert(Math.random());

    . . .

}

08° Modifier le code de façon à obtenir une valeur comprise entre 0 (inclus) et 20(exclu).

...CORRECTION...

Il suffit de rajouter une multiplication.

alert(20*Math.random());

On obtient alors un nombre compris entre 0,000 et 19.999 par exemple.

Pas très pratique comme nombre n'est-ce pas ?

Nous pourrions utiliser simplement la fonction parseInt mais il existe heureusement de nombreuses autres méthodes dans Math, notamment de nombreuses méthodes permettant de faire des arrondis :

Arrondir avec Math

Avec Math.ceil(x), on obtient un arrondi de x à l'entier juste supérieur : ceil veut dire plafond en anglais.

Ainsi:

  • 8.36 donne 9
  • 8.49 donne 9
  • 8.50 donne 9
  • 8.92 donne 9

Avec Math.floor(x), on obtient un arrondi de x à l'entier juste inférieur : floor veut dire sol en anglais.

Ainsi :

  • 8.36 donne 8.
  • 8.49 donne 8
  • 8.50 donne 8
  • 8.92 donne 8.

Avec Math.round(x), on obtient un arrondi de x comme on le fait naturellement : si la partie décimale est inférieure strictement à 0.5, on arrondit à l'inférieur. Sinon, on arrondit au supérieur.

Ainsi :

  • 8.36 donne 8.
  • 8.49 donne 8
  • 8.50 donne 9
  • 8.92 donne 9.

Point ou virgule ? : attention, Javascript attend des nombres réels ( 'à virgule' ) en utilisant la notation anglosaxonne : on notera ainsi 3.2 et pas 3,2. Faites vraiment attention à cela, sinon vous risquez de voir assez rapidement que votre beau code ne fonctionne pas !

09° Utiliser la remarque précédente pour obtenir maintenant un nombre entier ne pouvant valoir que 0, 1, 2, 3.

...CORRECTION...

var x = 4*Math.random(); // x compris entre 0 et 3.99999

x = Math.floor(x); // x vaut 0,1,2 ou 3

alert(x);


En plus rapide, on condense tout en une ligne :

alert(Math.floor(4*Math.random()));

10° Utiliser la remarque précédente pour obtenir maintenant un nombre entier ne pouvant valoir que 1, 2, 3, 4.

...CORRECTION...

var x = 4*Math.random(); // x compris entre 0 et 3.99999

x = Math.ceil(x); // x vaut 1,2,3 ou 4

alert(x);


En plus rapide, on condense tout en une ligne :

alert(Math.ceil(4*Math.random()));

Correction alternative et plus rigoureuse : la précédente peut donner 0 très très rarement : si la valeur est 0, son arrondi donnera 0 aussi.

...CORRECTION...

var x = 4*Math.random(); // x compris entre 0 et 3.99999

x = 1 + Math.floor(x); // x vaut 1,2,3 ou 4

alert(x);


En plus rapide, on condense tout en une ligne :

alert(1 + Math.floor(4*Math.random()));

Si on change 1 en valeur minimale (inclus) et 4 en valeur maximale (inclus) vous devriez être capable de vous créer une belle fonction qui générera n'importe quel nombre entier aléatoire entre fournissant en argument ces deux valeurs extrêmes. Non ? Sinon, pensez à m'appeler.

4 - Mini-projet

Et si vous réalisiez une fonction change_couleur qui change aléatoirement la couleur de la div sur laquelle on clique en utilisant un index tiré au hasard et le tableau tCouleurs ?

A vous de jouer. Voici le résultat attendu.

Et la prochaine fois, nous rajouterons les images et les cris d'animaux !