Révision 135908 sur Dessiner avec Canvas

  • Raccourci de la révision : Dessiner_avec_canvas
  • Titre de la révision : Dessiner avec canvas
  • ID de la révision : 135908
  • Créé :
  • Créateur : Chbok
  • Version actuelle ? Non
  • Commentaire /* Voir aussi */ Modif du lien vers raycaster pour correspondre aux autres pages
Étiquettes : 

Contenu de la révision

Introduction

Depuis Firefox 1.5, Firefox comprend un nouvel élément HTML servant à dessiner programmatiquement. L'élément <canvas> est basé sur la spécification canvas du WhatWG, elle-même basée sur la balise <canvas> d'Apple implémentée dans Safari. Celui-ci peut être utilisé pour afficher des graphes, des élements d'interface, et d'autres éléments graphiques personnalisés sur le client.

<canvas> crée une surface de dessin de taille fixe, ou canevas, exposant un ou plusieurs contextes de rendu. Nous nous concentrerons sur le contexte de rendu 2D (c'est d'ailleurs le seul contexte de rendu actuellement défini). Dans le futur, d'autres contextes peuvent fournir différents types de rendu. Par exemple, il est probable qu'un contexte 3D basé sur OpenGL ES sera ajouté à la spécification <canvas>.

Le contexte de rendu 2D

Un exemple simple

Pour commencer, voici un exemple simple qui dessine deux rectangles ayant une intersection, l'un d'entre-eux possédant une transparence alpha :

Exemple 1.

<html>
 <head>
  <script type="application/x-javascript">
function draw() {
 var canvas = document.getElementById("canvas");
 var ctx = canvas.getContext("2d");

 ctx.fillStyle = "rgb(200,0,0)";
 ctx.fillRect (10, 10, 50, 50);

 ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
 ctx.fillRect (30, 30, 50, 50);
}
  </script>
 </head>
 <body onload="draw()">
   <canvas id="canvas" width="300" height="300"></canvas>
 </body>
</html>

La fonction draw récupère l'élément canvas, et ensuite son contexte 2d. L'objet ctx peut ensuite être utilisé pour dessiner réellement vers le canevas. L'exemple remplit simplement les deux rectangles, en positionnant fillStyle à deux couleurs différentes à l'aide des spécifications de couleur CSS et d'un appel à fillRect. Le second appel à fillStyle utilise rgba() pour spécifier une valeur alpha parmi les informations de couleur.

Les appels à fillRect, strokeRect et clearRect affichent un rectangle plein, surligné ou vide. Pour afficher des formes plus complexes, on utilise des chemins.

Utilisation de chemins

La fonction beginPath commence un nouveau chemin, et moveTo, lineTo, arcTo, arc et des méthodes similaires sont utilisées pour ajouter des segments au chemin. Le chemin peut être fermé à l'aide de closePath. Une fois que le chemin est créé, vous pouvez utiliser fill ou stroke pour afficher celui-ci sur le canevas.

Exemple 2.

<html>
 <head>
  <script type="application/x-javascript">
function draw() {
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  ctx.fillStyle = "red";

  ctx.beginPath();
  ctx.moveTo(30, 30);
  ctx.lineTo(150, 150);
  ctx.quadraticCurveTo(60, 70, 70, 150);
  ctx.lineTo(30, 30);
  ctx.fill();
}
   </script>
 </head>
 <body onload="draw()">
   <canvas id="canvas" width="300" height="300"></canvas>
 </body>
</html>

L'appel à fill() ou stroke() provoque l'utilisation du chemin. Pour être rempli ou dessiné à nouveau, le chemin devra être recréé.

État graphique

Les attributs du contexte comme fillStyle, strokeStyle, lineWidth et lineJoin font partie de l'état graphique courant. Le contexte fournit deux méthodes, save() et restore(), qui peuvent être utilisées pour déplacer l'état courant vers et depuis la pile d'états.

Un exemple plus compliqué

Voici un exemple un petit peu plus compliqué, qui utilise des chemins, des états et introduit également la matrice de transformation courante. Les méthodes du contexte translate(), scale() et rotate() transforment toutes la matrice courante. Tous les points affichés sont au préalable transformés par cette matrice.

Exemple 3.

 <html>
  <head>
   <script type="application/x-javascript">
 function dessineNoeudPap(ctx, fillStyle) {
 
   ctx.fillStyle = "rgba(200,200,200,0.3)";
   ctx.fillRect(-30, -30, 60, 60);
 
   ctx.fillStyle = fillStyle;
   ctx.globalAlpha = 1.0;
   ctx.beginPath();
   ctx.moveTo(25, 25);
   ctx.lineTo(-25, -25);
   ctx.lineTo(25, -25);
   ctx.lineTo(-25, 25);
   ctx.closePath();
   ctx.fill();
 }
 
 function point(ctx) {
   ctx.save();
   ctx.fillStyle = "black";
   ctx.fillRect(-2, -2, 4, 4);
   ctx.restore();
 }
 
 function dessine() {
   var canvas = document.getElementById("canvas");
   var ctx = canvas.getContext("2d");

   // notez que toutes les autres translations sont relatives à
   // celle-ci
   ctx.translate(45, 45);

   ctx.save();
   //ctx.translate(0, 0); // non nécessaire
   dessineNoeudPap(ctx, "red");
   point(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(85, 0);
   ctx.rotate(45 * Math.PI / 180);
   dessineNoeudPap(ctx, "green");
   point(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(0, 85);
   ctx.rotate(135 * Math.PI / 180);
   dessineNoeudPap(ctx, "blue");
   point(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(85, 85);
   ctx.rotate(90 * Math.PI / 180);
   dessineNoeudPap(ctx, "yellow");
   point(ctx);
   ctx.restore();
 }
    </script>
  </head>
  <body onload="dessine()">
    <canvas id="canvas" width="300" height="300"></canvas>
  </body>
 </html>

Ceci définit deux méthodes dessineNoeudPap et point, qui sont appelées 4 fois. Avant chaque appel, translate() et rotate() sont utilisées pour définir la matrice de transformation courante, qui à son tour positionne le point et le nœud papillon. point affiche un petit carré noir centré sur (0, 0). Ce point est déplacé par la matrice de transformation. dessineNoeudPap affiche un chemin simple en forme de nœud papillon en utilisant le style de remplissage fourni en paramètre.

Comme les opérations de matrices sont cumulatives, save() et restore() sont utilisées autour de chaque jeu d'appels afin de restaurer l'état initial du canevas. Une chose à surveiller est que la rotation se passe toujours autour de l'origine courante ; donc une séquence translate() rotate() translate() donnera des résultats différents d'une série d'appels translate() translate() rotate().

Compatibilité avec le <canvas> d'Apple

Pour la plus grande partie, le <canvas> de Mozilla est compatible avec celui d'Apple et d'autres implémentations. Il convient cependant d'être averti de quelques problèmes, décrits ci-dessous.

Balise </canvas> requise

Dans l'implémentation d'Apple Safari, <canvas> est un élément fortement semblable à l'élément <img> ; il ne doit pas forcément avoir de balise de fermeture. Cependant, pour que <canvas> puisse être utilisé à grande échelle sur le Web, il est important de pouvoir fournir facilement du contenu alternatif. C'est pourquoi l'implémentation de Mozilla a une balise de fin requise.

Si aucun contenu alternatif n'est nécessaire, un simple <canvas id="foo" ...></canvas> sera entièrement compatible avec Safari et Mozilla -- Safari ignorera simplement la balise de fermeture.

Si un contenu alternatif est désiré, certaines astuces CSS doivent être utilisées pour masquer le contenu alternatif à Safari (qui doit seulement afficher le canevas), et masquer ces mêmes astuces à Internet Explorer (qui doit afficher le contenu alternatif). À faire : les commandes CSS exactes doivent être fournies par hixie

Fonctionnalités supplémentaires

Affichage de contenu Web dans un canevas

L'élément canvas de Mozilla a été étendu avec la méthode drawWindow. Celle-ci dessine une capture du contenu d'un élément DOM window dans le canevas. Par exemple,

ctx.drawWindow(window, 0, 0, 100, 200, "rgb(0,0,0)");

affichera le contenu de la fenêtre courante dans le rectangle (0,0,100,200) défini en pixels relatifs au coin en haut à gauche de la fenêtre d'affichage, sur un fond noir, dans le canevas. En spécifiant "rgba(0,0,0,0)" comme couleur, le contenu sera dessiné avec un fond transparent (ce qui sera plus lent).

Avec cette méthode, il est possible de remplir un IFRAME caché avec du contenu arbitraire (par exemple, du texte HTML stylé avec CSS, ou du SVG) et de le dessiner dans un canevas. Celui-ci sera redimensionné, rotationné etc. suivant la transformation courante.

L'extension tab preview de Ted Mielczarek's utilise cette technique dans le chrome pour fournir des miniatures de pages Web, et sa source est disponible pour référence.

Voir aussi

{{ wiki.languages( { "en": "en/Drawing_Graphics_with_Canvas", "ja": "ja/Drawing_Graphics_with_Canvas" } ) }}

Source de la révision

<h3 name="Introduction"> Introduction </h3>
<p>Depuis <a href="fr/Firefox_1.5_pour_les_d%c3%a9veloppeurs">Firefox 1.5</a>, Firefox comprend un nouvel élément HTML servant à dessiner programmatiquement. L'élément <code>&lt;canvas&gt;</code> est basé sur la 
<a class="external" href="http://www.whatwg.org/specs/web-apps/current-work/#graphics">spécification canvas du WhatWG</a>, elle-même basée sur la balise <code>&lt;canvas&gt;</code> d'Apple implémentée dans
Safari. Celui-ci peut être utilisé pour afficher des graphes, des élements d'interface, et d'autres éléments graphiques personnalisés sur le client.
</p><p><code>&lt;canvas&gt;</code> crée une surface de dessin de taille fixe, ou <i>canevas</i>, exposant un ou plusieurs <i>contextes de rendu</i>.  Nous nous concentrerons sur le contexte de rendu 2D  (c'est d'ailleurs le seul contexte de rendu actuellement défini).
Dans le futur, d'autres contextes peuvent fournir différents types de rendu. Par exemple, il est probable qu'un contexte 3D basé sur OpenGL ES sera ajouté à la spécification <code>&lt;canvas&gt;</code>.
</p>
<h3 name="Le_contexte_de_rendu_2D"> Le contexte de rendu 2D </h3>
<h4 name="Un_exemple_simple"> Un exemple simple </h4>
<p>Pour commencer, voici un exemple simple qui dessine deux rectangles ayant une intersection, l'un d'entre-eux possédant une transparence alpha :
</p><p><img align="right" alt="Exemple 1." src="File:fr/Media_Gallery/Canvas_ex1.png">
</p>
<pre class="eval">&lt;html&gt;
 &lt;head&gt;
  &lt;script type="application/x-javascript"&gt;
function draw() {
 var canvas = document.getElementById("canvas");
 var ctx = canvas.getContext("2d");

 ctx.fillStyle = "rgb(200,0,0)";
 ctx.fillRect (10, 10, 50, 50);

 ctx.fillStyle = "rgba(0, 0, 200, 0.5)";
 ctx.fillRect (30, 30, 50, 50);
}
  &lt;/script&gt;
 &lt;/head&gt;
 &lt;body onload="draw()"&gt;
   &lt;canvas id="canvas" width="300" height="300"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>La fonction <code>draw</code> récupère l'élément <code>canvas</code>, et ensuite son contexte <code>2d</code>. L'objet <code>ctx</code> peut ensuite être utilisé pour dessiner réellement vers le canevas. L'exemple remplit simplement les deux rectangles, en positionnant <code>fillStyle</code> à deux couleurs différentes à l'aide des spécifications de couleur CSS et d'un appel à <code>fillRect</code>. Le second appel à <code>fillStyle</code> utilise <code>rgba()</code> pour spécifier une valeur alpha parmi les informations de couleur.
</p><p>Les appels à <code>fillRect</code>, <code>strokeRect</code> et <code>clearRect</code> affichent un rectangle plein, surligné ou vide. Pour afficher des formes plus complexes, on utilise des chemins.
</p>
<h4 name="Utilisation_de_chemins"> Utilisation de chemins </h4>
<p>La fonction <code>beginPath</code> commence un nouveau chemin, et
<code>moveTo</code>, <code>lineTo</code>, <code>arcTo</code>, <code>arc</code> et des méthodes similaires sont utilisées pour ajouter des segments au chemin. Le chemin peut être fermé à l'aide de <code>closePath</code>. Une fois que le chemin est créé, vous pouvez utiliser <code>fill</code> ou <code>stroke</code> pour afficher celui-ci sur le canevas.
</p><p><img align="right" alt="Exemple 2." src="File:fr/Media_Gallery/Canvas_ex2.png">
</p>
<pre class="eval">&lt;html&gt;
 &lt;head&gt;
  &lt;script type="application/x-javascript"&gt;
function draw() {
  var canvas = document.getElementById("canvas");
  var ctx = canvas.getContext("2d");

  ctx.fillStyle = "red";

  ctx.beginPath();
  ctx.moveTo(30, 30);
  ctx.lineTo(150, 150);
  ctx.quadraticCurveTo(60, 70, 70, 150);
  ctx.lineTo(30, 30);
  ctx.fill();
}
   &lt;/script&gt;
 &lt;/head&gt;
 &lt;body onload="draw()"&gt;
   &lt;canvas id="canvas" width="300" height="300"&gt;&lt;/canvas&gt;
 &lt;/body&gt;
&lt;/html&gt;
</pre>
<p>L'appel à <code>fill()</code> ou <code>stroke()</code> provoque l'utilisation du chemin. Pour être rempli ou dessiné à nouveau, le chemin devra être recréé.
</p>
<h4 name=".C3.89tat_graphique"> État graphique </h4>
<p>Les attributs du contexte comme <code>fillStyle</code>,
<code>strokeStyle</code>, <code>lineWidth</code> et <code>lineJoin</code> font partie de l'<i>état graphique</i> courant. Le contexte fournit deux méthodes, <code>save()</code> et <code>restore()</code>, qui peuvent être utilisées pour déplacer l'état courant vers et depuis la pile d'états.
</p>
<h4 name="Un_exemple_plus_compliqu.C3.A9"> Un exemple plus compliqué </h4>
<p>Voici un exemple un petit peu plus compliqué, qui utilise des chemins, des états et introduit également la matrice de transformation courante. Les méthodes du contexte <code>translate()</code>, <code>scale()</code> et <code>rotate()</code> transforment toutes la matrice courante. Tous les points affichés sont au préalable transformés par cette matrice.
</p><p><img align="right" alt="Exemple 3." src="File:fr/Media_Gallery/Canvas_ex3.png">
</p>
<pre> &lt;html&gt;
  &lt;head&gt;
   &lt;script type="application/x-javascript"&gt;
 function dessineNoeudPap(ctx, fillStyle) {
 
   ctx.fillStyle = "rgba(200,200,200,0.3)";
   ctx.fillRect(-30, -30, 60, 60);
 
   ctx.fillStyle = fillStyle;
   ctx.globalAlpha = 1.0;
   ctx.beginPath();
   ctx.moveTo(25, 25);
   ctx.lineTo(-25, -25);
   ctx.lineTo(25, -25);
   ctx.lineTo(-25, 25);
   ctx.closePath();
   ctx.fill();
 }
 
 function point(ctx) {
   ctx.save();
   ctx.fillStyle = "black";
   ctx.fillRect(-2, -2, 4, 4);
   ctx.restore();
 }
 
 function dessine() {
   var canvas = document.getElementById("canvas");
   var ctx = canvas.getContext("2d");

   // notez que toutes les autres translations sont relatives à
   // celle-ci
   ctx.translate(45, 45);

   ctx.save();
   //ctx.translate(0, 0); // non nécessaire
   dessineNoeudPap(ctx, "red");
   point(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(85, 0);
   ctx.rotate(45 * Math.PI / 180);
   dessineNoeudPap(ctx, "green");
   point(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(0, 85);
   ctx.rotate(135 * Math.PI / 180);
   dessineNoeudPap(ctx, "blue");
   point(ctx);
   ctx.restore();
 
   ctx.save();
   ctx.translate(85, 85);
   ctx.rotate(90 * Math.PI / 180);
   dessineNoeudPap(ctx, "yellow");
   point(ctx);
   ctx.restore();
 }
    &lt;/script&gt;
  &lt;/head&gt;
  &lt;body onload="dessine()"&gt;
    &lt;canvas id="canvas" width="300" height="300"&gt;&lt;/canvas&gt;
  &lt;/body&gt;
 &lt;/html&gt;
</pre>
<p>Ceci définit deux méthodes <code>dessineNoeudPap</code> et <code>point</code>, qui sont appelées 4 fois. Avant chaque appel, <code>translate()</code> et
<code>rotate()</code> sont utilisées pour définir la matrice de transformation courante, qui à son tour positionne le point et le nœud papillon. <code>point</code>
affiche un petit carré noir centré sur <code>(0, 0)</code>. Ce point est déplacé par la matrice de transformation. <code>dessineNoeudPap</code> affiche un chemin simple en forme de nœud papillon en utilisant le style de remplissage fourni en paramètre.
</p><p>Comme les opérations de matrices sont cumulatives, <code>save()</code> et
<code>restore()</code> sont utilisées autour de chaque jeu d'appels afin de restaurer l'état initial du canevas. Une chose à surveiller est que la rotation se passe toujours autour de l'origine courante ; donc une séquence <code>translate()
rotate() translate()</code> donnera des résultats différents d'une série d'appels
<code>translate() translate() rotate()</code>.
</p>
<h3 name="Compatibilit.C3.A9_avec_le_.3Ccanvas.3E_d.27Apple"> Compatibilité avec le &lt;canvas&gt; d'Apple </h3>
<p>Pour la plus grande partie, le <code>&lt;canvas&gt;</code> de Mozilla est compatible avec celui d'Apple et d'autres implémentations. Il convient cependant d'être averti de quelques problèmes, décrits ci-dessous.
</p>
<h4 name="Balise_.3C.2Fcanvas.3E_requise"> Balise <code>&lt;/canvas&gt;</code> requise </h4>
<p>Dans l'implémentation d'Apple Safari, <code>&lt;canvas&gt;</code> est un élément fortement semblable à l'élément <code>&lt;img&gt;</code> ; il ne doit pas forcément avoir de balise de fermeture. Cependant, pour que <code>&lt;canvas&gt;</code> puisse être utilisé à grande échelle sur le Web, il est important de pouvoir fournir facilement du contenu alternatif. C'est pourquoi l'implémentation de Mozilla a une balise de fin <i>requise</i>.
</p><p>Si aucun contenu alternatif n'est nécessaire, un simple <code>&lt;canvas id="foo" ...&gt;&lt;/canvas&gt;</code> sera entièrement compatible avec Safari et Mozilla -- Safari ignorera simplement la balise de fermeture.
</p><p>Si un contenu alternatif est désiré, certaines astuces CSS doivent être utilisées pour masquer le contenu alternatif à Safari (qui doit seulement afficher le canevas), et masquer ces mêmes astuces à Internet Explorer (qui doit afficher le contenu alternatif).  <b>À faire : les commandes CSS exactes doivent être fournies par hixie</b>
</p>
<h3 name="Fonctionnalit.C3.A9s_suppl.C3.A9mentaires"> Fonctionnalités supplémentaires </h3>
<h4 name="Affichage_de_contenu_Web_dans_un_canevas"> Affichage de contenu Web dans un canevas </h4>
<p>L'élément <code>canvas</code> de Mozilla a été étendu avec la méthode <code>drawWindow</code>. Celle-ci dessine une capture du contenu d'un élément DOM <code>window</code> dans le canevas. Par exemple,
</p>
<pre class="eval">ctx.drawWindow(window, 0, 0, 100, 200, "rgb(0,0,0)");
</pre>
<p>affichera le contenu de la fenêtre courante dans le rectangle (0,0,100,200) défini en pixels relatifs au coin en haut à gauche de la fenêtre d'affichage, sur un fond noir, dans le canevas. En spécifiant "rgba(0,0,0,0)" comme couleur, le contenu sera dessiné avec un fond transparent (ce qui sera plus lent).
</p><p>Avec cette méthode, il est possible de remplir un IFRAME caché avec du contenu arbitraire (par exemple, du texte HTML stylé avec CSS, ou du SVG) et de le dessiner dans un canevas.  Celui-ci sera redimensionné, rotationné etc. suivant la transformation courante.
</p><p>L'extension <a class="external" href="http://ted.mielczarek.org/code/mozilla/tabpreview/">tab preview</a> de Ted Mielczarek's  utilise cette technique dans le chrome pour fournir des miniatures de pages Web, et sa source est disponible pour référence.
</p>
<h3 name="Voir_aussi"> Voir aussi </h3>
<ul><li> <a href="fr/Tutoriel_canvas">Tutoriel canvas</a>
</li><li> <a href="fr/Un_raycaster_basique_avec_canvas">Un raycaster basique avec canvas</a>
</li><li> <a class="external" href="http://developer.apple.com/documentation/AppleApplications/Reference/SafariJSRef/Classes/Canvas.html">La documentation d'Apple sur Canvas</a>
</li><li> <a class="external" href="http://weblogs.mozillazine.org/roc/archives/2005/05/rendering_web_p.html">Affichage de miniatures de pages Web</a>
</li><li> <a class="external" href="http://awordlike.com/">The Lightweight Visual Thesaurus</a>
</li></ul>
<ul><li> <a href="Special:Tags?tag=HTML:Canvas&amp;language=fr">Et plus...</a>
</li></ul>
{{ wiki.languages( { "en": "en/Drawing_Graphics_with_Canvas", "ja": "ja/Drawing_Graphics_with_Canvas" } ) }}
Revenir à cette révision