Niveau : Confirmé

Introduction à Canvas

Tutoriel par (Développeur, Strasbourg)
Créé le (24134 lectures)
Tags : transparence, canvas, Transformation, ombrage, effet

Sommaire


Les effets

Transparence

Les couleurs de remplissage et de contour sont définies par fillStyle et strokeStyle. Si elles sont spécifiées via une valeur RGBA (A = Alpha), alors elles pourront utiliser un effet de transparence (ou opacité).

Voici un exemple de texte rouge avec une opacité de 50% (valeur = 0.5) par-dessus lequel sont tracés deux rectangles avec des couleurs et opacités différentes.

var text = "Hello kiwi!"; 
ctx.font = "30pt Verdana";
ctx.textAlign = "left"; 
ctx.textBaseline = 'top';
ctx.fillStyle = 'rgba(127,0,0,0.5)';
ctx.fillText(text,50,50);

ctx.fillStyle = 'rgba(252, 194, 0, 0.3)';
ctx.fillRect(160,50,150,50);

ctx.fillStyle = 'rgba(118, 174, 42, 0.4)';
ctx.fillRect(280,80,50,50);

Démonstration

Un autre attribut du contexte permet de fournir une transparence globale sans passer par une couleur RGBA. L'attribut globalAlpha appliquera un effet global de transparence à tous les tracés futurs. Sa valeur est comprise entre 0 et 1, 1 étant 100% opaque et 0 totalement transparent. 

ctx.globalAlpha = 0.5; // 50% opacité pour tous les tracés futurs
ctx.fillRect(0,0,100,100);
ctx.fillStyle = "blue";
ctx.fillRect(50,50,100,100);
ctx.fillStyle = "pink";
ctx.fillRect(100,100,100,100);
ctx.fillStyle = "green";
ctx.fillRect(150,150,100,100);
ctx.fillStyle = "gold";
ctx.fillRect(200,200,100,100);
ctx.fillStyle = "red";
ctx.fillRect(250,250,100,100);

Canvas GlobalAlpha

Démonstration

Ombres

Un ensemble de propriétés contrôlent la projection d'ombres pour les formes, tracés, textes, etc. Les paramètres sont les suivants :

  • shadowOffsetX : décalage horizontal
  • shadowOffsetY : décalage vertical
  • shadowBlur : quantité de flou
  • shadowColor : couleur de l'ombre

Ombrages Canvas

ctx.font = "30pt Verdana";
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 5;
ctx.shadowColor = 'orange';
ctx.fillStyle = 'olive';
ctx.fillText("Hello Kiwi!", 40, 60);
ctx.beginPath();
ctx.strokeStyle = 'skyblue';
ctx.shadowColor = 'grey';
ctx.lineWidth = 10;
ctx.arc(150,70,60,0,Math.PI,false);
ctx.stroke();

Démonstration

Composition

Avec Canvas, la composition régit les règles de superpositions de pixels. L'attribut globalCompositeOperation peut piocher parmi un ensemble de valeurs qui vont créer des effets tels que l'on peut en rencontrer sur des logiciels de traitement d'images lorsqu'il s'agit de superposer des calques. Il faut bien retenir ici cependant qu'il s'agit d'une composition à un moment donné, et que Canvas ne comprend pas à proprement parler de calques, à moins de superposer plusieurs éléments <canvas> différents.

  • Basées sur le nouveau contenu :
    source-over source-in source-out source-atop
  • Basées sur le contenu déjà présent :
    destination-over destination-in destination-out destination-atop
  • Basées sur le rapport entre les deux :
    lighter darker copy xor

Canvas composite

// La base est un carré Rouge
ctx.fillStyle = "crimson"; 
ctx.fillRect(100,100,150,150);

// Un cercle bleu qui n'est visible que dans le carré rouge source
ctx.globalCompositeOperation = "source-atop";
ctx.fillStyle = "deepskyblue";
ctx.arc(50,50,150,0,Math.PI*2,true);
ctx.fill();

// Un carré orange placé "en-dessous" de la source
ctx.globalCompositeOperation = "destination-over";
ctx.fillStyle = "gold";
ctx.fillRect(140,140,210,210);

Démonstration

Transformations

Nous ne parlerons pas d'animations ici mais de la transformation basique du contexte. Vous aurez remarqué que j'ai apporté la précision "du contexte" car il est important de souligner que ce n'est pas juste un tracé ou une forme que vous allez déformer mais bien l'ensemble du canvas et ses coordonénes. C'est irréverssible : si aucun état n'a été préalablement sauvegardé avec la méthode save(), il ne sera pas possible de restaurer le fonctionnement initial avec restore(). Le jonglage entre ces états mémorisés dans une pile (de type FILO - First In Last Out) est assez complexe lorsqu'on débute.

Voici les transformations envisageables :

  • Changer l'échelle du contexte avec scale( x , y ),
  • Appliquer une rotation avec rotate( angle ),
  • Le déplacer avec translate( x , y ),
  • Appliquer une transformation transform( [matrice] ),
  • ou avec setTransform([matrice])
Démonstration avec rotation

Cet extrait de code fait appel au chargement d'image externe (voir partie précédente) tout en appliquant des rotations successives (valeur 0.35) avant de dessiner à nouveau la même image.

var img = new Image();
img.src = "img/pepins.png";
img.onload= function(){
	ctx.drawImage(img,150,15);
	ctx.rotate(0.35);
	ctx.drawImage(img,150,15);
	ctx.rotate(0.35);
	ctx.drawImage(img,150,15);
	ctx.rotate(0.35);
	ctx.drawImage(img,150,15);
}

Canvas rotation

Démonstration

Démonstration avec translation

Cet extrait de code fait appel au chargement d'image externe (voir partie précédente) et applique une une première translation vers la droite de 150 pixels, puis une deuxième translation vers le basde 200 pixels.

var img = new Image();
img.src = "img/pepins.png";
img.onload= function(){
	ctx.drawImage(img,0,0);
	ctx.translate(150,0);
	ctx.drawImage(img,0,0);
	ctx.translate(0,200);
	ctx.drawImage(img,0,0);
}

Canvas translation

Démonstration

Commentaires

Didodu258 a dit le

Très bon tutoriel.
J'ai une remarque pour ceux qui voudrait essayer le programme de la section "Retouche des pixels" dans le chapitre "Jouer avec les Pixels".

Il semblerait que la plupart des navigateurs modernes n'exécutent pas la ligne contenant le getImageData pour des mesures de sécurité (quelques informations disponibles ici : goo.gl/p64w8 mais ça reste encore flou pour moi).

J'ai trouvé une solution sur le site stackoverflow.com pour ceux qui n'aurait pas d'hébergement et qui désirerait quand même utiliser ce code : il faut exécuter le script dans un serveur local (localhost). Personnellement j'ai utilisé wampserver et ça fonctionne parfaitement.

À part faire comme ça je n'ai pas trouvé d'autres solutions, si quelqu'un pouvait en dire plus...
(et si on pouvait ne pas supprimer mon commentaire...)

dew a dit le

C'est en effet une restriction de sécurité : il faut utiliser les ressources du domaine qui héberge déjà la page (afin de ne pas extraire les informations d'un domaine tiers). Donc localhost peut fonctionner pour les tests (plutôt qu'une adresse IP, ou un accès via file:// qui ne permet pas d'appliquer une règle de sécurité propre à un domaine).