Relecture d'une fonction javaScript


#1

Bonjour,

Pour mon portfolio j’ai besoin de faire un effet ‘scratch card’, et j’ai trouvé un code, qui fonctionne, mais je l’ai copié collé, modifié les cibles, mais j’aimerais que l’on m’en explique les détails, parce que j’ai envie d’apprendre, et ne pas copier bêtement…
Si l’un d’entre vous avait la gentillesse de m’expliquer l’utilité du code point par point ce serait formidable !
Merci par avance :)

var tableau = document.getElementById("grat1"),
tablCanvas = tableau.getContext('2d'),
brushRadius = (tableau.width / 100) * 5,
img = new Image();

if (brushRadius < 50) { brushRadius = 10 }
img.onload = function(){  
	tablCanvas.drawImage(img, 0, 0, tableau.width, tableau.height);
};
img.loc = 'https://blabla/v1485734874/';
img.filename = 'pinceau_flou_g2znk3.jpg';

if (window.devicePixelRatio >= 2) {
	var nameParts = img.filename.split('.');
	img.src = img.loc + nameParts[0]+"-2x"+"."+nameParts[1];
} else {
	img.src = img.loc + img.filename;
}

function detectLeftButton(event) {
    if ('buttons' in event) {
        return event.buttons === 1;
    } else if ('keyCode' in event) {
        return event.keyCode === 1;
    } else {
        return event.button === 1;
    }
}

function getBrushPos(xRef, yRef) {
	var bridgeRect = tableau.getBoundingClientRect();
    return {
	  x: Math.floor((xRef-bridgeRect.left)/(bridgeRect.right-bridgeRect.left)*tableau.width),
	  y: Math.floor((yRef-bridgeRect.top)/(bridgeRect.bottom-bridgeRect.top)*tableau.height)
    };
}
      
function drawDot(mouseX,mouseY){
    tablCanvas.beginPath();
    tablCanvas.arc(mouseX, mouseY, brushRadius, 0, 2*Math.PI, true);
    tablCanvas.fillStyle = '#000';
    tablCanvas.globalCompositeOperation = "destination-out";
    tablCanvas.fill();
}

tableau.addEventListener("mousemove", function(e) {
  var brushPos = getBrushPos(e.clientX, e.clientY);
  var leftBut = detectLeftButton(e);
  if (leftBut == 1) {
		drawDot(brushPos.x, brushPos.y);
  }
}, false);

tableau.addEventListener("touchmove", function(e) {
    e.preventDefault();
    var touch = e.targetTouches[0];
    if (touch) {
    var brushPos = getBrushPos(touch.pageX, touch.pageY);
        drawDot(brushPos.x, brushPos.y);
    }
}, false);

#2

Bonjour,
Demander d’expliquer point par point un code va souvent finir sans réponse.
Le mieux, c’est de nous demander d’expliquer une partie précise du code.

Nous fournir la coloration syntaxique et l’indentation serait bienvenue. Merci de changer ta « citation » (>) en « code » (` * 3).

Déjà, les grandes parties que je peux expliquer rapidement (bloc = lignes de code sans ligne vide) :

  • Premier + deuxième blocs : initialization du canvas et des paramètres (classique)
  • troisième bloc : je ne sais pas ce que fonctionnellement ça fais. Techniquement, ça change l’url de l’image selon le ratio de ton écran (pour mobile, principalement). Peut-être une image zoomée ?
  • detectLeftButton : Est-ce que l’événement en cours a le clic gauche enfoncé ?
  • getBrushPos : Position du pinceau (≈ du curseur/doigt) sur le canvas
  • drawDot : Dessine un point (≈cercle) autour du point fourni
  • Les deux listeners : Lorsque tu bouges ta souris avec le bouton gauche enfoncé ou ton doigt, dessine le cercle autour de celui-ci

Si tu as besoin de détail, merci de préciser ta question.

Bon apprentissage,
Gaëtan


#3

Bonjour joanC,

En ce qui concerne l’explication des fonctions, il y a le site MDN en français qui t’aideras énormément j’imagine. Si tu ne sais pas par quel bout le prendre, je vais te montrer par l’exemple la démarche pour comprendre un code inconnu.

Bien entendu cela sera plus simple pour moi car j’en connais bien plus mais dans les fait la démarche serait la même pour toi.

Pour être dans des conditions de compréhension de code, je ne vais pas tester le code pour en retirer une reflexion authentique.

Pour finir je vais remettre le code dans une version lisible car l’indentation et la bonne écriture du code fait parti intégrante de la possibilité de relecture de celui-ci

/* Création d'une variable `tableau` dans le scope globale 
   à laquelle est assigné par référence l'objet `HTMLElement` 
   dont l'attribut `id` est de valeur `grat1`.
   Le fait qu'elle soit dans le scope globale signifie
   qu'on pourra lire/modifier sa valeur partout dans le code. */
var tableau = document.getElementById("grat1"),

	/* Création d'une variable `tableCanvas` dans le scope globale contenant une 
	   représentation / un espace de travail dans lequel on
	   va pouvoir « dessiner » en 2 dimension (le dessin habituel quoi).

	   À ce stade je devine que `tableau` contient une référence sur un objet
	   `<canvas id="grat1"></canvas>` c-à-d qu'il est très exactement de type
	   `HTMLCanvasElement` car il contient la methode `getContext` 
	   (et c'est le canvas qui possède cette méthode). */
    tablCanvas = tableau.getContext('2d'),

	/* Création d'une variable `brushRadius` (tjs globale) contenant une valeur de type
	   `number` dont la calcule est basé sur la largeur du canvas comme l'indique l'utilisation
	   de `tableau.width`. Ce calcule ressemble à une « règle de 3 » comprendre par la quel est la valeur de taille de
	   5% de la taille du canvas. À ce stade, je ne sais pas à quoi cela va servir, cependant brush fait référence à un pinceau il me semble
	   et radius est la diamètre divisé par 2 du cercle que celui-ci prendra pour dessiner. Il y a de forte chance que sa serve à dessiner
	   / écrire ou gommer. */
	brushRadius = (tableau.width / 100) * 5, 

	/* Création d'une variable `img` (tjs globale) contenant une référence vers un objet `HTMLImgElement`
	   dont la représentation dans le DOM HTML sera `<img>`. Cet objet nouvellement créer n'existe
	   qu'en mémoire car actuellement il n'a pas été placé dans le DOM. */
	img = new Image();

/* Dans le cas ou `brushRadius` (5% de la largeur du canvas) est inférieur à `50`,
   décidé que cette valeur est `10`. */
if (brushRadius < 50) { brushRadius = 10 }

	/* Abonner notre `img` à l'évènement `load`. Cela signifie que, dès que l'image qui va être contenu par `<img>` sera
	   totalement chargée, la fonction associé sera exécutée. */
	img.onload = function() {

		/* Quand la fonction sera executée elle dessinera dans le contexte 2D
		   le dessin suivant : « coller » l'image contenu par `<img>`, la collé à partir du coin haut gauche
		   en position x:0 et y:0 et étendre cette image sur toute la largeur du `tableau` (et donc de la représentation 2D) (`tableau.width`) et
		   sur toute la hauteur du `tableau` (`tableau.height`). On comprend donc que notre contexte de dessin est actuellement remplis par l'image
		   de `img` qui à se niveau de lecture du code ne possède pas encore d'image dans sa source. Et cette fonction n'est pas encore utilisée. Elle le sera plus loin. */
		tablCanvas.drawImage(img, 0, 0, tableau.width, tableau.height);
	};

	/* Création d'une propriété non standard `loc` sur `img` (c'est à dire qu'elle ne représente rien pour l'objet `HTMLImgElement`).
	   Cela sert à stocker de l'information qui va suivre l'objet `img` je suppose car c'est plus pratique que de créer une variable « volante »
	   pour le suivit. Le revers de la médaille c'est que si tu cherches à savoir ce que représente `loc` pour un objet de type `HTMLImgElement` tu ne trouverras rien. Par acquis de conscience nous allons sur Google et tapons `HTMLImgElement`. La première page (française) est celle de MDN. On l'ouvre, `ctrl + f` et on cheche la valeur `loc`. 0 résultat. J'avais donc bien deviné que `loc` était juste une valeur arbitraire. Puisque cette valeur représente une URL, et qu'on l'a attachée à `img`, j'imagine que ça représente le chemin vers l'image qui sera chargée dans `img`. Ce qui n'est actuellement pas le cas. */
	img.loc = 'https://blabla/v1485734874/';

	/* Idem que au dessus, pas standard, etc. Représente comme `filename` le suggère le nom du fichier image à l'adresse de `loc`. */
	img.filename = 'pinceau_flou_g2znk3.jpg';

	/* De mémoire `window.devicePixelRatio` permet de connaître la densité de pixel « virtuel » dans un pixel réel. Mais comme c'est plus très clair dans ma tête je demande à google `window.devicePixelRatio`, je tombe sur la référence MDN et c'est exactement ça. Je cherche encore un peu, je m'intéresse au retina, je matte dans google image 2, 3 schémas et je comprends. C'est à dire que si notre cadre fait 100px sur 100px et que l'image qu'on y place fait 100px sur 100px mais que le périphérique peut afficher 4 pixels physique (largeur x hauteur) dans 1 pixel virtuel, en réalité pour « exploiter la précision de l’appareil il faudrait lui donner une image de 200px par 200px soit x2. C'est exactement ce que fait ce test. On fait cela pour les écrans de type retina.
	Du coup si le ratio est supérieur à 2 on va chargé la partie `if`, sinon la partie `else`. */
	if (window.devicePixelRatio >= 2) {

		/* On associe à une variable globale `nameParts` le nom du fichier sans l'extension car `img.filename` vaut `pinceau_flou_g2znk3.jpg` comme vu plus haut et `split('.')` retourne un tableau dont chaque élément est ce qu'il se trouve de part et d'autre des caractères `.`. On obtient donc ici `["pinceau_flou_g2znk3", "jpg"]`. Notons que `nameParts` est défini à un endroit vraiment maladroit car il laisse supposer qu'il n'est accessible que dans le `if` ce qui n'est pas le cas. Si une variable n'est pas défini dans une `function () {}` (pour appartenir à cette fonction), elle est globale. C'est ce qu'on appelle le champ lexical d'une fonction ou `scope`. Il aurait fallut définir `nameParts` sans valeur à la ligne juste après `img = new Image();` par exemple `img = new Image(), nameParts;` et ensuite seulement assignée ici la valeur `nameParts = img.filename.split('.');` pour aider tout le monde à bien comprendre sa réelle portée. */
		var nameParts = img.filename.split('.');

		/* Comme le ratio est supérieur à 2, on va affecter à la propriété `src` de l'objet `img` (`HTMLImageElement`) l'image `img.loc + nameParts[0]+"-2x"+"."+nameParts[1]` à savoir `'https://blabla/v1485734874/' + 'pinceau_flou_g2znk3' + '-2x' + '.' + 'jpg' `, càd l'image se situant à l'addresse `https://blabla/v1485734874/pinceau_flou_g2znk3-2x.jpg`. Cette image est justement 2x plus grande pour permettre à l'écran d'être bien exploitée */
		img.src = img.loc + nameParts[0]+"-2x"+"."+nameParts[1];
	} else {

		/* Ici on charge le fichier normal avec écran non rétina. En ce qui concerne `src`, c'est une propriété réelle de `HTMLImageElement` qui représente l'élément HTML dans le DOM suivant `<img src="https://blabla/v1485734874/pinceau_flou_g2znk3.jpg">` dans cet exemple. Dès l'instant ou la valeur de `src` est modifiée, ce qui est le cas ici, elle envoi un signal de type `load`. On a vu plus haut que si `load` était envoyé, alors on exécutait une fonction qui dessine l'image dans le cadre. Et bien c'est à ce moment là que ça démarre ! */
		img.src = img.loc + img.filename;
	}

Je m’arrêterai là pour aujourd’hui. Je t’encourage à faire la même démarche pour comprendre la suite même si contrairement à moi, tu vas faire bien plus de recherche sur Google. Si tu bloques sur un point précis du langage en lui même ou pour tout autre question JS, tu peux venir en discuter en live ici si tu as un compte Github.

Il y a du monde qui pourra t’aider en JS et en français.

Sinon attends qu’une âme charitable t’explique la suite ou que je n’ai pas d’autres postes auquel répondre la prochaine fois que je suis en créneau horaire « aide bénévole ».

Mais c’est assez calme sur Human Coder niveau JS et ça fait du bien d’écrire un peu en FR donc p-e la semaine prochaine ;)

PS : excuse moi pour toutes ces fautes d’ortho et de conjugaison, je n’ai pas pris de temps à la relecture :s


#4

Merci beaucoup !!
Oui bien évidemment j’ai fait les recherches sur google et MDN, c’est mon premier reflexe, mais pour autant je ne comprenais pas plus… Enfin à quoi sert telle fonction oui, mais ça ne m’aidait pas à comprendre “pourquoi cela ici, sur quoi il agit, quelle est la démarche” etc. Enfin tes explications sont super et m’aident beaucoup !
Un grand merci (à tous les deux !)

Je vais continuer à essayer de comprendre la suite, mais si tu repasses par là, c’est avec grand plaisir :)


#5

Je viens d’analyser toutes tes réponses, tu expliques vraiment bien, c’est super merci encore!


#6

Re @joanC

Voici la fin de l’explication du code.

Ce qu’il faut également garder à l’esprit c’est que la difficulté de compréhension d’un code dépend certe du nombre de fonctionnalité que tu ne connais pas qu’il utilise ainsi que le nombre d’élément de syntaxe de langage différent que tu ne connais pas.

Mais ce n’est pas tout, a difficulté dépend également de la manière dont celui-ci est proprement écrit ordonné et commenté ce qui est pour le coup indépendant de toi.

Il n’est pas important de toujours comprendre tout ce que tu manipules. Dans ce sens la réponse de @kneelnrise est une des manières d’appréhender un code inconnu. On se réfère aux grosses sections, et on fait des déductions par rapport au nom. Tester le code permet également de mieux le comprendre, chose que dans mon cas je n’ai pas faites.

La vrai question c’est : comment savoir, quand on a un code, quel partie je devrais lire et quel partie je ne devrais pas lire pour le comprendre. Car comment savoir qu’on aurait pas dû s’attarder sur une partie qui nous en a pas appris plus, avant d’y avoir consacrer du temps ?

Et c’est là qu’à mon sens la propreté du code et son rangement sont ce qui fait la différence entre 2 codes qui font la même chose.

Un code bien rangé, facile à lire en diagonale est un bon code ce qui n’est pas le cas ici. En tant que débutant il est difficile de comprendre quelles parties sont bonne à lire, et quelle parties sont bonne à ignorée.

Je te laisse me donner ton avis sur cette page qui explique comment produire du code JavaScript qui justement permet différent niveau de relecture de manière à savoir exactement quel niveau de compréhension tu souhaites avoir sur un code. Celui de @kneelnrise ou le miens. Cela pourra peut-être t’aider à choisir tes futurs code ou à les écrires proprement.

Coder proprement en JavaScript par l’exemple : Upload d’image

En attendant, chose promise, chose due :p

/* Déclaration d'une fonction (qui aurait dû être définie avant le premier `if` de l'environnement 
   global par convention afin d'avoir
   1. Une partie déclaration
   2. Une partie logique. C'est ce qui est expliqué dans le lien de l'article plus haut.
   Cette fonction prend en premier paramètre `event`.
   À ce stade je ne sais pas trop ce que cela fait mais d'après le nommage
   Ça analyse un événement pour en déduire que le « boutton » gauche fait quelque chose.
   On parle probablement du clique gauche de la souris, nous verrons plus loin. */
function detectLeftButton(event) {

    // Si l'objet event à une propriété qui se nomme "buttons" alors...
    if ('buttons' in event) {
        // dans le cas ou cette propriété vaut 1, on retourne true
        // sinon on retourne false.
        return event.buttons === 1;
    // Si l'objet event à une propriété qui se nomme "keyCode" alors...
    } else if ('keyCode' in event) {
        // dans le cas ou cette propriété vaut 1, on retourne true
        // sinon on retourne false.
        return event.keyCode === 1;
    // Si il n'y a ni buttons ni keyCode alors on test button (sans s).
    } else {
        // dans le cas ou cette propriété vaut 1, on retourne true
        // sinon on retourne false.
        return event.button === 1;
    }

    // La question ici c'est. Pourquoi ce test ? Pourquoi event pourrait t-il tantôt avoir « buttons », tantôt « keyCode » et tantôt « button ».
    // On pourrait fouiller un peu sur Google mais pour le moment j'emets l'hypothèse que c'est pour des raisons de compatibilité navigateur. J'emet également l'hypothèse qu'en fonction du type d'événement et de l'état de `event` les 3 valeurs pourrait retourner `0` sous entendu le bouton n'est pas enfoncé.
    // Nous en saurons p-e plus, plus loin, donc on recherchera plus tard si vraiment cela nous bloque.
}

// Idem que au dessus. D'après le nom on s'attend à ce que cette fonction nous retourne à quel endroit
// se trouve notre « Brush » soit pinceau. Si on réfléchi 2 secondes. Les seuls manière de dessiner sur
// un écran c'est avec sa souris ou son doigt (ou un stylet) c-à-d qu'en réalité sous ce nom on veut probablement
// indiquer ou sera positionné la sourie à un moment donnée. Pour connaître la position de quelque chose sur un plan
// 2D (context en 2D), il nous faut une valeur de position horizontal et vertical. Ça tombe bien les paramètres `xRef` et `yRef` semblent
// représenter ses valeurs.
function getBrushPos(xRef, yRef) {
    // Ici `var` est au bon endroit. Il est défini au sommet d'une fonction. Il est donc dans le `scope` de la fonction et ne sera utilisable
    // que dans celle-ci. On affecte à la varialbe `bridgeRect` la valeur de `tableau.getBoundingClientRect()`. 
    // On se souvient que `tableau` est un `HTMLElement` (un `HTMLCanvasElement` plus exactement). Je sais que `getBoundingClientRect()` retourne un objet
    // permettant de situer le canvas par rapport à la fenêtre du navigateur mais je n'en suis plus sur. Je demande à Google et je file dans les images car
    // visuellement c'est plus simple. Je vois qu'il contient 6 propriété : `left`, `top`, `right`, `bottom`, `width`, `height`.
    // `left`, `top`, `right`, `bottom` désigne la position des 4 bords du cadre par rapport au haut de l'affichage du navigateur. Ces valeurs changent donc 
    // quand on scroll dans la page car elles représente la position du canvas dans l'espace visible par rapport au bord haut et gauche.
	var bridgeRect = tableau.getBoundingClientRect();

    // On s’aperçoit ici que `bridgeRect.right-bridgeRect.left` représente en réalité la valeur `width` car soustraire la valeur la plus éloigné du bord gauche
    // à celle la plus proche nous donne le morceau représentant la largeur. On aurait donc tout simplement pu utiliser `bridgeRect.width`. Idem avec `bridgeRect.height`.

    // Grâce à `xRef-bridgeRect.left` je devine qu'on cherche à obtenir la valeur de la position de la souris non pas par rapport à la fenêtre du navigateur,
    // Mais par rapport à la position du canvas dans cette fenêtre. Enfin vu qu'on multiplie la largeur du canvas dans la fenêtre du navigateur par sa valeur réelle,
    // je suppose que c'est au cas où il y ai un zoom dans le navigateur. Pour finir, on tronque les valeurs à l'entier inférieur `Math.floor`.
    return {
	  x: Math.floor((xRef-bridgeRect.left) / (bridgeRect.right-bridgeRect.left) * tableau.width),
	  y: Math.floor((yRef-bridgeRect.top) / (bridgeRect.bottom-bridgeRect.top) * tableau.height)
    };

    // On a donc la position de notre souris sur le `canvas` ou x = 0 et y = 0 veut dire qu'on dessine dans le coin haut gauche et que toute les autres valeurs permette
    // de situer la souris dans le canvas.
}

// D'après le nom, on va dessiner un point.
// D'après les paramètres, on va dire ou dessiner le point.
function drawDot(mouseX,mouseY){

    // Je ne connais pas `beginPath`, go Google.
    // À priori c'est pour tracer un trait, un `path`, et ça indique que vis à vis
    // De ce que l'on va faire ensuite
    // cela représente le début des instructions.
    tablCanvas.beginPath();

    // Je suppose donc qu'on va dessiner une portion de cercle, « un arc » et que pour le dessiner on va
    // donner la position en `mouseX` et en `mouseY` du centre de l'arc, en donner l'éloignement vis à vis de ce centre (`brushRadius`)
    // ensuite la valeur 0 je ne sais pas, puis je suppose en voyant `2*Math.PI` que l'on trace un arc complet (soit un cercle)
    // ensuite la valeur `true` je ne sais pas. Je suis curieux, je file voir la doc sur Google.
    // Je m’aperçois que `0` (troisième valeur) correspond à l'angle de départ. Cela est logique car il faut bien commencer son tracé d'arc quelque part.
    // Ensuite la quatrième valeur (`2*Math.PI`) dit ou on va terminer sont tracé. On aura donc fait un tour. La valeur `true` indique que l'on effectue le
    // tracé dans le sens anti-horraire. Ici ça ne change rien puisque le cercle est complet, peut importe de quel sens part l'arc, on aura
    // un cercle complet. On pourrait donc ne rien mettre ou mettre `false`.
    tablCanvas.arc(mouseX, mouseY, brushRadius, 0, 2*Math.PI, true);

    // On remplit l'intérieur du cercle avec la couleur `#000`.
    tablCanvas.fillStyle = '#000';

    // On a `globalCompositeOperation` et ça je sais pas ce que c'est, je demande. Ça permet de définir comment on veut ajouter le contenu !
    // D'après l'exemple que j'ai vu. Ça ressemble à une gomme ! On n'est donc pas entrain d'écrire,
    // Mais entrain d'effacer le contenu en arrière plan. On est donc entrain de créer un « point d'effacement ».
    // Probablement pour effacer l'image qu'on mettra en fond.
    tablCanvas.globalCompositeOperation = "destination-out";

    // Et on effectue l'action (ce qui signifie qu'entre `beginPath` et `fill` c'était la préparation de comment on allait faire).
    tablCanvas.fill();
}

// Comme avec `load` sur `img`, on écoute ici sur le canvas les mouvements de la souris avec `mousemove`.
// De la même manière qu'affecter `img.src` déclenchait le `load`, ici le mouvement dans la zone du canvas va
// déclencher le `mousemove`. 

// Tu remarquera que le `load` avait été affecté avec `img.onload` alors que la le `mousemove` est affecté avec `addEventListener("mousemove"`. En réalité si le code était plus propre, on aurrait remplacé `img.onload` par `img.addEventListener("load"` comme pour `mousemove`. La différence est que en `ajoutantUnÉcouteurDÉvénement` on permet plus tard dans le code d'en ajouter d'autre, et puis d'autre. Alors qu'en utilisant `img.onload` on ne peut définir qu'un seul événement pour cette action à travers tout le code. C'est une mauvaise pratique. `img.onload` est l'équivalent de `<img onload="">` comme `img.src` est l'équivalent de `<img src="">`. `addEventListener` quand à lui est une vrai alternative JavaScript pour bien manipuler ce qu'il se passe sur les éléments du navigateur. 

// On peut donc dire que cela ce lit :

// Quand la souris bouge...
tableau.addEventListener("mousemove", function(e) {
    // trouver ou elle se trouve sure le canvas (par rapport à lui, et pas au navigateur)
  var brushPos = getBrushPos(e.clientX, e.clientY);
    // vérifier si le clique gauche de la souris est enfoncé (donc c'était bien pour couvrir tous les navigateurs).
  var leftBut = detectLeftButton(e);
    // et SI le clique gauche est enfoncé...
  if (leftBut == 1) {
        // ... gomer à la position indiquée !!!
		drawDot(brushPos.x, brushPos.y);
  }

// La valeur `false` ici signifie que l'événement sera écouté pendant la phase de remonté d'événement `bubbling`.
// Si il était à vrai, il serait écouté pendant la phase de `capture`.
// Cela signifie que si je bouge ma souris au dessus du canvas, je la bouge également au dessus de tous les éléments HTML qui
// entoure le canvas. Si chacun de ses éléments écoutait le mouvement de la souris il se déclencherait s'il était tous avec cette valeur
// à false ans l'ordre `canvas -> parent du canvas -> parent du parent du canvas -> etc`.
// Par contre avec cette valeur à true ce serait dans l'ordre `etc. -> parent du parent du canvas -> parent du canvas -> canvas`
// Pour résumer quand un mouvement de souris est effectué au dessus du canvas dans `<div><ul><canvas></canvas></ul></div>`
// on peut intercepter les événement dans cette ordre 
// div.addEventListener(..., ..., true) -> ul.addEventListener(..., ..., true) -> canvas.addEventListener(..., ..., true) 
// puis -> canvas.addEventListener(..., ..., false) -> ul.addEventListener(..., ..., false) -> div.addEventListener(..., ..., false)
}, false);

// Même punition avec `touchmove`. Celui-ci est déclenché quand des doigts (ou stylets) entre en
// contact avec l'écran dans la zone du canvas.
tableau.addEventListener("touchmove", function(e) {
    // On empêche le comportement par défaut, cela évite que la page scroll quand on pause
    // le doigt sur le canvas.
    e.preventDefault();

    // Dans le cas d'un événement `touchmove`, le premier paramètre de la fonction de retour (callback) `e` contient un tableau `targetTouches`.
    // Ce tableau contient tous les endroits (en x et y) sur le canvas ou les doigts sont en contact avec l'écran.
    // Cela permet de gérer si on le voulait plusieurs trait d'effacement. Ici on ne gère que le premier doigt en contact, c-à-d l'indice `0` du tableau.
    var touch = e.targetTouches[0];

    // Si cette indice retourne un objet contenant les coordonnée x et y du doigt.
    if (touch) {
    // Alors on trouve la position du doigt non pas par rapport à l'écran du navigateur (ce que renvoi `e.targetTouches[0]`) mais
    // on la trouve par rapport au canvas (noter que `brushPos` devrait être déclarer au même endroit que `touch` et être affecté dans le if. 
    var brushPos = getBrushPos(touch.pageX, touch.pageY);
        // et on gomme l'image à cette position.
        drawDot(brushPos.x, brushPos.y);
    }
}, false);

PS : Je serais toi je renommerai ce post « Relecture d’une fonction JavaScript : niveau de lecture », j’éditerais un peu mon message que toute cette conversation soit profitable à plus de monde que toi seul :)

Bonne continuation !


#7

Un grand merci pour toutes ces explications, vraiment, et pour le lien que je vais m’empresser de lire.
J’aimerais etre capable de la reproduire seule, mais je pense qu’il va falloir un peu de temps.
Meme si je comprenais les ‘termes’ (enfin pas tous loin de là) je ne comprenais pas forcément comment ils étaient utilisés et pourquoi.
Je pense avoir bien tout cerné grace à toi, et tu fais partie de ceux qui aident à avancer et ne pas perdre pieds…
:)