Des pixels

L’élément <canvas> est apparu avec le HTML5, celui-ci est une zone rectangulaire qui permet de lire et écrire chaque pixel à l’unité ou par groupe et de manipuler ces données.
Techniquement, cela vous permet de dessiner ou de refaire des effets « Photoshop » dans une page web. Si vous êtes habitué à Processing et son rendu pixel, vous êtes dans un registre similaire. D’ailleurs, la version JavaScript de Processing P5JS utilise la balise canvas.
L’inconvénient du canvas est sans doute le calcul des opérations, si vous voulez manipuler chaque pixel d’une image de 10 sur 10 pixels, cela donne 100 calculs, pour 100 pixels sur 100, 10 000, et pour du « full hd » de 1920 sur 1080 pixels, plus de 2 millions d’opérations.
Malgré ceci, on pourra utiliser cette balise à travers P5JS, des petits jeux à l’aide d’une librairie, des démos et autres.

HTML, SVG ou Canvas

Attention, refaire une interface en 100% canvas, n’est pas simple et amène son lot de problèmes en interactivité, accessibilité, référencement, responsive. On réservera cette balise pour les effets, les jeux et les expérimentations. Pour des animations simples, vous pouvez animer les éléments HTML via CSS ou SVG via JS.

Charger des images

Autres problèmes fréquents avec canvas le web ; vous ne pouvez pas analyser une image si celle-ci n’est pas chargée à 100%. Lancer une fonction d’analyse avant chargement retournera un résultat faux ou une erreur.

Un damier de 2 images

Cloner l’image dans le canvas

Pour le HTML, j’ai besoin d’un canvas et d’une image. Attention, j’ai fixé la taille du canvas dans le HTML !

  <img id="imgA" src="https://picsum.photos/g/400/400/?random" alt=""><!-- image ~ lorem ipsum 400 sur 400 -->
  <canvas id="canvas" width="400" height="400"></canvas>
// voir https://developer.mozilla.org/fr/docs/Tutoriel_canvas/Utilisation_d'images
 
// mon élément canvas
var canvas = document.querySelector('#canvas'); 
// truc à faire pour écrire ou lire
var ctx = canvas.getContext('2d');
// on crée une image temporaire
var img_tmp = new Image();
 
// on ajoute un écouteur qui surveille le chargement de la src
img_tmp.addEventListener('load',function() { // *
  // on clone et on place à 0,0 notre image
  ctx.drawImage(img_tmp, 0,0);
});
 
// on donne une source à notre image_tmp (ce qui lancera le load de la ligne *)
img_tmp.src = document.querySelector('#imgA').src;

voir le codepen

La méthode drawImage permet de passer une image source et jusqu’à 8 paramètres de coordonnées, dimensions de la source vers sa destination (le canvas).

ctx.drawImage(image, dx, dy); // d => destination
ctx.drawImage(image, dx, dy, dWidth, dHeight);
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); // s => source

On s’accroche !

ctx.drawImage(img_tmp, 100,100,200,200, // va prendre un carré de 200 sur 200 px à partir de 100,100
                       100,100,200,200); // le colle à 100,100 sur 200 sur 200
ctx.drawImage(img_tmp, 100,100,200,200, // va prendre un carré de 200 sur 200 px à partir de 100,100
                       100,100,100,100); // le colle à 100,100 sur 100 sur 100 (ce qui le redimensionne de 50%)

voir le codepen

Des bandes

En maitrisant une boucle, je dessine des bandes de 10 sur 400 que je décale de 20 pixels.

for(var i=0;i<20;i++){
  ctx.drawImage(img_tmp, i*20,0,10,400,
                         i*20,0,10,400);
}

voir le codepen

Un damier

Plus complexe, cela demande deux boucles imbriquées et une astuce mathématique.
1re étape, avec une case de 10 pixels, j’ai besoin de 40 lignes (j40) et 20 colonnes (i20).

for(var j=0;j<40;j++){
   for(var i=0;i<20;i++){
     ctx.drawImage(img_tmp, i*20,j*10,10,10,
                            i*20,j*10,10,10);
   }
}

voir le codepen

Hélas, j’obtiens des bandes car les lignes paires ne se décalent pas. Pour remédier à ceci, « %2 » est notre ami. Il s’agit du « modulo de 2 » qui retourne 1 si le chiffre est impaire ou 0 si le chiffre est paire.


0%2=0
1%2=1
2%2=0
3%2=1

Je vais donc ajouter 10 au x selon j%2 (si la ligne est impaire + 10, sinon + 0).

ctx.drawImage(img_tmp, i*20+j%2*10,j*10,10,10,
                       i*20+j%2*10,j*10,10,10);

voir le codepen

Et si je veux décaler le damier.

ctx.drawImage(img_tmp, i*20+(j+1)%2*10,j*10,10,10,
                       i*20+(j+1)%2*10,j*10,10,10);

voir le codepen

Avec deux images

See the Pen canvas 07 by Benoît Wimart (@benoitwimart) on CodePen.0

version avec taille de la case ajustable