Accueil

Traduction

Tutoriel Canvas - sommaire

Tutoriel Canvas - recherche

L'auteur : Patrick Darcheville

Vous pouvez me contacter via Facebook pour questions & suggestions : Page Facebook relative à mon site

Canvas : le constructeur Path2D

À l'origine dessiner des polygones complexes via Canvas c'était "galère" ; le script était long avec de multiples lineTo().
Cette période est révolue à condition que votre navigateur ait implémenté le constructeur Path2D().
Grâce à cette fonction, il suffit de définir un modèle d'objet (position et dimensions) et de lui affecter un nom.
Ensuite vous pouvez dupliquer N fois ce modèle mais avec des styles différents.
Autre bonne nouvelle : cette méthode peut avoir comme argument un chemin selon la notation SVG (chemin exprimé en absolu ou en relatif).

Pour résumer une forme complexe pourra être définie en tant qu'objet graphique en une seule instruction.
Cet objet pourra être appelé N fois avec des contextes différents.

Premier exemple avec le constructeur Path2D()

Le premier canevas de la page

Le code JS

L'élément canvas définit un repère de 600 par 400 ; l'attribut ID est absent ; une règle de style en ligne pour que le canevas soit 'responsive'.

function f1()
{
	var canevas = document.querySelector('canvas'); 
	var contexte = canevas.getContext('2d');
	X = canevas.width ;
	Y = canevas.height;
	contexte.lineWidth = 3; 
	// créer un premier objet graphique : un rectangle
	var rectangle1 = new Path2D();
	rectangle1.rect(0,0,100,100);
	
	// créer un deuxième objet graphique : un cercle
	var cercle1 = new Path2D();
	cercle1.arc(100,100, 50, 0, 2 * Math.PI);

	// dessiner ces objets en noir (couleur par défaut)
	contexte.fill(rectangle1);
	contexte.fill(cercle1);

	//dessiner ces objets en rouge après translation 
	contexte.translate(X/3,0); 
	contexte.fillStyle ="red"; 
	contexte.fill(rectangle1);
	contexte.fill(cercle1);

	// dessiner ces objets en contour violet après translation
	contexte.translate(0,Y/3); 
	contexte.strokeStyle ="purple"; 
	contexte.stroke(rectangle1);
	contexte.stroke(cercle1);

	// remplir ces formes en orange après translation
	contexte.translate(-X/3,0); 
	contexte.fillStyle ="orange"; 
	contexte.fill(rectangle1);
	contexte.fill(cercle1);
}
f1(); // appel fonction

Formes définies avec la syntaxe SVG

Comme je le disais en introduction de ce chapitre, le construction Path2D autorise la notation SVG des chemins.
Donc là où il aurait fallu une instruction lineTo() plusieurs instructions moveTo() il n'y aura plus qu'une instruction Path2D(chemin exprimé avec la notation SVG).

Le deuxième canevas de la page

Dans le deuxième canevas ci-dessus il y a quatre formes colorées en noir.
Survolez le canevas : les formes deviennent vertes.
Cliquer dans le canevas : les formes deviennent oranges.
Double-cliquez dans le canevas : les formes deviennent bleues.
Déplacer le curseur en dehors du canevas : les formes deviennent noires
Enfoncez une touche du clavier : les formes deviennent violet
Relachez la touche : les formes deviennent invisibles ...

La fonction JS

La balise canvas définit un repère de 400 par 400 ; l'attribut ID est absent ; une règle de style en ligne pour que la 'toile' soit 'responsive'.

function f2()
{
	var canevas = document.querySelectorAll('canvas')[1]; 
	// sélection deuxième canevas
	var contexte = canevas.getContext('2d');
	X = canevas.width ; 	
	Y = canevas.height;
	
	// premier objet 
	var triangle = new Path2D('M10 10 L200 100 L200 200 Z');
	contexte.fill(triangle);
	
	// deuxième objet
	var rectangle = new Path2D( "M250 150 H400 V200 H250 Z");
	contexte.fill(rectangle);
	
	// troisième objet 
	var toit_usine = new Path2D('M10 250 l20 -20 l20 20 l20 -20 l20 
		20 l 20 -20 l 20 20 l 20 -20 l20 20');
	contexte.stroke(toit_usine);
	
	// quatrième objet
	var carre = new Path2D('M10 300 h 80 v 80 h -80 z');
	contexte.fill(carre);
	
	// changements de couleurs en fonction de différents évènements.
	canevas.onmouseenter = function()
		{ 
			contexte.fillStyle ="green";
			contexte.strokeStyle ="green";
			contexte.clearRect(0,0,X,Y);
			contexte.fill(triangle);
			contexte.fill(rectangle);
			contexte.stroke(toit_usine);
			contexte.fill(carre);
		} 
	canevas.onclick = function()
		{ 
			contexte.fillStyle ="orange";
			contexte.strokeStyle ="orange";
			contexte.clearRect(0,0,X,Y);
			...
		} 
	canevas.ondblclick = function()
		{ 
			contexte.fillStyle ="blue";
			contexte.strokeStyle ="blue";
			...
		} 
	canevas.onmouseleave = function()
		{ 
			contexte.fillStyle ="black";
			...
		} 
	document.onkeydown = function()
		{ 
			...
		}
	document.onkeyup = function()
		{ 
			contexte.fillStyle ="white";
			contexte.strokeStyle ="white"; 
			...
		}
}
f2();	// appel de f2

Analyse de cette fonction

Chaque objet est défini avec une seule instruction via le constructeur Path2D().
Les deux premiers chemins sont notés en absolu (les lettres L,H,V sont en majuscules).
Les deux derniers chemins sont notés en relatif (les lettres l,h,v sont en minuscules).
Si vous ne comprenez pas la syntaxe relative à la notation des chemins en SVG, suivez le lien : La balise PATH de SVG

Concernant les différentes fonctions anonymes il est conseillé d'insérer dans chacune d'elles l'instruction clearRect() avant de redessiner les objets.

Restrictions

Dans la notation d'un trajet selon la syntaxe SVG, les abscisses et ordonnées ne peuvent pas être des variables !

Pourquoi utiliser le constructeur Path2D et la notation SVG des chemins ?

Je vous montre maintenant que dans certains cas, le recours au constructeur Path2D() avec la notation SVG du chemin est incontournable.
Thématique : pour commémorer l'appel du 18 juin, nous devons réaliser une belle croix de Lorraine ombrée (ombre portée vers le coin supérieur gauche).

Mauvaise solution

Une croix de Lorraine dessinée avec trois rectangles qui se croisent.

Ci-dessous le rendu

C'est très moche car chaque rectangle est ombré ; ce n'est pas du tout le rendu espéré.

Bonne solution

Il faut créer une seule forme sous forme d'un chemin SVG.

Le rendu

Le code correspondant

Le chemin est noté en relatif en indiquant la longueur des droites horizontales ou verticales.
Pour définir ce chemin je me suis aidé d'un croquis réalisé sur une feuille "petits carreaux" avec l'échelle : 10 carreaux pour 100 pixels.

Travaux pratiques

Atelier 1

Réaliser une superbe ballustrade.

La balise canvas définit un repère de 900 par 300 ; l'attribut ID est absent ; une règle de style en ligne rend le canevas 'responsive'.

function f3()
{

	var canevas = document.querySelectorAll('canvas')[2]; 
	...
	var colonne = new Path2D("M 0,20 h120 v30 h-20 c-30,60 50,140 0,200 h20 v40 h-120 
		v-40 h20 c-50,-60 30,-140 0,-200 h-20 v-30 z");

	contexte3.fillStyle = ...

	for (i=0; i<=7; i++)
	{
	... 		// dessin d'une colonne
	...			 // déplacement de 120px sur l'axe X
	} // fin for 
...
} // fin fonction f3
...

Le canevas fait 900 par 300 avec un background "azur".
Une colonne fait 120 de large. Le chemin est complexe : des courbes de Bézier.
Pour dessiner la balustrade il faut dupliquer 8 fois l'objet "colonne" avec translation.

Atelier 2

Dessinez trois croix de Lorraine décalées et de couleurs différentes.

La balise canvas définit un repère de 900 par 300 ; une règle de style définit un fond bleu ciel.

Extrait du code :

function f4()
{
	...
	var croix = new Path2D('M170,50 h60 v50 h60 v60 h-60 v90 h110 v60 
	h-110 v90 h-60 v-90 h-110 v-60 h110 v-90 h-60 v-60 h60 v-50 z'); 
	...
	contexte.fillStyle ="blue"; 
	contexte.fill(croix);
	contexte.translate(50,-10); 
	contexte.fillStyle ="white"; 
	...
	
}
...

Un chemin SVG comprend l'origine de la forme. Donc si vous voulez redessiner l''objet à un autre emplacement, il faut procéder à une translation.