Apprendre le JavaScript en dessinant...

p5.js est une librairie JavaScript (pour simplifier, un ensemble de fonctions) un environnement de programmation simple et adapté aux débutants, comme des designers, artistes, enseignants, étudiants ou autres, dans lequel on peut créer et animer des formes qui s'affichent dans une page web.

Tenter de s'approprier cette bibliothèque permet de découvrir les bases du langage JavaScript et d'apprendre d'une façon visuelle et ludique.

Ressources & Outils :

1. Installation

Télécharger la librairie complète : http://p5js.org/download/

Décompresser le dossier p5-zip, il contient un sous-dossier empty-example qui sera notre premier espace de travail.

Ouvrir dans brackets les fichiers index.html et sketch.js.

<html>
<head>
  <meta charset="UTF-8">
  <script type="text/javascript" src="libraries/p5.js"></script>
  <!-- uncomment lines below to include extra p5 libraries -->
  <!--<script src="libraries/p5.dom.js"></script>-->
  <!--<script src="libraries/p5.sound.js"></script>-->
  <script type="text/javascript" src="sketch.js"></script>
  <!-- this line removes any default padding and style. you might only need one of these values set. -->
  <style> body {padding: 0; margin: 0;} </style>
</head>

<body>
</body>
</html>
<script type="text/javascript" src="libraries/p5.js"></script>
<script type="text/javascript" src="sketch.js"></script>

L'élément script permet à la manière de l'élément link pour les feuilles de style, de lier au fichier html nos 2 fichiers javascript : 

Le premier p5.js contient la librairie et n'a pas à être modifié. Le second, sketch.js est celui sur lequel nous écrirons notre code.

Il contient deux fonctions setup() et draw()

function setup() {

}

function draw() {
  
}

La fonction setup() définit la configuration de départ et ne s’exécute qu’une seule fois. On y précise notamment la taille de notre surface de dessin, l'élément canvas (pour en savoir plus). 

La fonction draw() tourne en boucle, elle s'exécute à chaque rafraîchissement de l'image, environ 60 fois par seconde (60 FPS) et contient les éléments qui vont être dessinés dans le navigateur. Si les éléments à afficher sont trop nombreux ou trop complexes, le nombre de FPS diminue.

Un premier exemple commmenté : 

Taper (ou copier) le code suivant dans le fichier sketch.js

function setup() {
  createCanvas(640, 360);
}

function draw() {
    background(0,255,255);
    fill(125,200,0);
    ellipse(150,150,100,100)
}

La fonction frameRate() permet d'imposer le nombre de FPS :

frameRate(5);

Par ex. si on veut ralentir une animation, on peut imposer un framerate de 5 images par seconde.

La fonction createCanvas() créé une surface de dessin de 640 px de large et 360 px de haut. La fonction background() définit la couleur d'arrière-plan, fill(), la couleur de remplissage du disque dessiné à la ligne suivante et enfin la fonction ellipse() dessine un disque (ses deux premiers paramètres sont les coordonnées du centre et les deux derniers sont les dimensions).

2. Les bases du dessin

Dans p5.js le repère utilisé pour définir les coordonnées d'un point a son origine en haut et à gauche : 

  • Dessiner un point
point(x,y);
  • Dessiner un segment
line(x1, y1, x2, y2);
  • Dessiner un rectangle
rect(x, y, a, b);
  • Dessiner une  ellipse
ellipse(x, y, a, b);

x et y sont les coordonnées du sommet du rectangle situé en haut et à gauche.

x et y sont les coordonnées du centre de l'ellipse.

  • Dessiner un triangle
triangle(x1,y1,x2,y2,x3,y3);
  • Dessiner un quadrilatère
quad(x1,y1,x2,y2,x3,y3,x4,y4);

Épaisseur du contour des formes :

Par défaut le contour d’une forme est de 1 pixel. la fonction La fonction strokeWeight() permet de modifier l’épaisseur du contour. La fonction noStroke() permet de supprimer le contour.

  • La fonction arc() permet de dessiner une portion d'ellipse :
arc(x,y,a,b,angle_dep,angle_arr);

Travailler avec des degrés : la dernière ligne est équivalente à : 

arc(390, 60, 80, 80, radians(45), radians(225));

3. Colorier

Les fonctions stroke() et fill() définissent respectivement la couleur du contour et la couleur de remplissage. Elles se placent avant la forme à colorier. Elles acceptent des valeurs au format RGB ou RGBa (la 4ème valeur comprise entre 0 et 1 ajoute la transparence).

4. Les variables dans p5.js

Comme nous l'avons vu précédemment, la fonction draw() tourne en boucle. Cette propriété va nous permettre de créer des animations, des scénarios dans lesquels les formes bougent, interagissent avec les autres, réagissent à des événements, évoluent dans le temps... Les valeurs des différents paramètres du programme sont amenées à être modifiée lors du déroulement de celui-ci, ce qui rend nécessaire l'utilisation de variables.

Une variable stocke une valeur en mémoire afin qu’elle puisse être utilisée dans la suite du programme. Elle peut recevoir successivement de multiples valeurs lors du déroulement du programme.

En utilisant des variables, on évite aussi de répéter dans le code une même valeur, susceptible de varier, ce qui rend le code plus facile à maintenir :  Une modification au niveau d'une variable va se répercuter sur toutes ses itérations. 

Il y a des variables reconnues par p5.js comme mouseX et mouseY, respectivement l'abscisse et l'ordonnée du pointeur de la souris ou width et height, les dimensions du canvas.

 

Un deuxième exemple commenté : 

Taper (ou copier) le code suivant dans le fichier sketch.js

function setup() {
  createCanvas(600, 400);
  background(250, 250, 100);
}

function draw() {
  // background(250, 250, 100);

  // ellipse
  fill(250, 200, 200);
  ellipse(mouseX, mouseY, 100, 100);
  
  // rectangle
  // fill(200, 250, 200);
  // rect(400, 100, 50, 50);
}

// try mousePressed function 
function mousePressed() {
  background(250, 250, 100);
}

La fonction draw() qui s'execute en boucle dessine des disques centrés sur la position du pointeur de la souris. Si celle-ci est immobile , les disques s'empilent sinon de nouveaux disques sont dessinés en suivant le mouvement du curseur.

Nous utilisons dans cet exemple une nouvelle fonction mousePressed() qui exécute le code situé entre les accolades si l'utilisateur clique sur la souris. Ici la fonction redéfinit la couleur d'arrière plan ce qui a pour effet d'effacer les disques dessinés précédemment.

Introduction des événements :

Créer ses propre variables :

La première étape consiste à déclarer la nouvelle variable. Il faut ensuite l'initialiser, c'est à dire lui donner une valeur initiale.

Déclaration : 

var circleX; 

Initialisation : 

circleX = 50; 

Ici la variable s'appelle circleX

On affecte à circleX la valeur 50

Attention le signe = en JS ne veut pas dire "est égal à" mais "prend la valeur", c'est une affectation.

On peut déclarer et initialiser une variable en une seule instruction : 

var circleX = 50; 

Généralement on déclare les variables avant la fonction setup afin de pouvoir les utiliser n'importe où dans le programme, on parle de variables globales. Si vous déclarez une variable à l'intérieur d'une fonction vous ne pourrez l'utiliser qu'à l'intérieur de la fonction. 

Créer une animation à l'aide d'une variable :

Taper (ou copier) le code suivant dans le fichier sketch.js

var circleX = 50;

function setup() {
  createCanvas(600, 400);
}

function draw() {
  // background
  background(250, 250, 100);
  // ellipse
  fill(250, 200, 200);
  ellipse(circleX, 200, 80, 80);
  
  circleX = circleX + 1;
}

Dans cet exemple, la variable circleX désigne l'abscisse du centre du disque. L'animation est créée par l'instruction suivante :

circleX = circleX + 1

Comme nous l'avons vu précédemment ce qui peut ressembler à une égalité impossible est une affectation.

A chaque fois que la fonction draw() va s'exécuter, la valeur affectée à la variable circleX va augmenter de 1 : circleX prend la valeur circleX + 1

Un nouveau disque dont le centre se trouve un pixel à droite de celui du précédent disque va être dessiner ce donne l'impression que le disque avance.

On peut noter que le background est redessiné à chaque image (la fonction background() est à l'intérieur de la fonction draw() et non pas à l'intérieur de la fonction setup()). Dans le cas contraire tous les disques dessinés resteraient à l'écran comme dans l'exemple précédent.

Raccourcis :

x += 10; // est équivalent à x = x + 10
y −= 15; // est équivalent à y = y - 15

x++; // est équivalent à x = x + 1
y−−; // est équivalent à y = y − 1

En savoir plus :

5. Les instructions conditionnelles

if (condition) {
    instruction(s);
}

if

if (condition) {
    instruction1;
} else {
    instruction2;
}

if else

if (x > 5){
  // faire quelque chose
} else if (x > 50) {
  // faire autre chose
} else {
  // faire encore autre chose
}

La ou les instruction(s) sont exécutée(s) si la condition est vraie

Liste des opérateurs.

Liste des opérateurs logiques.

Taper (ou copier) le code suivant dans le fichier sketch.js :

var r=2;
var v=2;
function setup(){
    createCanvas(400,400);
    noStroke();
    fill(39, 31, 48);
}
function draw(){
  background(208, 252, 279);
  ellipse(200,200,2*r,2*r);
  if (r>200 || r<2){
    v=-v;
  }
  r=r+v;
}
 if (r>200 || r<2){
    v=-v;
  }

Si r > 200 ou r < 2 alors

v prend la valeur - v 

Coding Challenge #1

Coding Challenge #2

6. Les boucles

La boucle for

for (var i = 0 ; i <= width ; i+=10) {
line (i, 0, width-i, height)
}
var i = 0 ;     // initialisation

i <= width ;    // test : tant que i est inférieur ou égal à la largeur du canvas

i+=10           // incrémentation i = i + 10

line (i, 0, width-i, height)   /* on créé des lignes dont les extrémités sont respectivement :
(0, 0, width, height), (10, 0, width-10, height), (20, 0, width-20, height)... */ 

Une boucle for dans une boucle for

Coding Challenge #3

7. Positionner un canvas dans un fichier HTML

<html>
  <head>
    <title>Mon Canvas</title>
    <script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.6/p5.js"></script>
    <script src="sketch.js"></script>
  </head>
  <body>
    <p>Ceci est mon canvas</p>
    <div id="sketch-holder">
      <!-- notre canvas sera ici! -->
    </div>
    <p>Plutôt cool, non ?</p>
  </body>
</html>
// sketch.js

function setup() {
  var canvas = createCanvas(100, 100);
 
  // Move the canvas so it's inside our <div id="sketch-holder">.
  canvas.parent('sketch-holder');

  background(255, 0, 200);
}

Si vous souhaitez mettre plusieurs canvas sur une même page, c'est plus compliqué... par défaut les fonctions p5.js utilisent des variables globales et donc plusieurs fonctions setup et draw ne peuvent pas cohabiter sans un minimum de précautions...  Une des solutions consiste à passer en : 

var x = 100;
var y = 100;

function setup() {
  createCanvas(200,200);
}

function draw() {
  background(0);
  fill(255);
  ellipse(x,y,50,50);
}
var s = function(p) {

  var x = 100; 
  var y = 100;

  p.setup = function() {
    p.createCanvas(200, 200);
  };

  p.draw = function() {
    p.background(0);
    p.fill(255);
    p.rect(x,y,50,50);
  };
};

var myp5 = new p5(s);

"instance mode"

On créé une variable s, fonction de paramètre p (objet représentant notre canvas) que l'on appelle avec la variable myp5.

var arr = ["le premier élément", "le second élément"];  
console.log(arr[0]);             // affiche "le premier élément"    
console.log(arr[1]);             // affiche "le second élément"  
console.log(arr[arr.length - 1]);// affiche "le second élément"

var aList = [ [1, 4, 2], [7] ];       //tableau en 2d

8. Les Tableaux

9. Les objets

Un exemple pour comprendre : Repensons au disque animé dans l'exemple précédent. Si nous souhaitons utiliser plusieurs variables le caractérisant comme x et y pour les coordonnées de son centre d pour son diamètre... une bonne méthode pour organiser ces variables est de créer un objet nommé disque par exemple et d'y regrouper les variables.  

var disque = {
  x: 0,
  y: 200, 
  d: 50
};

Syntaxe pour la création d'un objet :

x, y et d sont ici les propriétés de l'objet disque. On y accède avec une notation utilisant le point « . » :

disque.x
disque.y
disque.z
var disque = {
  x: 0,
  y: 400, 
  d: 50
};


var r = 218;
var g = 160;
var b = 221;

function setup() {
  createCanvas(600, 400);  
}

function draw() {
  // background
  background(r, g, b);
  // ellipse
  fill(250, 200, 200);
  ellipse(disque.x, disque.y, disque.d, disque.d);
  
  disque.x = disque.x + 2;
  disque.y = disque.y - 2;
  disque.d = disque.d + 2;
}

Taper (ou copier) le code suivant dans le fichier sketch.js

10. La fonction map ()

Imaginons un scénario dans lequel deux grandeurs doivent varier de manière synchronisée mais elles ne varient pas sur la même échelle... La fonction map () est là pour résoudre le problème.

Dans l'exemple suivant nous souhaitons que la couleur d'arrière plan  varie en fonction de la position horizontale du disque sur le canvas. Cette dernière est déterminée par la variable mouseX et varie de 0 à 600. La variable r, déterminant la teinte de rouge  doit varier de 0 à 255 :

  r = map(mouseX, 0, 600, 0, 255);

r

mouseX

11. La fonction random ()

En construction...

Quand on maîtrise JS

quelques créations de Moses Holmström