.


titre.gif (1044 octets)

table des matières

 

adaptation d'un travail de maturité  fait par N. S. 2M8

Sous la supervision du professeur J. L.

 

Partie I: Les bases du dessin avec Canvas
I-1Accéder à Canvas

I.2 Les formes
  • I.2.1 Système de coordonnées
  • I.2.2 Première forme  .fillRect()
  • I.2.3 Formes vides     strokRect()
  • I.2.4 Méthode différente pour afficher un rectangle   .fill(), stroke()
  • I.2.5 Importance de l'ordre
  • I.2.6 Nettoyer une zone du dessin   clearRect()

I.3Les couleurs et techniques pour remplir le fond   
  • I.3.1 Les quatre façons de définir une couleur rgba (rouge, vert, bleu, alpha); "#RRVVBB"; "sonnom";  hsl (dégradé, saturation, luminosité)
  • I.3.2 Les dégradés  createLinearGradient(positionXdépart, positionYdépart, positionXarrivée, positionYarrivée)
  • I.3.3 Les images  drawImage(image, posX, posY)
  • I.3.4 Création de motifs   createPattern(image, répétition)

I.4 Les traits
  • I.4.1 Nos premiers traits moveTo( x, y) ; lineTo( x, y) ; closePath() 
  • I.4.2 Le design des traits  lineCap = "round / butt / quare"; .lineJoin="bevel / round / miter ";
  • I.4.3 Les cercles et les arcs   arc(posX, posY, rayon, angleDeDépart, angleDeFin, sens); arcTo(P1x, P1y, P2x, P2y, rayon);
  • I.4.4 De la droite à la courbe  bezierCurveTo( p1x, p1y,  p2x, p2y, p3x, p3y); quadraticCurveTo( p1x, p1y, p2x, p2y)

I.5 Le texte
    • I.5.1Écrire avec Canvas
    •       fillText("texte", posX, posY); strokeText("texte", posX, posY)
  •  

    Partie II: Les techniques avancées

    II.1 Nouvelles techniques de dessin
    • II.1.1 Les ombres  shadowOffsetX=... ; shadowOffsetY=.....;  shadowBlur=...; shadowColor=....
    • II.1.2 Spécifier une zone de dessins  clip();
    • II.1.3 La composition des dessins    globalCompositeOperation = ...
    • II.1.4 Connaître la position d'un point par rapport à un tracé     isPointInPath(posX, posY)
    II.2 Dessinez via la souris
    • II.2.1 Récupérer la position du curseur : onmousemove =  fonction(event)
    • II.2.2 Un cercle pour un clic onclick=  fonction(event)
    II.3 Modification des pixels
    • II.3.1 Récupération des pixels    createImageDate( x, y);   getImageData( x, y, width, height);
    • II.3.2 Application de filtre sur une image
    II.4 Les traits
    • II.4.1 Sauvegarder et restaurer notre contexte  save(),  restore().
    • II.4.2 Les transformations basiques   rotate (angle)   translate( x, y)  scale( x, y)
    • II.4.3 Les transformations matricielles     transform ( a, b, c , d, e, f);        setTransform( a, b, c, d, e, f);
    II.5 Les animations
    • II.5.1 Théorie sur les animations, récupération du temps   setTimeout();     setInterval()
    • II.5.2 Une balle rebondissante
    • II.5.3 Des courbes aléatoires
    • II.5.4 Un système solaire

    Partie III: Applications de Canvas

    III.1Réalisation d'une horloge
    • III.1.1 Variables et cadran  date();
    • III.1.2 Le mouvement des aiguilles

    III.2 Analyses de fonctions et graphiques
    • III.2.1 Dessin des axes et mise en place de l'interface
    • III.2.2 Dessin d'une courbe
    Annexe
    • A.1 Aller plus loin avec Canvas
    • A.2 Mémo des fonctions acquis

    Il est important de noter, qu'à la base ce cours a été créé dans le cadre d'un travail de maturité réaliser au gymnase Auguste Piccard. La version présentée est différente du contenu original, cette version à été modifiée pour les besoins actuels

     

     

    Partie I:Les bases du dessin avec Canvas

    Mise en place de Canvas

    Qu'est ce que Canvas ?

    Pour rentrer directement en matière, sachez que Canvas est en fait une balise HTML. Son rôle en tant que balise va être de créer un cadre dans lequel nous allons pouvoir dessiner. D'ailleurs, "canvas" en français signifie "toile". Cela donne déjà une bonne idée de ce que nous allons pouvoir faire avec. C'est à ce moment que le Javascript entre en jeu, son rôle va être de dessiner dans ce cadre. Il faut donc mettre en place la balise en HTML et ensuite avec le Javascript nous allons dessiner à l'intérieur.

     

    Cette balise a été créée par Apple pour être utilisée sur son navigateur, Safari. Elle est apparue en même temps que HTML5. Très vite cette balise a été implantée dans Firefox. Ensuite c'est Google Chrome et Opera qui ont réussi à l'interpréter. Finalement, dans sa dernière version, Internet Explorer a acquis cette balise. Cependant il faut faire attention avec Internet Explorer car il souffre d'un certain retard, encore aujourd'hui il ne connaît pas certaines fonctions du Javascript, voilà pourquoi il faudra y être attentifs quand vous utiliserez Canvas dans Internet Explorer.

     

    Mise en place de notre Canvas

    Vous êtes chanceux, la balise s'écrit comme son nom: <canvas>.

    Vous pouvez mettre à Canvas deux attributs, un pour la hauteur et l'autre pour la largeur. Si vous ne définissez pas sa taille, ses dimensions de base seront 300 pixels pour la largeur et 150 pour la hauteur.

    Rappel: Les attributs pour les balises sont à intégrer immédiatement après le nom de la balise et avant le >. Dans notre cas nous avons besoin de l'attribut height (hauteur) et de l'attribut width(largeur).

    Voici donc logiquement ce que vous devriez obtenir avec ces balises

    <canvas id ="cvs0" width ="100" height = "100">
    </canvas>

    Oui je sais, vous ne voyez toujours rien, cependant cette fois notre cadre est créé et il fonctionne, mais la couleur du fond de Canvas n'existe pas, voilà pourquoi il est invisible. Si vous ne croyez pas à son existence, vous pouvez définir le style du fond d'une certaine couleur via CSS.

    Comme déjà mentionné, les dessins se font via Javascript, il faut donc que nous puissions accéder à Canvas. Plusieurs techniques sont disponible, cependant durant ce cours nous allons y accéder avec son identifiant ( id pour les intimes). Je lui donne comme id : cvsn

    <canvas id ="cvs1" width ="100" height = "100">
          votre navigateur n'accepte pas Canvas
    </canvas>
    votre navigateur n'accepte pas Canvas

    note : j'ai légèrement grisé le fond de la zone pour la mettre en évidence car sinon on ne vois rien. je vous montre dans un oment comment faire pour cela.

    Je vous expliquerai plus loin comment accéder à notre Canvas avec Javascript. Mais avant il nous reste une dernière chose à mettre en place. Avec ce que je vous ai dit et ce que vous pouvez voir maintenant, vous vous rendez certainement compte qu'il manque quelque chose entre les deux balises, et vous avez tout à fait raison. Si vous mettez du code entre les deux balises, le seul moment où il sera interprété par les navigateurs, c'est si ceux-ci ne supportent pas Canvas. Voilà pourquoi il peut être utile de mettre un petit message à l'intention de ceux qui n'auraient pas une version récente de leur navigateur

    <canvas id ="cvs2" width ="100" height = "100">
          votre navigateur n'accepte pas Canvas
    </canvas>
    votre navigateur n'accepte pas Canvas

    Voilà pour ce qui est du HTML, nous en avons fini pour ce chapitre. Jusqu'à la troisième partie nous n'allons plus toucher au HTML et nous allons uniquement nous concentrer sur le dessin.

     

    I.1 Accéder à Canvas

    Il nous reste une dernière étape avant de pouvoir dessiner dans notre Canvas, il faut y accéder. Pour cela il nous faut utiliser le Javascript. Comme vous le savez déjà, on peut placer le Javascript à plusieurs endroits pour le même effet. Pour ma part, je le mets toujours juste après la balise de fermeture de Canvas.

    <canvas id ="cvs3" width ="150" height = "150">
          votre navigateur n'accepte pas Canvas
    </canvas>

    <script>
    </script>
    votre navigateur n'accepte pas Canvas

    Peut être avez vous appris à spécifier le type de script. Cependant, depuis HTML5, il n'est plus obligatoire de le faire. De plus Canvas ne fonctionne que sur HTML5, voilà pourquoi je ne précise pas le type.

    La première chose à faire est de récupérer  l'id de Canvas et de le stocker dans une variable. Je nomme ma variable cvsn(Can1). Ne vous inquiétez pas, nous n'utiliserons pas longtemps cette variable, donc il n'est pas nécessaire de la mémoriser ou de lui donner un nom spécifique.

    Rappel: Pour accéder à un élément HTML avec le Javascript depuis un id, il faut utiliser la fonction: document.getElementById('Id_De_Mon_Canvas')dans mon cas je remplace l'id par cvsx.

    <canvas id ="cvs4" width ="150" height = "20">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv1 = document.getElementById('cvs4');
    </script>
    votre navigateur n'accepte pas Canvas

    Maintenant, voyons enfin quelque chose en rapport spécifiquement avec Canvas, c'est la notion de contexte. Le contexte sert à définir si nous travaillons en 2D ou en 3D. Actuellement, nous allons uniquement travailler en 2D. Je reviendrai plus tard dans le cours sur la question de la 3D. Le contexte sera l'élément central pour dessiner dans Canvas. Pour récupérer le contexte, il faut utiliser la méthode

    getContext('context')

    Dans notre cas nous attribuons au contexte une dimension en 2D. Elle va récupérer le contexte de notre Canvas, donc la méthode complète est:

    monElementCanvas.getContext('context').

    MonElementCanvas pour nous est stocké dans la variable can1. Il faut stocker cela dans une nouvelle variable que je nomme context1 (ConTeXt).

    <canvas id ="cvs5" width ="10" height = "150">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv1 = document.getElementById('cvs5');
         var context1 = canv1.getContext('2d');
    </script>
    votre navigateur n'accepte pas Canvas

    Ceci est le code que vous devrez toujours mettre si vous voulez utiliser Canvas. Mémorisez le bien car je ne l'écrirais pas à chaque nouvel exemple.

    Voilà, je sais que pour l'instant vous êtes un peu frustré parce que vous n'avez encore rien vu de concret. Mais nous venons de faire déjà une grande partie du travail. Maintenant nous pouvons enfin dessiner quelque chose.


    I.2 Les formes

    Voilà, la partie concrète commence enfin. Nous allons d'abord apprendre à mettre en place des formes simples, comme des rectangles ou des carrés. Je ferai une courte introduction sur les couleurs. Cependant je vous donnerai plus tard une explication plus détaillée dans la chapitre sur les couleurs.

     

    I.2.1 Système de coordonnées

    Avant de dessiner (oui je sais, vous voulez dessiner mais soyez encore un peu patient), je voudrais juste vous présenter le système de coordonnées utilisé par Canvas. Pour cela, rien de mieux qu'un dessin.


    Comme vous pouvez le voir au dessus, l'origine des points de coordonnées est en haut à gauche. C'est important de se rappeler où est positionné ce point car c'est depuis lui que nous placerons tout nos dessins. Souvenez  vous du sens des axes, car il ne faut pas inverser les deux valeurs lors de nos dessins.

     

    Ensuite, vous pouvez voir qu'on avance pixel par pixel, cela reprend ce que je disais plus haut. Avec Canvas vous pouvez vraiment travailler pixel par pixel.

     

    I.2.2 Première forme

    Nous allons enfin dessiner. Pour cette première forme nous allons rester dans quelque chose de très simple. Nous allons dessiner un rectangle. Lorsque nous dessinons un rectangle, nous devons choisir une position de départ pour le point en haut à gauche de notre rectangle. Ensuite il faut définir sa hauteur et sa largeur. Pour ce faire nous avons la fonction:

    fillRect(positionX, positionY, hauteur, largeur)

    Rect signifie que nous voulons un rectangle. Et fill signifie remplir. Maintenant il faut encore choisir une couleur pour notre rectangle. Pour cela nous allons utiliser :

    fillStyle = "couleur".

    Le nom de notre couleur est à donner en anglais. Nous avons maintenant tout les informations nécessaires pour dessiner notre première forme. Il faut toujours mettre la définitions de la couleurs avant d'effectuer le dessin car la fonction fillRect() va utiliser la couleurs qui à été défini en dernier.

    <canvas id ="cvs6" width ="150" height = "150">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv1 = document.getElementById('cvs6');
         var context1 = canv1.getContext('2d');
        context1.fillStyle =
    "green";
        context1.fillRect(
    10,30,130,90);
    </script>
          votre navigateur n'accepte pas Canvas

     Je remets une dernière fois ce qu'on a vu au chapitre précédent pour que vous vous rendiez bien compte où vont les différents éléments. Et maintenant, voilà à droite ce que vous devriez obtenir si vous avez fait tout juste. Oui, enfin quelque chose est visible. Amusez-vous à modifier les paramètres passés à la  fonction fillRect(). Les deux premiers paramètres définissent le pixel du coin supérieur gauche puis, les deux suivants, la largeur et la hauteur du rectangle.

    Comme vous le voyez aux lignes 7 et 8, les deux fonctions que nous avons vues sont a appliquer sur le contexte que nous avons défini. C'est pour cela que j'ai dit que le contexte était l'élément central de nos dessins. D'ailleurs on voit que je définis d'abord la couleur et ensuite je fais le dessin. C'est très important de toujours définir la couleur qu'on veut appliquer avant de dessiner notre objet, sinon celui-ci n'aura soit pas de couleur, soit pas la bonne couleur si plusieurs couleurs sont définies. 

    Ce n'est pas l'unique méthode pour attribuer des couleurs à nos formes, mais elles seront expliquées dans la suite du cours. Il est inutile de surcharger vos cerveaux pour l'instant. 

    I.2.3 Formes vides

    Vous avez vu qu'avant nous avons utilisé fill pour signifier que nous voulions une forme remplie, mais il est aussi possible d'obtenir des formes juste avec les contours tracés. Pour ce faire il suffit de changer fill par stroke. Le mot stroke veut dire "trait" en français. 

    Le principe est le même que pour une forme remplie, la seule chose qu'il faut rajouter est la taille du trait lineWidth = tailleEnPixel. Voici maintenant un exemple avec un rectangle de même dimensions que celui d'avant, cependant celui-ci n'est pas plein, mais il a juste un contour.

    <script>
        
    var canv1 = document.getElementById('cvs7');
         var context1 = canv1.getContext('2d');
        context1.lineWidth  = 5;
        context1.stokeStyle =
    "black";
        context1.strokRect(
    10,30,130,90);
    </script>
          votre navigateur n'accepte pas Canvas  

     

    I.2.4 Méthode différente pour afficher un rectangle

    Il existe une autre méthode pour afficher un rectangle. Au lieu de définir le remplissage ou non du rectangle dans la méthode, cela se fait après. Dans le cas présent, nous avons donc une une nouvelle méthode qui est celle-ci :      rect( posX, posY, largeur, hauteur);

    Elle ressemble beaucoup au deux précédentes, seulement le rectangle est seulement défini au niveau de sa taille, par encore de la façon dont il doit être dessiné. Il faut donc rajouter après cette méthode soit stroke() soit fill().

    <script>
        
    var canv1 = document.getElementById('cvs8');
         var context1 = canv1.getContext('2d');
        context1.lineWidth  = 2;
        context1.stokeStyle =
    "black";
        context1.fillStyle = "grey";
        context1.rect(
    10,20,60,90);
        context1.fill();
        context1.rect(80,20,60,90);
        context1.stroke();

    </script>
          votre navigateur n'accepte pas Canvas  

     Note: le stroke() est appliqué sur les 2 rectangles car il se trouve avant les deux méthodes qui créent les rectangles. Il n'est donc pas utile de le répéter.

    L'ordre dans lequel les dessins sont effectués a une grande importance, je vous montre ci-après comment pour gérer ce type de problème.

     

    I.2.5 Importance de l'ordre

    Chaque fois que vous faites un nouveau dessin, dans les cas précédents des rectangles, ils vont simplement s'ajouter les uns sur les autres. Il faut donc toujours prendre en compte. Par exemple, lorsque vous peignez, vous mettez d'abord une couche de fond. Ensuite par dessus vous allez rajouter des détails. Avec Canvas c'est la même chose. Imaginons que nous voulions le dessin ci-dessous:

        context1.lineWidth  = 5;
        context1.stokeStyle =
    "black";
        context1.fillStyle = "grey";
    // grand rectangle extérieur vide
        context1.strokeRect(
    50,50,50,80);
    // rectangle centrale plein
        context1.fillRect(60,60,30,60);
        context1.lineWidth  = 2;
    // petit rectangle intérieur vide
        context1.strokeRect(70,70,10,40);
          votre navigateur n'accepte pas Canvas  

    Alors, qu'est ce que contient ce dessin ? Il y a un premier rectangle vide, qui contient un autre rectangle qui lui est plein, au centre duquel il y a un troisième rectangle qui lui aussi est vide. Comme vous le voyez, pour décrire cette construction, je suis parti de l'élément le plus profond, pour venir à l'élément du haut. Si on inverse l'ordre de construction des deux derniers rectangle, le petit sera caché par le moyen qui est plein. 

    Nous verrons plus loin dans le cours une méthode qui permet de jouer avec la superposition des éléments.

     

    I.2.6 Nettoyer une zone du dessin

    Jusqu'ici, nous n'avons toujours fait que dessiner, mais vous avez certainement pensé que si nous pouvions dessiner, nous pouvions aussi effacer des zones de notre cadre. C'est exactement ce que nous allons faire maintenant. La méthode est:  :      clearRect(posX, posY, hauteur, largeur)

    Les coordonnées x et y indiquent la position du pixel de départ (coin supérieur gauche) , la hauteur et la largeur indiquent la taille que doit avoir ce rectangle qui va servir à effacer. Voici un exemple:

        context1.lineWidth  = 5;
        context1.fillStyle = "red";
    // grand rectangle extérieur pein rouge
        context1.fillRect(
    0,0,150,150);
    // 4 petits rectangles intérieur vide
        context1.clearRect(0,0,50,50);
       context1.clearRect(100,0,50,50);
       context1.clearRect(0,100,50,50);
       context1.clearRect(100,100,50,50);
          votre navigateur n'accepte pas Canvas  

    Attention, il ne faut jamais oublier de placer l'élément clearRect après les éléments que nous avons dessinés. Souvenez-vous de l'ordre dans lequel se dessinent les objets.

    L'utilité de pouvoir effacer les zones que nous voulons est double, la première est de pouvoir effacer tout la zone de dessin Canvas et la seconde est utile pour les animations. Il y a une technique simple pour faire cela, elle consiste à envoyer comme coordonnées de départ (0,0) et comme coordonnées d'arrivées la hauteur et la largeur du cadre. Il est possible d'accéder à ces valeurs avec Javascript:

    lecanvas.width (renvoi la largeur de mon Canvas)                lecanevas.height (renvoi la hauteur de mon Canvas)


    I.3   Les couleurs et techniques pour remplir le fond

    Il existe deux façons de colorer ou remplir nos formes. La première est par les couleurs, nous avons vu les bases juste avant. Il existe également d'autres moyens d'assigner des couleurs à des objets.
    La seconde façon consiste à charger une image et à l'appliquer dans la forme. Il est possible de juste appliquer cette image pour faire office de fond, mais il est aussi possible de la dupliquer pour créer une sorte de pattern.

    I.3.1 Les quatre façons de définir une couleur

    Nous avons vu la première au chapitre précédent, il suffit de donner le nom anglais de la couleur. Pour connaître tous les noms de couleurs qui sont interprétées par le HTML, il vous suffit de faire une recherche sur internet. Vous pouvez par exemple les trouver sur le lien suivant: http://www.w3schools.com/html/html_colornames.asp .

     Ce site regroupe le nom de toutes les couleurs qui sont supportées par les dernières versions d'HTML. Il est aussi très utile pour connaître les normes actuelles de HTML5. Cependant cette méthode d'assignation des couleurs présente un désavantage. Chaque navigateur est libre de fixer la couleur par rapport au nom comme il le veut. Voilà pourquoi un vert jaune sera plus vert sur un navigateur et plus jaune sur un autre. Pour ne pas avoir ce genre de différence il existe deux autres types de valeurs qui sont interprétées de la même manière par les navigateurs.

     La première est de donner la couleur en code rgba (rouge, vert, bleu, alpha). Les valeurs pour le rouge, le vert et le bleu sont définies entre 0 et 255. Plus le nombre est élevé, plus l'intensité en  couleur sera forte. Pour ce qui concerne alpha, il est possible que vous n'ayez jamais entendu parler de cette valeur. Elle indique la transparence de la couleur. Sa valeur peut varier entre 0 et 1. A zéro la couleur est totalement transparente et à 1 la couleur est totalement opaque. Le code complet est un peu différent des autre méthodes, il faut écrire:      rgba (rouge, vert, bleu, alpha)

     Il existe une méthode pour appliquer une transparence globale qui s'effectuera sur tous les éléments qui seront dessinés après l'appel de cette méthode:     globalAlpha = valeur entre 0 et 1

    Lla dernière façon d'assigner une couleur, c'est le code hexadécimal. L'hexadécimal est un système de calcul en base 16. Je ne vais pas vous expliquez comment ces calculs sont effectués, mais voilà à quoi peut ressembler un code en hexadécimal: #RRVVBB.

    Par exemple, pour la couleur verte, il y a trois façons de la définir: par son nom anglais, green, par son code rgba (0,255,0,1) ou encore son code hexadécimal, #00FF00. Rien de mieux qu'un petit exemple pour illustrer tout cela.

        context1.lineWidth  = 8;
        context1.strokeStyle =
    "#FF0000";// contour rouge
        context1.fillStyle = "green";
        context1.fillRect(
    40,40,80,80);  // rectangle vert
        context1.strokeRect(60,30,80,110);  // cadre rouge
       context1.fillStyle ="rgba(0,150,150,0.3)";
       context1.fillRect(100,20,100,70); // rectangle bleu transparent
       context1.fillStyle ="rgba(0,150,150,0.8)";
       context1.fillRect(100,70,100,70); // rectangle bleu opaque

          votre navigateur n'accepte pas Canvas  

    Je sais que je me répète mais vous pouvez voir ici l'importance de l'ordre dans lequel les rectangles sont dessinés pour la gestion de la transparence.

     Une dernière méthode existe, elle est cependant plus rarement utilisée. La voici:

    hsl (dégradé, saturation, luminosité)

    • Dégradé (hue en anglais) génère un degré de couleur. Au lieu de se baser sur une échelle de 255 pour une seule couleur, il se base sur 360°. 0° est rouge, 120° est vert, 240° est bleu.

    • La valeur pour la saturation se donne en pourcentage; à 0% la couleur est dans les ton gris, à 100% la couleur est pleine (comme l'IRC en éclairagisme).

    • Pour la luminosité c'est le même type de valeur qui est attendue: à 0% la lumière est noire, à 100% la lumière est blanche. Je vous donnerai un exemple dans le chapitre sur les animations pour vous rendre compte de l'utilité d'une telle façon de définir des couleurs.

     

    I.3.2 Lesdégradés

    Voilà encore une des grandes spécialités de Canvas, les dégradés. Il peut créer des dégradés très adoucis au niveau des couleurs et de la transition. Il existe deux types de dégradés.

    Le linéaire qui sera le long d'un axe, et le radial avec un point central et un rayon de diffusion. Commençons avec le radial:  createLinearGradient(positionXdépart, positionYdépart, positionXarrivée, positionYarrivée)

    Avec cette fonction, nous pouvons mettre en place une droite que le dégradé suivra. Il faut intégrer cela à une variable que nous appelons degrad. N'oubliez pas que cette fonction provient du contexte. Donc au final il faut faire quelque comme cela:

    var degrad  = context1.createLinearGradient()

     Ensuite il faut ajouter des couleurs. Pour ce faire, il existe une fonction spécialement créée pour ajouter des couleurs à notre dégradé:    addColorStop(positionDansLeDégradé, couleur)

    La position dans le dégradé varie entre 0 (départ)et 1(fin). Donc, cela implique qu'il faut ajouter à chaque fois une nouvelle couleur, à chaque fois qu'on veut créer un nouveau dégradé. Il faut donc au moins 2 couleurs pour créer un dégradé. Cette fonction est à appliquer à notre variable:     degrad.addColorStop()

     Une fois que nous avons toutes les couleurs que nous voulons, il faut passer notre variable gradient comme si c'était une couleur. Donc il faut faire:     fillStyle = degrad.  Puis il suffit de remplir un rectangle de la taille de notre Canvas pour obtenir un joli dégradé.


       
    var degrad = context1.createLinearGradient(0,150,200,-150);
        // le sens du dégradé est en diagonal de bas gauche à haut droite

        degrad.addColorStop(0, "red"); // couleur de départ
        degrad.addColorStop(1, "lime");


       context1.fillStyle =degrad;
       context1.fillRect(0,0,200,150);
          votre navigateur n'accepte pas Canvas

    Il est possible de mettre autant de couleurs que nous voulons (dans cet exemple, il y a 4 couleurs) :

        var degrad = context1.createLinearGradient(0,75,200,75);
        degrad.addColorStop(0, "red");
        degrad.addColorStop(0.3, "lime");
        degrad.addColorStop(0.6, "grey");
        degrad.addColorStop(1, "yellow");

       context1.fillStyle =degrad;
       context1.fillRect(0,0,200,150);
          votre navigateur n'accepte pas Canvas

     J'ai aussi parlé d'un dégradé de type radial :      createRadialGradient(posX0, posY0, rayon0, posX1, posY1, rayon1)

    Cette méthode est un peu différente de la précédente. Les deux points posX0 et posY0 sont les coordonnées du centre du premier cercle dont son rayon est défini par le paramètres rayon0. Il est en de même pour le second cercle (posX1, posY1, rayon1). Le dégradé s'étant entre les deux cercles.

     Voici le résultat qu'on peut obtenir en mettant le centre de deux cercles au même point:

        var degrad = context1.createRadialGradient(100,75,10,100,75,100);

        degrad.addColorStop(0, "#0000100");
        degrad.addColorStop(0.5, "#FFFFFF");
       degrad.addColorStop(1, "#101010");

       context1.fillStyle =degrad;
       context1.fillRect(0,0,200,150);
          votre navigateur n'accepte pas Canvas

    Maintenant, les mêmes couleurs mais avec le centre du second cercle légèrement décalé vers la gauche du dessin.


       
    var degrad = context1.createRadialGradient(60,75,10,130,75,100);

        degrad.addColorStop(0, "#000000");
        degrad.addColorStop(0.5, "#FFFFFF");
       degrad.addColorStop(1, "#101010");

       context1.fillStyle =degrad;
       context1.fillRect(0,0,200,150);
          votre navigateur n'accepte pas Canvas

      

    I.3.3 Les images

    Canvas accepte tout à fait les images. Cela se fait en deux étapes, la première est de charger une image avec Javascript. Pour ce faire il faut faire appel au constructeur new Image(). Vous devriez déjà avoir vu ce type de construction si vous avez déjà créé vos propres objets en Javascript.

     L'étape suivante consiste à attribuer un lien pour l'image à charger, c'est la propriété src. Oui, c'est la même que lors de la mise en place d'un lien HTML. Une autre propriété de cet objet est onload. Je vais toujours dessiner mes images après l'appel de la fonction créée avec onload, car il se peut que dans certains cas, surtout quand l'image est trop grande, que celle-ci soit affichée de manière saccadée. Ce que nous allons faire, c'est que nous allons attribuer à cette valeur une méthode propre à Canvas qui dessinera l'image.

    Voici la méthode qui va dessiner notre image dans le Canvas :   drawImage(image, posX, posY).  La variable image fait référence à l'image chargée. Elle sera dessinée aux positions x et y indiquées. Voici donc comment afficher une images dans Canvas

    <canvas id ="cvs17" width ="282" height = "192">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv1 = document.getElementById('cvs17');
       
      var context1 = canv1.getContext('2d');
        
    var image0 = new Image();
       image0.src = 'img/lyon.jpg'; //adresse de l'image
       image0.onload = function () {
                              
    context1.drawImage(this,0, 0);
                                }

      
    </script>
          votre navigateur n'accepte pas Canvas

     Note: this fait référence à l'objet en court d'utilisation, ici c'est image créée plus haut

    Cependant, utiliser la méthode telle quelle présente un défaut; La taille de l'image ne correspond pas forcément à la taille du Canvas. Dans l'exemple précédent, j'ai adapté la taille du Canvas pour que l'image soit entièrement à l'intérieur. Voilà pourquoi il existe une syntaxe plus complète pour cette méthode qui permet de modifier la taille de l'image à afficher:  drawImage(image, posX, posY, widthImage, heigthImage).   widthImage définit la largeur de l'image qui sera affichée (ne tient pas compte de la largeur de l'image originale). heigthImage définit la hauteur de l'image qui sera affichée (ne tient pas compte de la hauteur de l'image originale).copie :

    Il est possible que dans certains cas nous voulions découper notre image pour n'en afficher qu'une certaine partie. À nouveau il existe une syntaxe différente de la méthode pour pouvoir découper l'image:

    drawImage(image, cutX, cutY, cutWidth, cutHeight, posX, posY, widthImage, heigthImage);

    cutX et cutY définissent le point de départ de la découpe de l'image (par rapport à l'image). cutWidth et cutHeight définissent réciproquement la largeur et la hauteur de découpage. Au final on se trouve avec une nouvelle image rectangle.

     

    Attention cependant à l'utilisation de ce moyen pour modifier la taille de nos images. Dans mon exemple, vous pouvez voir que je ne respecte plus le fait que mon Canvas est de forme carrée, du coup mon image est déformée. De plus, une perte de précision est visible.

     

    I.3.4 Création de motifs

    Un motif est une image qui va être répétée pour former le fond d'une page. Il faut donc partir d'une image et ensuite la répéter, soit de façon horizontale, soit de façon verticale, soit des deux manières. Il existe une méthode simple pour créer un motif: createPattern(image, répétition);

    Le paramètre répétition peut prendre trois valeurs:

    • repeat-y: pour une répétition horizontale
    • repeat-x: pour une répétition verticale
    • repeat: pour une répétition qui combine les deux dernières possibilités.

    Ensuite il faut attribuer notre motif à la propriété fillStyle. La dernière chose à faire consiste à créer un rectangle plein  de la dimension que nous voulons.

    I.4   Les traits

    C'est maintenant que nous allons commencer à nous amuser. Les traits nous offrent un très grand nombre de possibilités. Au début ce seront uniquement des traits droits. Après nous commencerons à faire des cercles et des ovales. Pour finir, nous nous attaquerons aux courbes.

    I.4.1 Nos premiers traits

    J'ai toujours eu l'impression d'être un vrai peintre lorsqu'il est question de traits avec Canvas. Je m'explique, vous êtes un peintre, quelle est la première chose que vous faites ? Vous choisissez une toile sur laquelle peindre, ensuite vous trempez votre pinceau dans la peinture de votre choix. Après commence réellement le dessin, vous placez votre pinceau sur votre toile à un point de départ et après vous vous déplacez de point en point jusqu'à obtenir la forme souhaitée. Et bien Canvas utilisera la même méthode de travail.

    Pour choisir la couleur, c'est exactement les mêmes méthodes qu'avant; fillStyle si nous voulons une forme remplie et strokeStyle si nous voulons juste le trait. Nous pouvons encore choisir l'épaisseur du trait, pour ce faire il faut utiliser lineWidth que nous avons déjà utilisé avant. Jusque là, rien de bien nouveau.

    Maintenant que notre pinceau est prêt, nous devons dire que nous commençons notre trait. Pour ce faire nous utilisons la méthode de notre contexte :    beginPath()

    Une fois celle-ci mise en place, il faut déplacer notre pinceau jusqu'au point de départ, sans pour autant déjà peindre :   moveTo( x, y) 

    Cette méthode est exactement là pour ça. Elle nous permet de nous déplacer dans le Canvas sans pour autant tracer un trait visible. Maintenant que notre pinceau est à son point de départ, nous allons enfin pouvoir tracer nos traits avec la méthode :   lineTo( x, y) 

    Nous pouvons maintenant tracer tout les traits que nous voulons pour faire notre forme. Une fois qu'on est au dernier point, il existe une méthode :    closePath() 

    Celle-ci n'est pas obligatoire, elle va uniquement tracer un trait entre le dernier point et le premier. D'ailleurs il est l'heure de donner de la couleur. Pour donner la couleur, il suffit soit de mettre fill(), si nous voulons une forme pleine et stroke() si nous ne voulons que le trait. Ses deux méthodes doivent se trouver après la dernier trait tracé. Assez parlé, place à l'exemple:

       context2.lineWidth  = 5;
       context2.fillStyle ="rgba(0,0,150,0.3)"; // rempli en bleu
       context2.strokeStyle = "#A00000"; // traits en rouge
       context2.beginPath();
       context2.moveTo( 10, 10);
       context2.lineTo( 10, 140) ;
       context2.lineTo( 140, 140) ;
       context2.lineTo( 180, 60) ;
       context2.stroke();
        context2.fill();
     context2.beginPath(); // dessin d'un forme vide
       context2.moveTo( 20, 240);
       context2.lineTo( 70, 280) ;
       context2.lineTo( 120, 240) ;
       context2.closePath();  // ferme le triangle
       context2.stroke();
     context2.beginPath();// dessin d'un forme plein (sans bord)
     context2.moveTo( 20, 350);
       context2.lineTo( 70, 390) ;
       context2.lineTo( 120, 350) ;
        context2.fill();

     
          votre navigateur n'accepte pas Canvas

     

    I.4.2 Le design des traits

    On peut faire bien plus que de simplement modifier la taille du trait. Il est aussi tout à fait possible de modifier les extrémités des traits. La propriété est la suivante:  lineCap

    Elle peut recevoir trois attributs:

    • round: pour que l'extrémité du trait soit arrondie;
    • butt: le bout est coupé exactement aux extrémités ( mode par défaut);
    • quare: le trait est aussi coupé en carré comme avec butt, mais dans ce cas là il dépasse du point d'arrivée. Le trait a la même longueur qu'avec le type d'extrémité à round.

       context2.lineWidth  = 20;
       context2.strokeStyle = "BlueViolet";
       context2.beginPath();
       context2.lineCap = "round"
       context2.moveTo( 20, 80);
       context2.lineTo( 180, 80) ;
       context2.stroke();
       context2.beginPath();
       context2.lineCap = "butt"
       context2.moveTo( 20, 180);
       context2.lineTo( 180, 180) ;
       context2.stroke();
    context2.beginPath();
       context2.lineCap = "square"
       context2.moveTo( 20, 280);
       context2.lineTo( 180, 280) ;
       context2.stroke();
          votre navigateur n'accepte pas Canvas

    Vous pouvez voir que j'ai été obligé de faire un nouveau chemin à chaque fois. Si vous ne faites pas cela, seul le dernier lineCap est pris en compte.

     

    Une autre transformation existe, il est possible de modifier la jointure entre les différents traits lorsqu'il y a par exemple des coins. Cette fois nous devons faire appel à une autre méthode :   lineJoin

    Comme la précédente, elle possède trois valeurs possibles:

    • bevel: les joints sont biseautés
    • round: les joints sont arrondis
    • miter: les traits sont rallongés jusqu'à former un angle (mode par défaut)
       context2.lineWidth  = 10;
       context2.strokeStyle = "DarkOrange";
       context2.beginPath();
       context2.lineJoin = "bevel"
       context2.moveTo( 20, 130);
       context2.lineTo( 180, 130) ;
       context2.lineTo( 180, 20) ;
       context2.lineTo( 120, 80) ;

       context2.stroke();
       context2.beginPath();
       context2.lineJoin = "round"
      context2.moveTo( 20, 280);
       context2.lineTo( 180, 280) ;
       context2.lineTo( 180, 170) ;
       context2.lineTo( 120, 230) ;

       context2.stroke();
       context2.beginPath();
       context2.lineJoin = "miter"
       context2.moveTo( 20, 380);
       context2.lineTo( 180, 380) ;
       context2.lineTo( 180, 320) ;
       context2.lineTo( 120, 360) ;
    ;
       context2.stroke();
          votre navigateur n'accepte pas Canvas

     Il y a une autre propriété des traits de Canvas. Elle n'est utilisable que lorsque la valeur de lineJoin est miter. Elle va affecter la longueur maximale qu'il y a entre l'intersection des deux droites jusqu'à la pointe formée par l'angle. La longueur dont je parle est celle qui sépare les deux traits noirs les deux points de liaison (intérieur et extérieur).

    Maintenant voici cette fameuse propriété :   miterLimit = nombre;      De base sa valeur est à 10. Lorsque la longueur évoquée au dessus dépasse celle attribuée par miterLimit, l'angle se dessine de la même façon que lorsque la propriété lineJoin = 'bevel'.

        context2.lineJoin = "miter";
       context2.miterLimit  = 2;

       context2.lineWidth  =
    10;
       context2.strokeStyle = "Aqua";

       context2.beginPath();
       context2.moveTo( 20, 130);
       context2.lineTo( 180, 130) ;
       context2.lineTo( 180, 20) ;
       context2.lineTo( 120, 80) ;
       context2.stroke();

       context2.beginPath();
      context2.moveTo( 20, 280);
       context2.lineTo( 180, 280) ;
       context2.lineTo( 180, 170) ;
       context2.lineTo( 160, 230) ;
       context2.stroke();
          votre navigateur n'accepte pas Canvas

    I.4.3 Les cercles et les arcs

    C'est bien joli de pouvoir faire des formes avec des coins, mais qu'en est-il si nous ne voulons pas de coins? Sachez que Canvas offre la possibilité de faire des cercles, pour cela il y a une seule et unique méthode:

    arc(posX, posY, rayon, angleDeDépart, angleDeFin, sens)

    Je pense que les trois premières valeurs sont simples à comprendre, les coordonnées x et y pour placer le centre de notre cercle et le rayon, je pense que vous avez compris. Cependant vous pouvez voir qu'il y a une question d'angle et de sens, je vais vous expliquer tout cela. Dans certaines situations, il est possible que nous ne voulions pas faire un cercle complet, voilà pourquoi il y a une question d'angle de départ et un angle d'arrivée. Le sens va interférer sur le sens dans lequel le cercle va se construire par rapport aux angles choisis. Voici une explication en image:

    Il est important de toujours garder ce dessin en tête quand vous dessinez un cercle. Cependant, sachez que cet attribut est optionnel, de base sa valeur est false (sens horaire).

    Une autre information importante: Canvas travaille en radiant. Ce qui signifie que vous ne pouvez pas simplement donner la valeur en degré, vous devez faire la transformation de degré à radiant. Cela est simple, il suffit d'effectuer ce petit calcul:

    (Math.PI/180)*angle

    Math.PI renvoi la valeur de pi, qui en radiant est équivalent à 180°. Je divise donc 180° par 180, comme ça je me retrouve avec la valeur de 1°, il me suffit de multiplier ensuite le tout par la valeur de l'angle que je souhaite utiliser. Voilà un exemple avec un petit smiley:

        context2.fillStyle  = "Chocolate";
       context2.strokeStyle = "Brown";
       context2.lineWidth  = 3;
      
    context2.beginPath(); // tête
       context2.arc( 75, 75,50, 0, 2*Math.PI);
    // cercle ( 2PI [rad])
       context2.fill();
       context2.stroke();
       context2.beginPath();
    // bouche

        context2.strokeStyle = "red";
     
    context2.arc(75, 75,30, Math.PI/180*10, Math.PI/180*170);
       context2.stroke();
        context2.beginPath(); // oeil gauche
        context2.strokeStyle = "black";
       context2.fillStyle  = "Aquamarine";
      
    context2.arc(55, 70,20, Math.PI/180*220, Math.PI/180*320);
       context2.stroke();
       context2.fill();
       context2.beginPath(); // oeil droite
      
    context2.arc(95, 70,20, Math.PI/180*220, Math.PI/180*320);
       context2.stroke();
       context2.fill();
       context2.beginPath(); // nez
      
    context2.strokeStyle = "Brown"
      
    context2.moveTo(75,68);
       context2.lineTo(75,85);
       context2.stroke();
          votre navigateur n'accepte pas Canvas

     Comme vous l'avez ppris au chapitre sur les couleurs, il est possible d'ajouter des dégradés, voilà le genre de dessin qu'il est  possible d'obtenir en jouant avec les dégradés:

        var gradientCercle = context2.createRadialGradient(50,50, 1,35,35,100);
       gradientCercle.addColorStop(
    0,"beige");
       gradientCercle.addColorStop(1,"burlywood");
       
    var gradientOmbre = context2.createLinearGradient(75,75,140,140);
      
    gradientOmbre.addColorStop(0,"black");
       gradientOmbre.addColorStop(1,"white");

       context2.fillStyle  =
    gradientOmbre;
       context2.beginPath();
      
    context2.arc(90, 130,40, 0, 2*Math.PI);
       context2.fill();
     context2.fillStyle = gradientCercle;
       context2.beginPath();
       context2.arc(75, 75,40, 0, 2*Math.PI);
       context2.fill();
          votre navigateur n'accepte pas Canvas

    Il existe une dernière méthode qui implique les arcs, c'est celle-ci :    arcTo(P1x, P1y, P2x, P2y, rayon).  

    Cette méthode va continuer à partir du dernier point atteint.
    Le premier couple de points (P1x, P1y) est le point vers lequel l'arc va tendre.
    Le second couple de point (P2x, P2y) est celui d'arrivée de l'arc.
    Le rayon définit le rayon du cercle.

     Voilà un petit exemple de mise en place de cette méthode :

    <canvas id ="cvs27" width ="200" height = "200">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv2 = document.getElementById('cvs27');
       
    var context2 = canv2.getContext('2d');

       context2.strokeStyle  =
    "#f05000";
       context2.fillStyle  = "#200020";
      
    context2.lineWidth  = 4;
      
    context2.beginPath();
      
    context2.moveTo(10, 20);
       context2.lineTo(90, 20);
    // horizontal haut
       context2.arcTo(110, 20,130,50,50);  // cercle ext.
       context2.lineTo(130, 130);// vertical droite
       context2.lineTo(100, 130); // horizontal bas
       context2.lineTo(100, 80); //
    vertical
       context2.arcTo(100, 40, 50,50,50); // cercle int
    context2.lineTo(10, 50); // horizontal
    context2.closePath(); // ferme la forme
    context2.stroke();
    context2.fill();

      
    </script>
          votre navigateur n'accepte pas Canvas


    I.4.4 De la droite à la courbe

    Je viens de vous présenter une façon de faire des formes non-cubiques avec des cercles, mais très vite nos dessins sont limités. Il existe une dernière manière de tracer des traits : les courbes. Elles sont au nombre de 2 types différentes.

    1 ° Les courbes de bézier:      bezierCurveTo( p1x, p1y,  p2x, p2y, p3x, p3y)  Le premier et le second couple de coordonnées (p1x, p1y,  p2x, p2y) sont les points de tension (vers lesquels la courbe va tendre). Le troisième couple (p3x, p3y) est le point d'arrivée.

    2° La seconde courbe est la quadratique:  quadraticCurveTo( p1x, p1y, p2x, p2y)

    Le premier couple de coordonnées (p1x, p1y) est un point vers lequel la courbe va tendre. Le dernier couple de coordonnées (p2x, p2y) est le point de tension (point d'arrivé). Voici une illustrations des deux courbes :

       context2.strokeStyle  = "darksalmon";
       context2.fillStyle  = "darkkhaki";
      
    context2.lineWidth  = 5;
      
    context2.beginPath();
      
    context2.moveTo(10, 50);
       context2.bezierCurveTo(90, 110,190,0,240,30);
    // horizontal haut
       context2.stroke();
       context2.fill();

       context2.beginPath();
      
    context2.moveTo(20, 200);
       context2.quadraticCurveTo(300, 200, 280, 280); // horizontal haut
       context2.stroke();

      
          votre navigateur n'accepte pas Canvas

    I.5 Le texte

    Si nous devions écrire du texte avec les précédente méthodes, cela serait très lent et une réelle perte de temps. Heureusement pour nous Canvas a plus d'un tour dans son sac.

    I.5.1 Écrire avec Canvas

    Canvas nous offre deux méthodes pour écrire du texte, les voici :    fillText("texte", posX, posY)    ou      strokeText("texte", posX, posY)

    Je pense que la différence vous saute aux yeux. Dans l'un des cas, le texte est plein ( fillText() ), dans le second ( strokeText() ) il n'y aura que le contour des lettres du texte qui sera affiché, l'intérieur sera vide. Il faut tout de fois faire attention à l'utilisation de la seconde fonction, car celle-ci peut donner un texte peu visible ou même ne pas afficher que les contours, utilisez donc cette méthode avec parcimonie. Pour les deux positions (posX, posY ), elles correspondent au coin inférieur gauche du texte. Donc si vous mettez comme coordonnées (0,0), le texte sera en dessus de la zone de dessin visible.

     Il existe trois méthodes pour aider à la mise en page du texte.

    1° La première nous permet de modifier la taille et la police du texte :    font= "taille police1,police2,police3 ..."     Voici un exemple      font = "12pt Times, Arial, sans-sherif"

    La première valeur à indiquer est la taille de la police, elle peut s'indiquer soit par sa taille en pixel sois par sa taille en point. Ensuite, il est possible de mettre plusieurs polices différentes, c'est utile par exemple lorsque la première police donnée n'est pas prise en compte sur le navigateur qui va lire la page. Dans l'exemple la taille du texte est de 12pt et la police est Times. Cependant si le navigateur de ne gère pas la polices Times, alors il utilisera Arial et s'il ne l'utilise pas alors il utilisera sans-sherif.

    2° La seconde est une méthode pour aligner horizontalement le texte :       textAlign = placement           placement peut prendre trois variable; left (gauche), center (centre), right ((droite).

      context2.beginPath();
       context2.lineCap = "butt"
       context2.moveTo( 150, 1);
    // un trait à l'axe pour le situer
       context2.lineTo(150, 200) ;
       context2.stroke();
       context2.fillStyle  = "#0C0C0C";
      
    context2.font = "18pt Arial, Times";
      
    context2.textAlign = "right";
      
    context2.fillText ("à droite",150, 50);
       context2.textAlign = "center";
      
    context2.fillText (" centre",150, 100);

     context2.textAlign = "left";
      
    context2.fillText ("gauche",150, 150);
          votre navigateur n'accepte pas Canvas

    3° Il en existe une troisième qui va gérer son alignement vertical :    textBaseline = placement    qui  peut aussi prendre trois variable: top (haut), middle (milieu), bottom (bas).

      context2.beginPath();
       context2.lineCap = "butt"
       context2.moveTo( 1, 75);
    // un trait à l'axe pour le situer
       context2.lineTo(300, 75) ;
       context2.stroke();
       context2.fillStyle  = "#0C0C0C";
      
    context2.font = "18pt Times, Arial";
      
    context2.textBaseline = "top";
      
    context2.fillText ("en dessous",10, 75);
       context2.textBaseline = "middle";
      
    context2.fillText (" l'axe",120, 75);
       context2.textBaseline = "bottom";
      
    context2.fillText ("au-dessus",190, 75);
          votre navigateur n'accepte pas Canvas

    Elles ne sont pas obligatoires pour écrire du texte, elles vont simplement modifier la position de base du texte.

    Il existe une autre fonction, elle est cependant rarement utilisée, elle permet de mesurer la taille en pixel d'un texte, cela peut être utile pour ne pas dépasser du cadre :  measureText(votreTexte)

       context2.fillStyle  = "#FC0C00";
       context2.strokeStyle  = "#FC0060";
      
    context2.font = "20pt Times, Arial";
      
    var longtext = context2.measureText("long")
      
    context2.strokeText ("long",10, 75);
       context2.font = "12pt Times, Arial";
      
    context2.fillText (" longueur"+Math.round(longtext.width)+"pixel",10, 150);
          votre navigateur n'accepte pas Canvas

     J'ai des petites informations à donner sur le dernier point:

    • La première est que vous avez certainement reconnu la fonction Math.round () , je l'utilise pour ne pas me retrouver avec un nombre affolant à virgule.
    • La seconde est sur ma variable qui teste la taille de mon texte, je ne récupère que sa longeur, mais je pourrais aussi récupérer sa hauteur.
    • Troisième information, j'aurais très bien pu créer une variable qui stockerait mon texte. Comme ça je la passe non seulement à ma méthode measureText () mais en plus je sais que c'est aussi elle que j'écris à l'écran.

     

     

    Partie II:Les techniques avancées

    II.1 Nouvelles techniques de dessin

    Jusqu'ici, vous avez appris les bases de Canvas, mais il existe encore bien des choses à apprendre. Ce sont plus des petites astuces que vraiment de nouvelles façons de dessiner, mais elles ont tout de même leur place dans ce cours.

     

    II.1.1 Les ombres

    Il est possible avec Canvas de mettre en place des ombres. Il faut d'abord définir la projection de l'ombre par rapport à l'objet ombragé. Pour cela nous avons deux propriétés:   shadowOffsetX   et    shadowOffsetY. Si vous n'apportez pas de modification aux deux propriétés, leur valeur sera celle par défaut, l'ombre sera alors placée équitablement autour de la forme. Il suffit ensuite de leur attribuer une valeur, elle représente le décalage par rapport à l'objet qui contient l'ombre. Si vous laissez ça nul, l'ombre sera placée de manière égale autour de la forme. Ensuite nous pouvons assigner une quantité de flou à cette ombre :    shadowBlur .    Plus la valeur attribuée à shadowBlur est élevée, plus la quantité et la dissipation de l'ombre seront importantes, à 0 l'ombre est nulle. Il est inutile de mettre une valeur trop haute, car si elle est trop haute il n'y aura simplement plus d'ombre. La dernière étape consiste à attribuer une couleur à notre ombre, encore une fois, Canvas nous offre une nouvelle propriété: shadowColor

    Ensuite c'est tout. Il n'y a pas besoin de dessiner nous même l'ombre, elle se dessinera automatiquement. Cependant, cela implique qu'il faut avoir défini notre ombre avant de dessiner la forme qui doit avoir l'ombre. Voici de quoi illustrer mes propos:

    <canvas id ="cvs32" width ="200" height = "200">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv2 = document.getElementById('cvs32');
       
    var context2 = canv2.getContext('2d');

       context2.fillStyle  = "#F02020";
       context2.strokeStyle  = "#FC0000";
       context2.shadowBlur = 10;
      
    context2.shadowColor = "black";
      context2.fillRect (10, 10,30,30);
      context2.shadowBlur = 10;

       context2.shadowOffsetX= 20;
       context2.shadowOffsetY= 5;
      
    context2.fillRect (50,50, 30,30);
      context2.shadowOffsetX=
    30;
      context2.shadowOffsetY=
    15;
      context2.fillRect (100,100, 30,30);
      context2.font = "18pt Arial, Times";
       context2.fillText ("ombre",10, 160);

      
    </script>
          votre navigateur n'accepte pas Canvas


    II.1.2 Spécifier une zone de dessins

    Jusqu'à maintenant, nous avons toujours travaillé dans l'entier du contexte. Il existe cependant une méthode qui permet de définir une zone précise dans laquelle les dessins vont se faire. Cette méthode est la suivante :    clip();      Elle doit être appliquée après avoir dessiné une première forme, par exemple un rectangle, ensuite il suffit de dessiner tout ce que nous voulons dans le contexte, seulement ce qui se trouve à l'intérieur de cette zone définie avant sera visible, comme dans l'exemple suivant:

       context2.fillStyle  = "gainsboro";
       context2.strokeStyle  = "black";
       context2.fillRect  (0,0, 150,150); // le fond de cnavas est grisé
      context2.rect (25,25, 100,100);
       context2.stroke();
       context2.clip();  // la zone d'affichage = le dernier rectangle
       context2.fillStyle  = "darkred";
     context2.font = "22pt Arial, Times";
     context2.fillText ("c'est coupé",10, 34);
    // le haut et les cotés sont coupés
     context2.fillText ("c'est coupé",10, 75); // les cotés sont coupés
       context2.fillText ("c'est coupé",10, 134);// le bas et les cotés sont coupés
          votre navigateur n'accepte pas Canvas

     

    II.1.3 La composition des dessins

    Vous vous rappelez que dans les chapitres précédents je mettais un point d'honneur à dire que l'ordre dans lequel nous dessinions était important, et bien je ne vous ai pas tout dit. Avec Canvas nous avons la possibilité de travailler avec la superposition des pixels pour en faire à peu près ce que nous voulons. D'abord la méthode pour faire ça :    globalCompositeOperation       Cette méthode peut trier certains pixels pour nous. Cela permet d'afficher ou de cacher certains pixels. C'est un outil qu'on peut retrouver dans certains logiciels de dessin avec le système de calque. Attention, je ne dis pas que Canvas fonctionne avec un système de calque. Il y a en tout 16 opérations possibles.

     Quatre s'appliquent par rapport au contenu que nous allons créer (source):

    • source-over (place la source au dessus)
    • source-in (seule la source qui chevauche ce qui est déjà dessiné est affichée)
    • source-out (seule la source qui ne chevauche pas ce qui est déjà dessiné est affichée)
    • source-atop (la partie de la source qui chevauche ce qui est déjà dessiné est affichée)

    Quatre autres vont s'appliquer par rapport aux dessins qui ont déjà été fais (destination):

    • destination-over (la destination est au-dessus du nouvel objet )
    • destination-in (la destination est affichée sous le nouvel objet)
    • destination-out (seulela destination qui n'est pas chevauchée par le nouvel objet est affichée)
    • destination-atop (la partie de la destination qui chevauche le nouvel objet est affichée)

    Les quatre dernières font un mixe entre le nouvel élément et les anciens.

    • lighter(la zone de chevauchement est plus claire)
    • darker (la zone de chevauchement est plus foncée)
    • copy(seul le nouvel objet est affiché)
    • xor (tout est affiché sauf la zone de chevauchement)
       context2.fillStyle  = "yellow";
      context2.fillRect (50, 50,150,150);
      context2.globalCompositeOperation = "source-over"; 
    // code avec source-over
       context2.fillStyle  = "lime";
      
    context2.fillRect (0,00, 100,100);

      Je vous donne directement un récapitulatif des 12 différents résultats que nous pouvons obtenir en utilisant la même construction que celle écrite ci-dessus :

    source-over
          votre navigateur n'accepte pas Canvas
    source-in
          votre navigateur n'accepte pas Canvas
    source-out
          votre navigateur n'accepte pas Canvas
    source-atop
          votre navigateur n'accepte pas Canvas
    destination-over
          votre navigateur n'accepte pas Canvas
    destination-in
          votre navigateur n'accepte pas Canvas
    destination-out
          votre navigateur n'accepte pas Canvas
    destination-atop
          votre navigateur n'accepte pas Canvas
    lighter
          votre navigateur n'accepte pas Canvas
    darker
          votre navigateur n'accepte pas Canvas
    copy
          votre navigateur n'accepte pas Canvas
    xor
          votre navigateur n'accepte pas Canvas

    II.1.4 Connaître la position d'un point par rapport à un tracé

    Il peut être utile dans certains cas de savoir si un point précis se trouve dans le tracé en cours. Pour ce faire il faut utiliser la méthode:    isPointInPath(posX, posY);          Cette fonction retourne true si le point qui est défini par posX et posY se trouve dans le tracé en cours. Dans l'exemple suivant je vais définir un rectangle avec la méthode rect(), ensuite je vérifie si le point donné se trouve à l'intérieur de celui-ci, si c'est le cas alors j'affiche le rectangle:

    <canvas id ="cvs46" width ="150" height = "150">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
        
    var canv2 = document.getElementById('cvs46');
       
    var context2 = canv2.getContext('2d');

       context2.fillStyle  = "deeppink";
       var pixelX = 60;
       
    var
    pixelY = 80;
       context2.rect  (25,25, 120,120);  
      if ( context2.isPointInPath(pixelX, pixelY))  {
                    context2.fill();// n'est excécuté que si le point est dans rect.
                    };  // fin de la condition if {}
      </script>
          votre navigateur n'accepte pas Canvas
     Le rectangle s'affiche car la valeur retournée par isPointInPath() est vraie. Cela se vérifie par le dessin au-dessus où nous pouvons voir que le point ( 60, 80) est bien situé à l'intérieur du rectangle. Cette méthode est très utile dans le cas où nous utilisons des variables qui peuvent changer au cour du temps.

    II.2 Dessinez via la souris : onmousemove

    Attention, ne vous attendez pas à créer le nouveau Paint. Je vais simplement vous introduire des notions un peu plus poussée en Javascript pour par exemple dessiner un cercle à chaque clic sur notre Canvas.

    II.2.1 Récupérer la position du curseur

    La première étape est de mettre un événement sur notre balise Canvas.

    Rappel: Il existe plusieurs types d'événements. Pour les mettre en place, il suffit d'insérer à l'intérieur d'une balise un type d'événement. Par exemple <canvas onclick="alert('test');">. Dans cet exemple, si vous cliquez sur le cadre, une nouvelle fenêtre va s'ouvrir avec comme message "test". Pour récupérer les informations de cet événement, il suffit d'envoyer un attribut: event. Par exemple:  <canvas onclick="maFonction(event);">

    Dans notre cas, nous voulons plusieurs choses:

    • Un événement qui s'active lorsque notre curseurpasse par dessus le cadre de Canvas
    • La position de notre balise Canvas dans la page.
    • La position de la souris dans le Canvas.
    • Afficher un message avec les informations de positions.

    Voici à quoi devrait ressembler votre balise Canvas et la fonction que nous allons utiliser.

    <canvas id ="cvs" width ="300" height = "150"onmousemove="XYcurseur(event)">;
          votre navigateur n'accepte pas Canvas
    </canvas>

       function XYcurseur(event) {
                  // code de la fonction
                    };  // fin de la function {}

    Plusieurs étapes importantes sont maintenant à mettre en place dans notre fonction. La première est d'effacer l'entier du cadre, sinon le texte se superpose et il deviendrait très rapidement illisible. L'étape suivante consiste à récupérer la position du cadre Canvas dans la page en tenant compte du défilement vertical de la page. Pour ce faire, il existe une méthode qui retourne les positions exactes des objets de type  blocs :     getBoundingClientRect() (à appliquer sur le canvas et non sur le context  exemple : moncanvas.getBoundingClientRect()).

     Maintenant que nous avons cette position, nous pouvons calculer la position du curseur par rapport au cadre de Canvas. Pour ce faire il faut encore récupérer une donnée, c'est la position du curseur, c'est à ce moment que nous avons besoin de la variable de type event que nous avons transmit à notre fonction:

    • event.clientX (Coordonnée x de la souris)
    • event.clientY (Coordonnée y de la souris)
    <canvas  id ="cvs47" width ="250" height = "150 onmousemove="XYcurseur(event)">
         
    votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
    var canv47 = document.getElementById('cvs47');
    var context47 = canv47.getContext('2d');
    context47.font=
    "18pt Arial";
    context47.fillStyle=
    "blueviolet";
    function XYcurseur(
    event) {
       context47.clearRect(
    0,0,canv47.width,canv47.height); // efface le cadre
       var XYrect = canv47.getBoundingClientRect();    // action avec le canvas et pas le context
       var Xcurseur = Math.round(event.clientX - XYrect.left); 
       var Ycurseur = Math.round(event.clientY - XYrect.top);
       context47.fillText(
    "Position de la souris",10, 35);
       context47.fillText(
    "X="+Xcurseur, 70, 70);
       context47.fillText(
    "Y="+Ycurseur, 70, 105);
       };

      </script>
    Passez la souris dans le cadre ci-dessous! votre navigateur n'accepte pas Canvas

      

    II.2.2 Un cercle pour un clic

    Dans le chapitre précédent, nous avons travaillé avec l'événement onmousemove =  fonction(event), mais dans ce chapitre, si nous voulons dessiner un cercle à chaque fois que nous cliquons sur le Canvas, nous devons utiliser onclick=  fonction(event).

     Le reste est presque comme le dernier exemple, il faut récupérer la position du curseur et ensuite dessiner un cercle ayant comme centre la position du curseur au moment du clic. Voilà à quoi cela devrait ressembler (mon exemple implique des nombres aléatoires):

    Note: Vous pouvez voir que pour obtenir un nombre entre 0 et 255, j'utilise à la ligne 14 un Math.floor() (donne l'entier inférieur ou égal), car sinon il serait possible d'obtenir comme résultat 256, ce qui n'est pas possible quand nous travaillons avec des couleurs. Ceci est un exemple de l'utilisation des nombres aléatoires avec Canvas. Non seulement la taille des cercles va varier, mais en plus chaque couleurs sera différente.

    II.3 Modification des pixels

    Canvas est une surface de pixels. Jusqu'à présent nous avons seulement effleuré cette idée. Nous allons maintenant réellement en parler. Dans ce chapitre nous allons pouvoir travailler pixel par pixel, couleur par couleur. Dit comme ça, cette tâche peut paraître faramineuse, mais vous comprendrez vite que ce n'est pas le cas.

    II.3.1 Récupération des pixels

    Je sais que je vais me répéter, mais Canvas est une surface de pixels. Et si nous pouvons dessiner tous les pixels que nous voulons grâce à des méthodes qui vont faire le travail à notre place, nous pouvons aussi accéder à chaque pixel, à chaque couleur de chaque pixel. Pour cela il existe deux méthodes :  createImageDate( x, y);   getImageData( x, y, width, height);

    Ces deux méthodes crée un tableau qui contiend toutes les valeurs de nos couleurs pour chaque pixel. Cependant elles ne fonctionnent pas de la même manière.  createImageDate( x, y) crée une image vierge. Nous allons donc pouvoir créer une image de A à Z avec cette méthode. Les dimensions de cette image sont définies par x et y. getImageData( x, y, width, height)  crée un tableau de pixels en récupérant ceux présents sur le canvas déjà créé. Les pixels récupérés sont un rectangle. Le coin supérieur gauche de ce rectangle sera la position définie par x et y, ensuite sa taille sera définie par width et height.

    Les deux valeurs:  x et y indiquent la taille du contexte. Donc si notre contexte fait 150 par 150, les valeurs x et y sont 150. Ensuite un point important à comprendre est comment est construit ce tableau. Il va stocker la couleur de chaque pixel, mais comme nous le savons, une couleur est composée de quatre données, c'est le système RGBA. Cela signifie que les quatre premières cases de notre tableau sont uniquement la couleur du premier pixel. Voici un petit récapitulatif de l'apparence du tableau en question:

     

    Pixel 1

    Pixel 2

    Pixel 3

    Pixel [4]

    Red

    [0]

    [4]

    [8]

    [12]

    Green

    [1]

    [5]

    [9]

    [13]

    Blue

    [2]

    [6]

    [10]

    [14]

    Alpha

    [3]

    [7]

    [11]

    [15]

     Cela implique que pour parcourir l'ensemble des pixels, il faut sauter de 4 en 4.

     Note: Je récupère les informations de notre objet imageD avec la propriété data .

    .J'applique une couleur de fond à mon contexte, ensuite je récupère l'ensemble des valeurs des couleurs et je demande à ce qu'un alert() me renvoie la valeur de la couleur du premier pixel. Vous pouvez voir que c'est bien les bonnes valeurs qui sont retournées (dans cet exmple rouge : 1*16=16, vert : 1*16=16, bleu A=1 => 10*16=160)

    Je pense qu'à ce moment fuse une grande question dans votre tête, pourquoi est-ce que la valeur alpha est 255 alors que nous avons définis que sa valeur était 1? Comme je l'ai dis plus tôt, pour définir alpha, nous donnons des valeurs comprisent entre 0 (transparent) et 1 (opaque). Hors, les couleurs du pixels ne sont pas stockées ainsi. Je ne sais pas si c'est une erreur de la part des personnes qui s'occupent de Canvas ou quelque chose comme ça, mais n'oubliez pas cette information, car lorsque nous voudrons modifier des valeurs alpha, nous devrons travailler entre 0 et 255, pas entre 0 et 1 comme lorsque nous définissons une couleur.

     

    II.3.2 Application de filtre sur une image

    Vous vous rappelez de notre précédente photo photo du Lyon ? Imaginons maintenant que nous voulions faire certains outils pour travailler la photo et que nous voulions appliquer un filtre de couleur par dessus. C'est là que la récupération de tous les pixels peut être utile et vous allez voir que c'est non seulement très simple mais aussi très rapide.

     Tout d'abord il existe une nouvelle méthode à apprendre pour pouvoir retourner les tableaux modifiés :    putImageData( imageData, x, y);   Cette fonction va retourner les valeurs du tableau de pixels enregistré dans la variable imageD. La position x et y indique le coin supérieur gauche à partir duquel les pixels de imageD vont être affichés.

    Il faudra aussi mettre en place une boucle pour modifier les pixels. Pour ce faire il faut en utiliser une de type for qui fera l'ensemble des cases du tableau. Pour récupérer la longueur du tableau vous pouvez utiliser: mapP.length. Ensuite souvenez-vous ce que j'ai dis avais, pour passer de pixels en pixels, il faut sauter de 4 en 4, c'est pour ça qu'à chaque tour de boucle il faudra incrémenter notre variable i par + 4.

    Dans cet exemple, j'applique un filtre rouge sur l'ensemble de l'image. Pour ce faire je diminue la valeur du vert et du bleu tout en augmentant celle du rouge.

    Note: Le premier pixel représente la valeur pour le rouge, le second le vert et le troisième le bleu. Je ne m'occupe pas de la case du tableau qui gère l'alpha.

     

    Je vous montre un autre exemple où, au lieu d'augmenter l'intensité d'une couleur, je vais mettre la photo en noir et blanc. Je vais donc me retrouver avec uniquement des gris. Si vous avez déjà un peu jouer avec les couleurs, vous n'êtes certainement pas sans savoir que les valeurs pour le rouge, le vert et le bleu sont égales les unes aux autres. C'est exactement ce principe que je vais utiliser ici:

    Note: La seule chose qui est modifiée par rapport à l'exemple précédent, c'est dans la boucle for.

    Dans les deux exemples que je vous ai montrés, j'utilise comme fond une image, mais il est tout à fait possible d'appliquer ces transformations de pixels sur des dessins que vous auriez fait vous-mêmes. Ce que vous venez d'apprendre représente un vrai avantage de Canvas par rapport à ses concurrents, comme SVG. C'est un outil très puissant mais aussi très rapide. Vous avez aussi pu vous rendre compte que bien que nous touchions au pixels eux-même, il n'y a eu aucune perte de qualité des images. C'est dû au fait que nous avons travaillé pixel par pixel.

    II.4 Les transformations

    Avant de nous lancer à corps perdu dans les animations, il y a certains points importants à savoir sur le contexte. Actuellement nous n'avons jamais réellement joué avec le contexte. Sachez cependant que nous possédons de puissantes méthodes qui vont révolutionner votre vision de Canvas.

     

    II.4.1 Sauvegarder et restaurer notre contexte

    Jusqu'à maintenant nous avons toujours travaillé sur une version unique du contexte. Mais avec deux méthodes :   save()    et    restore().   Nous pouvons sauvegarder avec save() l'état du contexte sur lequel nous étions en train de travailler. Ensuite avec restore() nous pouvons restaurer l'état du contexte. Il suffit d'appliquer save() avant que nous ne modifions et restore() lorsque nous avons fini de travailler avec la version modifiée du contexte.

     Ce genre de méthode peut être très utile lors de la création d'animations. Par exemple, imaginons que nous voulions dessiner un moulin qui tourne, il serait intéressant de pouvoir dessiner d'abord le moulin, ensuite de dessiner les pales de ce moulin, mais il serait fastidieux de redessiner le dessin par rapport à chaque nouveau tour de boucle (c'est la boucle du temps). C'est pour ça que nous allons toujours dessiner les 4 pales de la même manière, c'est le contexte que nous allons modifier. C'est beaucoup plus rapide que de tout redéfinir manuellement.

     Je me rends bien compte que pour l'instant tout cela peut sembler un peu flou, cependant il est important que vous gardiez en tête ce que vous venez d'apprendre, nous en aurons vite besoin.

     

    II.4.2 Les transformations basiques

     Je pense que si vous devez vous remémorer vos cours sur les transformations, il y en a trois auxquelles vous devez penser:

    • rotate (angle) : la rotation ( le coin supérieur gauche de Canvas est le centre de rotation )          
    • translate( x, y)   : le déplacement du contexte
    • scale( x, y) : l'échelle du contexte (le coin supérieur gauche de Canvas ne bouge pas)

    Ces trois transformations s'appliquent uniquement sur le contexte. Ce qui veut dire que dès que vous aurez appliqué une de ces transformation, le reste de tout vos dessins en sera affecté. Je pense qu'un exemple ne serait pas de trop:

    context52.strokeStyle="red";
    context52.lineWidth=5;
    function draw() {
       context52.moveTo(
    80,10);
       context52.lineTo(10,60);
       context52.moveTo(10,40);
       context52.lineTo(10,60);

      context52.lineTo(30,60);
      context52.stroke();
      };
    draw();   
    context52.translate(
    75,0); // déplacement à droite
     context52.scale(0.5,0.5); // réduction 1/2
    draw();
    context52.scale(2,2);   // doublement de l'échelle ( retrouve taille initiale)
    context52.translate(0,75);  // déplacement vers le bas
    context52.rotate(Math.PI/180*90);  // rotation de la zone de 90° horaire
    draw();
          votre navigateur n'accepte pas Canvas

    La première flèche est affichée selon la position normale du contexte. La seconde flèche est translatée de 75 pixels dans la direction x, ensuite les dimensions du contexte sont réduites de moitié. Voilà ce que cela donne étape par étape, le fond vert représente le contexte visible dans le Canvas, les bords noirs représentent le cadre de notre Canvas:



    Note: Ce n'est pas parce qu'une partie du contexte n'est plus visible dans le cadre que celle-ci n'existe plus.

    Pour la troisième flèche, les dimensions sont d'abord multipliées par deux. Ensuite il subit une translation de 75 pixels dans la direction y avant de subir une rotation de 90°. Voici les différentes étapes:


     

    II.4.3 Les transformations matricielles

    Je vois que vous avez peur juste en lisant le mot matricielles, et bien vous avez tort. Ce sont ici simplement deux nouvelles fonctions que je vous propose. Au lieu d'être des méthodes qui ne modifient qu'une seule transformation du contexte, avec celles-ci, nous pouvons modifier l'ensemble des transformations possibles  :    transform ( a, b, c , d, e, f);        setTransform( a, b, c, d, e, f);

     Je vais d'abord vous expliquer la différence entre les deux méthodes. Quelles que soient les modifications qui ont été faites, setTransform() applique des transformations comme si aucune autre n'avait été faite avant. Quant à transform(), elle va s'appliquer sur le contexte dans l'état où il est, donc si il y a déjà eu des modifications du contexte, les transformations appliquées par transform() vont "continuer" celles déjà présents.

     Maintenant, parlons des lettres, elles représentent pour les deux méthodes la même transformation:

    • a: Change l'échelle à l'horizontale
    • b: Biaise le contexte à l'horizontale
    • c: Biaise le contexte à la verticale
    • d: Change l'échelle à la verticale
    • e: Déplace le contexte à l'horizontale
    • f: Déplace le contexte à la verticale

     Je pense qu'un exemple serait très utile car je comprends que cela soit des notions compliquées à comprendre dès la première lecture. Voici le premier exemple avec un setTransform()


    context53.fillStyle="black";
    context53.fillRect(0,0,200,150);
    context53.setTransform( 1, 0, 0, 1, 0, 0); // cache le premier !
    context53.fillStyle="blue";
    context53.fillRect(0,0,200,150);
    context53.setTransform( 1, 0, 0, 1, 20, 50); //décale +20 à droite, + 50 en bas
    context53.fillStyle=
    "red";
    context53.fillRect(0,0,200,150);
    context53.setTransform( 0.5, 0.5, 0.3, 0.2, 0, 60);
    context53.fillStyle=
    "yellow";
    context53.fillRect(0,0,200,150);


      votre navigateur n'accepte pas Canvas
    Il y a en tout 4 rectangles qui sont affichés dans cet exemple. Le premier est à la position de base cependant celui-ci n'est pas visible. Cela est du au fait que le second rectangle est par-dessus. Nous pouvons donc en tirer la conclusion que setTransform( 1, 0, 0, 1, 0, 0); est en fait le contexte de base. Le second rectangle est décalé par rapport au premier. C'est à partir du quatrième rectangle que nous nous rendons compte que setTransform(); remet le contexte dans sa forme d'origine avant d'y appliquer des transformations. Nous pouvons le voir avec le déplacement horizontal. Le contexte du troisième rectangle est déplacé de 50 pixels vers la droite et 20 vers le bas. Hors le contexte du quatrième contexte n'est pas déplacé à l'horizontale, comme nous l'indiquons dans ses attributs.

     Voici le même exemple mais où je remplace le setTransform(); par transform();, vous allez alors comprendre la différence entre ces deux méthodes:

    <canvas id ="cvs54" width ="300" height = "300">
          votre navigateur n'accepte pas Canvas
    </canvas>
    <script>
     
    var canv54 = document.getElementById('cvs54');
     var context54 = canv54.getContext('2d');
    context54.fillStyle="black";
    context54.fillRect(0,0,200,150);
    context54.transform( 1, 0, 0, 1, 0, 0);
    // cache le premier !
    context54.fillStyle=
    "blue";
    context54.fillRect(0,0,200,150);
    context54.transform( 1, 0, 0, 1, 20, 50); //décale +20 à droite, + 50 en bas
    context54.fillStyle=
    "red";
    context54.fillRect(0,0,200,150);
    context54.transform( 0.5, 0.5, 0.3, 0.2, 0, 60);
    context54.fillStyle=
    "yellow";
    context54.fillRect(0,0,200,150);
      
    </script>


      votre navigateur n'accepte pas Canvas

     Note: vous pouvez voir que je n'ai modifié aucune valeur, la seule chose qui a été modifiée est la méthode.

     À nouveau nous avons quatre rectangles. Le premier est caché par le second, nous pouvons donc en conclure que transform( 1, 0, 0, 1, 0, 0) est la matrice de base, donc aucune transformation n'est appliquées sur le contexte. Le second rectangle est lui aussi déplacé de 50 pixels vers la droite et 20 vers le bas, comme dans l'exemple précédent. Par contre, le quatrième rectangle n'est pas à la même position que dans l'exemple précédent. Puisque les modification produient par transform() s'ajoutent les unes aux autres, le quatrième rectangle est déplacé de 100 pixels vers le bas (50 + 60)  et de 20 pixels vers la droite (20 + 0).  Nous observons donc bien que toutes les transformations effectuées par transform() s'ajoutent les unes aux autres.


    II.5 Les animations

    Enfin le dénouement, voilà le moment que vous attendez tous: les animations. Inutile de vous le préciser, c'est à ce moment que Canvas dévoile vraiment tout sa puissance.

     Nous en avons fini avec les nouvelles méthodes, nous allons maintenant nous concentrer sur la mise en place de boucles pour animer notre Canvas.

     

    II.5.1 Théorie sur les animations, récupération du temps

    Une animation se passe toujours dans le même ordre:

    • Une première image est dessinée
    • Tout est effacé
    • Une nouvelle image est dessinée, légèrement modifiée par rapport à la précédente
    • Tout est effacé
    • Une nouvelle image est dessinée, légèrement modifiée par rapport à la précédente
    • Ainsi de suite

     Comme vous le voyez, le principe est assez simple, en fait il n'y aura qu'une seule chose technique et nouvelle durant ce chapitre, c'est la façon dont nous allons récupérer le temps. Actuellement, la plupart des écrans d'ordinateurs affichent une fréquence de 60 images/seconde C'est ainsi que les animations peuvent sembler fluide pour vous. Depuis quelques années, avec l'arrivée de la 3D, certains écrans peuvent monter jusqu'à 120 images/seconde, cela permet d'afficher simultanément deux images (c'est la technique utilisée pour donner une illusion de 3D). Vous avez peut être déjà entendu parler des deux méthodes suivantes :     setTimeout();     setInterval()

    Rappel: Pour utiliser setInterval(), il faut écrire setInterval(function, intervalle). Pour utiliser setTimeout() il faut utiliser  la même construction. Il ne faut pas oublier d'écrire les intervalle en ms, 1000ms = 1seconde.

     

    Ces deux méthode présentent un inconvénient important, imaginons que nous voulions dessiner plusieurs choses mais pas en même temps. Il est possible que le temps alloué pour dessiner un dessin soit coupé par le temps plus court d'un autre dessin. Ce qui implique qu'en utilisant ces fonctions, certains dessins ne seront pas dessinés par manque de temps. Il existe aujourd'hui une nouvelle méthode :    requestAnimationFrame()   Cette fonction calcule le temps qu'il faut pour dessiner un nouvel objet, du coup nous pouvons dessiner plusieurs objets, sans qu'ils soient dessinés simultanément mais pour que l'image soit fluide.

    Malheureusement cette fonction va nous poser un problème, elle n'est actuellement pas standardisée, voilà pourquoi nous allons mettre en place une petite fonction pour que la méthode soit fonctionne correctement:

    Note: L'objet window est un objet qui représente une fenêtre ouverte dans le  navigateur.

    Comme vous le voyez, j'ai mis en place une fonction de secours qui permet, dans le cas où le navigateur utilisé n'interprète pas cette fonction, d'utiliser la fonction setTimeout à une fréquence de 60 images/seconde.

     

    II.5.2 Une balle rebondissante

    Dans notre première méthode, nous allons créer une balle qui va rebondir contre les bords de notre Canvas. Le principe est assez simple il nous faut une fonction (que je nomme animate()) qui va s'occuper de dessiner la balle. Cette fonction doit effacer l'ensemble du Canvas, elle doit dessiner une balle par rapport à une position x et y (qui est le centre de la balle). Ensuite il faut vérifier si la balle n'a pas touché un des bords, si c'est le cas, il faut inverser la vitesse correspondante au bord touché.

     

    Cette animation a donc cinq variables:

    • le diamètre de la balle
    • la position x qui est au centre de la balle (donc le diamètre de la balle divisé par 2)
    • la position y qui est au centre de la balle (donc le diamètre de la balle divisé par 2)
    • la vitesse x
    • la vitesse y

    Note: J'utilise un Canvas de 300 par 150 pixels.

    II.5.3 Des courbes aléatoires

    Mon but, dans cet exemple, est de mettre en place des courbes de Bézier qui vont automatiquement se dessiner, elles devront disparaître au bout d'un certain temps et je veux que la coloration des courbes change au fil du temps. Voilà ce que vous devriez obtenir comme résultat final :

    Pour la position je crée deux variables, dernierX et dernierY qui vont toujours stocker la dernière position à laquelle est allée la courbe, comme ça la courbe va être suivi. Je mets aussi une variable pour gérer la couleur. Je vais utiliser le type de couleur hsl (expliqué au chapitre des couleurs). Cette variable sera modifiée à chaque nouveau tour de boucle.

     Je modifie le type de courbe, d'abord je modifie la méthode lineCap, pour lui mettre comme valeur round. Ainsi le bout de la courbe est plus naturel. Ensuite je modifie la taille des traits. Je mets comme taille minimum 5px, ensuite j'y ajoute un nombre aléatoire qui va jusqu'à 10.

    Pour le dessin en lui même, j'utilise le dernier point comme point de départ, ensuite je modifie ce point; je fais la longueur et la hauteur que je multiplie par un nombre aléatoire. Ensuite je trace ma courbe de bézier. Je modifie la couleur, j'applique une ombre qui part sur le noir et je termine le trait.

    Je mets ensuite une autre fonction en place. Celle-ci a pour but de diminuer petit à petit la valeur des courbes précédentes pour qu'elles disparaissent entièrement. J'applique donc une transformation de la couleur de la surface totale. La seule modification que j'effectue est que je mets une valeur alpha, pour le fond, je le fais en noir.

     Puisque j'applique une coloration de transparence sur l'ensemble du dessin, il faut que avant de dessiner ma courbe, donc au moment où j'entre dans la fonction qui la dessine, je  sauvegarde le contexte. Je restaure le contexte à la fin de cette fonction.

    Note: Dans cet exemple j'utilise deux setInterval, j'ai dit au préalable que cela posait problème car il était alors possible que certaines images ne soient pas affichées, ici c'est malheureusement le cas. Cependant, si j'avais mis deux requestAnimeFrame(), le taux de rafraichissement aurait été trop élevé, du coup l'animation aurait été trop rapide. Voilà pourquoi je décide dans ce cas précis d'utiliser deux setInterval.

    ATTENTION : vous ne pouvez pas mélanger setInterval ou setTimeout avec requestAnimeFrame(). Il est impératif de choisir une seule solution pour l'ensemble des éléments Canvas présents sur une page.

     

    II.5.4 Un système solaire

    Voici un nouvel exemple dans lequel nous allons créer un système solaire. De quoi avons nous besoin pour faire un système solaire ? Nous avons besoin d'un soleil, de planètes et de satellites. Pourquoi cet exercice est-il intéressant ? Le fait qu'il y ait un soleil, des planètes et encore des satellites nous oblige à jongler entre différents niveaux de contexte à sauvegarder.

    Vous pouvez voir que je fais quelque chose de bizarre avec le contexte et le dessin des planètes et satellites. Je ne les place pas comme ils se positionnent autour du soleil. Je les place sur un axe, je déplace ensuite le contexte de manière à ce que le coin supérieur gauche du contexte dans lequel j'ai dessiné mes objets soit au centre du cadre visible. Je fais cela car l'angle autour duquel va se produire la rotation est le coin supérieur gauche du contexte. Place maintenant à ce que vous devriez obtenir:

    Note: Je le répète, les planètes et le satellite ne sont pas placés par rapport à leur position finale ou à la position du soleil.

     Note: La variable i sera une variable qui va s'incrémenter à chaque tour, c'est avec cette variable que nous allons modifier la rotation du contexte.

    Maintenant, la fonction animate(),

    • effacement du cadre,
    • mise en place du fond noir,
    • dessin du soleil et de la première planète :

    Note: Comme vous le voyez, je multiplie la vitesse des planètes par la valeurs i, cela permet d'avoir une valeur pour l'angle.

    Note: Pour dessiner la première planète, je travaille dans un contexte différent de celui dans lequel je dessine le soleil mais je le restaure lorsque j'ai fini de dessiner la planète.

    Dessin de la seconde planète et de son satellite. Incrémentation de i et fin de la fonction animate():

    Note: J'utilise un save() alors que je n'ai pas restauré le contexte de base. Il est donc possible d'utiliser plusieurs sauvegardes et plusieurs restaurations. C'est un système qui est dit "par empilement". Ce qui veut dire que lorsque j'utilise restore(), c'est par rapport au dernier contexte qui a été sauvegardé.

     

     

     


     

    Partie III: Applications de Canvas

     

    III.1 Réalisation d'une horloge

    Voici le premier exemple d'une application de Canvas dans un vrai mini-programme. Celui-ci est une horloge où le but de canvas est uniquement d'indiquer les heures. Le travail des calculs est effectué par Javascript. Il reste que c'est un exemple intéressant car il comporte beaucoup de parties dédiées à Canvas.

     

    III.1.1 Variables et cadran

    Je met en place une seule fonction dont la tâche sera de toujours effacer le contexte et de tout redessiner dessus. Voici donc le début de ma fonction:

    function horloge(){
    var heure = new Date();
    context59.save();
    context59.clearRect( 0, 0, 300, 300);
    context59.translate( 150, 150);
    context59.rotate(-Math.PI/2);
    context59.strokeStyle = "red";
    context59.fillStyle = "white";
    context59.lineWidth = 5;
    context59.lineCap = "square";
    // il faut faire Dessin du cadran et des aiguilles
    context59.restore()
    window.requestAnimFrame(function() { horloge() } );
    } horloge();


     

     L'objet Date() rrenvoie à la valeur du temps au moment où il est créé, voilà pourquoi je recrée cette variable à chaque fois que j'appelle cette fonction.

     Lorsque je fais le dessin des aiguilles je les positionne toujours par rapport au coin supérieur gauche, voilà pourquoi je déplace le contexte au centre du cadre et j'applique une rotation de 90° dans le sens inverse des aiguilles d'une montre. J'effectue la rotation car la position de base des aiguilles et à 12:00.

     Pour le principe des barres pour les heures et les minutes, je fais un simple trait, je fais une rotation du contexte et je recommence jusqu'à avoir fait le tour complet du cadran.

    // ce code s'insère dans le code décrit ci-dessus (context59)
    context60.save(); // Marques des heures
    for(var i=0; i<12; i++){
    context60.beginPath();
    context60.rotate(Math.PI/6);
    context60.moveTo( 100, 0);
    context60.lineTo( 120, 0);
    context60.stroke();
    };
    context60.restore();
    context60.save(); // Marques des minutes
    context60.lineWidth = 3;
    for(i=0; i<60; i++){
    if(i%5!=0) {
    context60.beginPath();
    context60.moveTo( 117, 0);
    context60.lineTo( 120, 0);
    context60.stroke();
    };
    context60.rotate(Math.PI/30);
    };
    context60.restore();

    context60.beginPath();// Cadran extérieur
    context60.lineWidth = 2;
    context60.strokeStyle = "grey";
    context60.arc( 0, 0, 130, 0,Math.PI*2,true);
    context60.stroke();
          votre navigateur n'accepte pas Canvas

     

     Pour la boucle des heures, je fais la boucle tant que i est plus petit que 12. Cela car le premier trait est fait à 0, c'est la marque qui indiquera 12:00. Ensuite je fais 11 traits de plus. Ce qui au total fait 12 traits pour les heures et donc est le bon nombre.

     La boucle i > for pour les minutes repose sur le même principe que pour les heures. Je fais cependant cette fois un test à l'intérieur pour savoir si le nombre i modulo 5 n'est pas égal à 0. Si c'est le cas, cela signifie qu'il y a déjà un trait qui est dessiné, celui des heures.

     Pour les deux rotations des contextes, c'est 180 divisé par la moitié du nombre de traits à faire. Si  les deux valeurs sont doublées, alors c'est 360 divisé par 12 ou 60, c'est donc la bonne rotation.

     Le résultat que vous obtenez est celui que j'ai moi-même choisi. Cependant, libre à vous de créer votre propre horloge. Il en est de même pour les aiguilles que nous allons tout de suite dessiner.

     

    III.1.2 Le mouvement des aiguilles

    La première chose à faire, c'est d'obtenir l'heure, la minute et la seconde précise, c'est ici que nous allons utiliser l'objet Date():

    Je pense que la construction de la 4ème ligne soulève quelques questions. Je vais traduire cette ligne en français. hr est égal à hr si il n'est pas plus grand ou égal à 12, sinon il faut soustraire 12 de hr. Je fais cela car, contrairement aux minutes et aux secondes, il n'y a pas 24 traits. Du coup, dès qu'il 13:00, alors l'heure est réduite de 12, donc il ne reste que 1.

    var sec = heure.getSeconds(); // la varaible heure est définie au début du programme
    var min = heure.getMinutes();
    var hr = heure.getHours();
    hr = hr>=12 ? hr-12 : hr;
    // Aiguille des heures
    context61.save();
    context61.rotate( hr*(Math.PI/6) + min*(Math.PI/360) + sec*(Math.PI/21600) );
    context61.strokeStyle = "blue";
    context61.lineWidth = 10;
    context61.beginPath();
    context61.moveTo(-20,0);
    context61.lineTo(80,0);
    context61.stroke();
    context61.restore();
    // Aiguille des minutes
    context61.save();
    context61.rotate( min*(Math.PI/30) + sec*(Math.PI/1800) );
    context61.lineWidth = 7;
    context61.beginPath();
    context61.moveTo( -30, 0);
    context61.lineTo( 112, 0);
    context61.stroke();
    context61.restore();
    // Aiguille des secondes
    context61.save();
    context61.rotate(sec *(Math.PI/30));
    context61.strokeStyle = "black";
    context61.lineWidth = 4;
    context61.beginPath();
    context61.moveTo(-30, 0);
    context61.lineTo( 120, 0);
    context61.stroke();
    context61.restore();
          votre navigateur n'accepte pas Canvas

     

    Pour afficher la position des éguilles, 'additionne le temps qui s'est déjà écoulé en minutes et en secondes pour les heures et juste en secondes pour les minute. Je divise cependant la valeur de PI par un nombre différent qu'il y a de secondes dans une minutes et de minutes dans une heure. Pour 360 j'ai fais 6 (la moitié des heures) fois 60 (nombre de minutes dans 1 heure). Pour 21600 j'ai fais 360 (nombre de minutes dans 6 heure) fois 60 (nombre de seconde dans 1 minutes). Je pense que du coup, je n'ai pas besoin de vous expliquer d'où vient le 1800..

    III.2 Analyses de fonctions et graphiques

    Ceci est un embryon de programme. C'est juste pour vous montrer un domaine d'application un peu scientifique dans lequel Canvas peut se montrer extrêmement puissant.

     Dans cet exemple, nous permettons à l'utilisateur de donner les coefficients d'une courbe, ensuite nous la dessinons, mais nous dessinons aussi sa dérivée et sa dérivée seconde.

     Je ne vais cependant pas vous présenter du code. Je fais cela car il est long et répétitif, de plus il est d'un niveau qui peut parfois être assez complexe, voilà pourquoi je vais vous donner une présentation théorique de son fonctionnement. Je vous rappel que vous pouvez retrouver l'exemple avec le code complet.

    III.2.1 Dessin des axes et mise en place de l'interface

    La première étape est la mise en place de l'axe. Voici celui que j'utilise ( voir //Dessin de l'axe). Cet axe, bien que simple, permet de facilement représenter n'importe quelle droite ou courbe. Par ailleurs, avec les marques présentes sur les axes, il est facile pour n'importe qui de voir les valeurs. Il faudra cependant faire très attention avec cette question d'échelle. Il faudra que l'échelle pour les courbes et les droites soit la même.

    <canvas id="cvs" width="700" height="700" style="border:1px solid #9E9E9E; float:left;">
    Désolé, votre navigateur ne supporte pas Canvas. Mettez-vous à jour
    </canvas>
    <button onClick="f1+=1; MAJ();">Afficher F(x)</button> // mise en place des champs boutons
    <button onClick="f2+=1; MAJ();">Afficher F'(x)</button>
    <button onClick="f3+=1; MAJ();">Afficher F''(x)</button>
    <input type="text" value="0" id="x6">* x6 // mise en place des champs boutons
    <input type="text" value="0" id="x5">* x5
    <input type="text" value="0" id="x4">* x4
    <input type="text" value="1" id="x3">* x3
    <input type="text" value="4" id="x2">* x2
    <input type="text" value="3" id="x1">* x1
    <input type="text" value="2" id="x0">* x0
    <button onClick="MAJ();">Modifier</button>
    <script>
    var cvs = document.querySelector('#cvs');
    var ctx = cvs.getContext('2d');
    var f1=0;
    var f2=0;
    var f3=0;
    MAJ();
    function MAJ(){ // lire les valeurs contenue dans les champs texte
       x6 = document.getElementById('x6').value;
       x5 = document.getElementById('x5').value;
       x4 = document.getElementById('x4').value;
       x3 = document.getElementById('x3').value;
       x2 = document.getElementById('x2').value;
       x1 = document.getElementById('x1').value;
       x0 = document.getElementById('x0').value;
       ctx.clearRect(0, 0, cvs.width, cvs.height);
       axe();
       draw();
    }
    function axe(){   //Dessin de l'axe
      
    ctx.strokeStyle ="rgb(0,0,0)";
       ctx.beginPath();
       ctx.moveTo(0,350);
       ctx.lineTo(700,350);
       ctx.stroke();
       ctx.beginPath();
       ctx.moveTo(350,0);
       ctx.lineTo(350,700);
       ctx.stroke();
       var a = 700/20;
       for(var i = 0; i<20;i++) {
          ctx.beginPath();
          ctx.moveTo(a*i ,345);
          ctx.lineTo(a*i ,355)
          ctx.stroke();
          ctx.beginPath();
          ctx.moveTo(345 ,a*i);
          ctx.lineTo(355 ,a*i)
          ctx.stroke();
       }
    } // fin la fonction axe
    function draw(){   //Dessin de la fonction
       if(f1 > 1){  f1 = 0; }
       if(f2 > 1){  f2 = 0; }
       if(f3 > 1){  f3 = 0; }
       if(f1 == 1){  //affiche la courbe
          ctx.strokeStyle = "rgb(0, 0, 0)";
          ctx.beginPath();
          ctx.moveTo(0, 0);
          for(var x=0;x<700;x++){
             var a = (x - 350)/40;
             y = (350 - (x6*Math.pow(a,6)+x5*Math.pow(a,5)+x4*Math.pow(a,4)+x3*Math.pow(a,3)+x2*Math.pow(a,2)+x1*Math.pow(a,1)+x0*Math.pow(a,0))*40);
             ctx.lineTo(x,y);
             x = x-0.9;
          } // fin for
          ctx.stroke();
      } // fin if
       if(f2 == 1){ //affiche la 1ere dérivée de la courbe
          ctx.strokeStyle = "rgb(0, 0, 100)";
          ctx.beginPath();
          ctx.moveTo(0, 0);
          for(var x=0.0;x<700;x++){
             var a = (x - 350)/40;
             y = (350 - (x6*6*Math.pow(a,5)+x5*5*Math.pow(a,4)+x4*4*Math.pow(a,3)+x3*3*Math.pow(a,2)+x2*2*Math.pow(a,1)+x1*1)*40);
             ctx.lineTo(x,y);
             if(Math.round(y)-350 < 1){
                if(Math.round(y)-350 > -1){ ctx.moveTo(x,0);  ctx.lineTo(x,700); }
             }
             x = x -0.9;
          } // fin for
          ctx.stroke();
       } // fin if f2
       if(f3 == 1){ //affiche la seconde dérivée de la courbe
          ctx.strokeStyle = "rgb(0, 100, 0)";
          ctx.beginPath();
          ctx.moveTo(0, 0);
          for(var x=0.0;x<700;x++){
             var a = (x - 350)/40;
             y = (350 - (x6*6*5*Math.pow(a,4)+x5*5*4*Math.pow(a,3)+x4*4*3*Math.pow(a,2)+x3*3*2*Math.pow(a,1)+x2*2)*40);
             ctx.lineTo(x,y);
             if(y-350 < 1){
                if(y-350 > -1){  ctx.moveTo(x,0);  ctx.lineTo(x,700); }
             }
             x = x-0.9;
          }
          ctx.stroke();
       } // fin if f3
    } /// fin de la fonction draw
    </script>
     
    Désolé, votre navigateur ne supporte pas Canvas. Mettez-vous à jour * x6
    * x5
    * x4
    * x3
    * x2
    * x1
    * x0



     

    il faut ajouter un système de boutons ( voir // mise en place des champs boutons) et de cases (// mise en place des champs texte) pour que l'utilisateur puisse utiliser la fonction qu'il souhaite.  Ces boutons et ces champs ne sont pas dans le script, mais directement sur la page html. Les trois premiers boutons ont pour but d'afficher ou non les courbes et les dérivées. Dans le code j'utilise simplement une boucle conditionnelle à chaque fois que je veux redessiner le tout. Les sept cases qui suivent vont permettre à la personne qui utilise cette application de choisir les coefficients de xn.

     Dans mon exemple la mise à jour se fait avec le bouton "modifier". Il serait par contre, tout à fait possible de faire en sorte que la mise à jour de l'affichage se fasse dès que l'un des chiffres dans l'une des cases est modifié.

     La boucle principale, celle qui va dessiner ou non les courbes, est appelée (MAJ() ) dès que l'utilisateur appuie sur le bouton "modifier" ou sur l'une des trois premier boutons. Nous allons d'ailleurs nous attaquer maintenant à la boucle principale.

    III.2.2 Dessin d'une courbe

    Bien, nous avons déjà placé les bases avant. Nous avons une boucle principale, nous avons trois variables pour savoir si il faut dessiner ou non les courbes, ensuite nous avons sept variables qui stockent nos sept coefficients pour xn. Donc la première chose à faire dans notre boucle principal est de récupérer toutes nos variables. Une fois celle-ci récupérées, nous pouvons effectuer des tests pour savoir si il faut afficher ou non nos droites. Si c'est le cas, alors il faut dessiner.

    Pour le tracé des droites je commence toujours par le point (0,0). Pour dessiner, j'utilise une boucle de type for(). Elle va s'effectuer sur tous les x qui sont égaux à la largeur de notre canvas. Cependant, il est impossible d'utiliser la valeur de x telle quelle, il va falloir la transformer à chaque tour de boucle. Vous vous demandez peut être pourquoi il faut faire cela, c'est pour deux raisons.

    •  La première est la question de l'échelle vue auparavant. Si par exemple je choisis d'avoir 20 unités dans mon axe, il va falloir que je divise x par le double du nombre d'unités, ce qui fait 40 si vous prenez 20 unités.

    • La seconde raison est due au point de départ de la droite, rappelez-vous j'ai choisi (0,0), hors ce point ne correspond par au centre de l'axe, mais au coin supérieur gauche. Hors la première valeur de x est 0. Il faut donc soustraire à x la moitié de la largeur du canvas. Il faudra effectuer les mêmes modifications sur le point y.

    C'est ainsi que je dessine la fonction f(x). J'apporte une petite modification pour les deux dérivées. J'effectue dans une boucle un test pour savoir si la valeur de y est égale à 0. Si c'est le cas alors je dessine une droite verticale à la position x du point où y est égal à 0. Ainsi je permets à l'utilisateur de voir visuellement ce que représente les zéros des dérivées par rapport à la fonction de base. Au final, en cliquant sur le bouton "afficher F(x)",  vous pouvez visualiser la fonction x3+4x2+3x+2

    En  en cliquant sur le bouton "afficher F'(x)" ,  vous pouvez voir qu'il y a deux droites horizontales qui correspondant aux deux maximums et minimums de la fonction x3+4x2+3x+2.

    Ceci n'est pas la méthode optimal pour dessiner les fonctions, cette méthode est très limitées et il est impossible d'y inclure des racines ou des fonctions trigonométrique. Il ne faut pas oublier qu'il s'agit simplement d'une introduction et pas d'une méthode complète et optimal.

     

     

     

     

    Annexe

    A.1 Aller plus loin avec Canvas

    Maintenant faites comme moi, appliquez vos acquis pour mener à bien un projet de plus grande envergure. Il reste encore beaucoup de domaines à mettre en place avec Canvas. L'utilisation de Canvas pour créer des exemples physiques peut être quelque chose de très éducatif. Si vous êtes quelqu'un de plus artistique, cherchez un peu sur Internet, vous trouverez beaucoup d'exemples d'animations possibles avec Canvas. Ce que je vous ai montré durant ce cours n'est qu'un échantillon. Faites vos propres expériences et vos propres tests.

    Un autre domaine dans lequel vous pouvez travailler avec Canvas est la 3D. Au lieu de travailler uniquement avec Javascript, il va falloir travailler avec une API, WebGL. Cette API est tirée de la bibliothèque OpenGL. Depuis quelque temps, de vrai chefs-d'œuvre commencent à apparaître sur le net. Il y a même des jeux vidéos qui commencent à voir le jour, pour l'instant très simples.

    Il est même possible que cette façon de créer des univers 2D ou 3D pourrait remplacer l'actuel Flash. Cela pourrait changer le visage du mini-jeux sur Internet. Mais nous n'y sommes pas encore, il y a encore beaucoup à faire avec Canvas et je vous conseille de vous intéresser à cette nouvelle balise qui pourrait d'ici quelques années devenir le standard du nouveau Web.

    A.2 Mémo des fonctions acquises

    Rectangles

    Méthode

    Description

    rect( posX, posY, largeur, hauteur)

    Crée un rectangle. Le coin supérieur gauche est défini par posX et posY. Ses dimensions sont ensuite définies par les paramètres largeur et hauteur. 

    fillRect( posX, posY, largeur, hauteur)

    Dessine un rectangle plein. Le coin supérieur gauche est défini par posX et posY. Ses dimensions sont ensuite définies par les paramètres largeur et hauteur. 

    strokeRect( posX, posY, largeur, hauteur)

    Dessine uniquement les contours d'un rectangle. Le coin supérieur gauche est défini par posX et posY. Ses dimensions sont ensuite définies par les paramètres largeur et hauteur. 

    clearRect( posX, posY, largeur, hauteur)

    Nettoie une zone spécifique de Canvas avec un rectangle. Le coin supérieur gauche est défini par posX et posY. Ses dimensions sont ensuite définies par les paramètre largeur et hauteur. 

    Couleurs, Style et Ombre

    Méthode

    Description

    createLinearGradient( posX0, posY0, posX1, posY1)

    Crée un dégradé linéaire suivant une droite. Le point de départ est défini par les coordonnées posX0 et posY0. Le point d'arrivée de la droite est défini par posX1 et posY1.

    createRadialGradient( posX0, posY0, r0, posX1, posY1, r1)

    Crée un dégradé radial entre deux cercles. Le centre du premier cercle est défini par posX0 et posY0, son rayon est défini par r0. Le centre du second cercle est défini par posX1 et posY1, son rayon est défini par r1.

    addColorStop(stop, couleur)

    Ajoute une couleur à un dégradé et un endroit où elle doit s'arrêter. Le paramètre stop est une valeur entre 0 et 1 qui représente la position entre le départ et la fin du dégradé. Le paramètre couleur définit la couleur à atteindre au point.

    createPattern(image, repetition)

    Répète un élément spécifique dans une certaine direction. Le paramètre image est l'objet qui contient l'image à répéter. Le paramètre repetition  définit le mode de répétition.

    Propriété

    Description

     

    fillStyle

    Attribue la couleur pour remplir le dessin.

    strokeStyle

    Attribue la couleur pour tracer le dessin.

    shadowColor

    Attribue la couleur pour l'ombre.

    shadowBlur

    Attribue la dissipation de l'ombre.

    shadowOffsetX

    Attribue la distance horizontale de l'ombre depuis l'objet qui contient l'ombre.

    shadowOffsetY

    Attribue la distance verticale de l'ombre depuis l'objet qui contient l'ombre.

     

     

    Composition

    Propriété

    Description

    globalAlpha

    Attribue une transparence sur l'ensemble du contexte

    globalCompositionOperation

    Modifie la composition globale du contexte et définit l'ordre dans lequel les éléments sont affichés (superposition).

    Traits

    Méthode

    Description

    beginPath()

    Commence un nouveau tracé.

    moveTo( posX, posY)

    Se déplace au point donné par posX  et posY sans tracer de traits.

    lineTo(  posX, posY)

    Se déplace au point donné par posX  et posY en traçant un trait.

    arcTo( posX0, posY0, posX1, posY1, r)

    Dessine un arc de cercle entre deux droites. Le point de départ est défini par posX0 et posY0. Son point d'arrivée est défini par posX1 et posY1. Son rayon est défini par r.

    arc( posX, posY, r, angle0, angle1, sens)

    Dessine un cercle ou un arc de cercle. Son centre est défini par posX et posY. Le rayon est défini par r. L'angle de départ est défini par angle0 et celui d'arrivée par angle1. Le paramètre sens définit dans quel sens sera dessiné le cercle.

    quadraticCurveTo( pX, pY, posX, posY)

    Dessine une courbe quadratique en partant du dernier point atteint. Les paramètres pX et pY définissent le point vers lequel la courbe va tendre. Le point d'arrivée de la courbes est défini par posX et posY.

    bezierCurveTo( p0X, p0Y, p1X, p1Y, posX, posY)

    Dessine une courbe de Bézier en partant du dernier point atteint. Les paramètres p0X et p0Y définissent le première point vers lequel la courbe va tendre, le second point vers lequel la courbe va tendre est défini par p1X et p1Y. Le point d'arrivée de la courbes est défini par posX et posY.

    closePath()

    Dessine un trait entre le dernier point et le premier (permet de fermer une forme).

    fill()

    Remplit le dessin créé avec le tracé.

    stroke()

    Dessine le tracé qui a été fait.

    clip()

    Définit une seule zone dans laquelle les dessins faits seront visibles.

    isPointInPath()

    Renvoie la valeur true si le point est situé dans le tracé en cours.

    Style des traits

    Propriété

    Description

    lineCap

    Attribue le style de l'extrémité d'un trait.

    lineJoin

    Attribue le style de coin entre deux droites.

    lineWidth

    Attribue la largeur des traits.

    miterLimit

    Attribue la longueur maximum du style de coin miter.

     

     

     

    Texte

    Méthode

    Description

    fillText( texte, posX, posY, longeurMax)

    Dessine un texte plein. Le paramètre texte contient le texte à afficher. Il sera positionné par rapport à posX et posY. Le dernier paramètre est optionnel, il permet de définir la longueur maximum allouée en pixel au texte.

    strokeText( texte, posX, posY, longeurMax)

    Dessine les contours d'un texte. Le paramètre texte contient le texte à afficher. Il sera positionné par rapport à posX et posY. Le dernier paramètre est optionnel, il permet de définir la longueur maximum allouée en pixel au texte.

    measureText(texte)

    Retourne un objet qui contient la largeur du texte spécifié par le paramètre texte.

    Propriété

    Description

    font

    Attribue les propriétés pour le style de texte.

    textAlign

    Attribue l'alignement au texte.

    testBaseline

    Attribue l'alignement vertical à un texte.

     

     

     

    Image

    Méthode

    Description

    drawImage( image, coupeX, coupeY, coupeLargeur, coupeHauteur, posX, posY, largeur, hauteur)

    Dessine une image qui est donnée par le paramètre image. Le coin supérieur gauche de l'image est défini par posX et posY. Il est possible de modifier ses dimensions avec les paramètres largeur et hauteur. Il est aussi possible de ne sélectionner qu'une partie de l'image donnée en paramètre. Pour ce faire il faut définir le point de départ de l'image prise par coupeX et coupeY. Les dimensions de cette sélection sont définies par coupeLargeur et coupeHauteur.

    Transformations

    Méthode

    Description

    translate( x, y)

    Translate le contexte par rapport aux paramètres donnés par x et y.

    rotate( angle)

    Tourne le contexte selon l'angle donné par angle.

    scale( echelleX, echelleY)

    Modifie l'échelle du contexte selon echelleX et  echelleY.

    setTransform( echelleX, deviationVerticale, deviationHorizontale, echelleY, x, y)

    Remet la matrice de base du contexte avant d'appliquer les transformations comme un transform(). Une translation est effectuée par les paramètres x et y. Un changement d'échelle est fait par echelleX et echelleY. Les paramètres deviationVerticale et deviationHorizontale vont déformer le contexte.

    transform( echelleX, deviationVerticale, deviationHorizontale, echelleY, x, y)

    Applique des transformations sur le contexte. Une translation est effectuée par les paramètres x et y. Un changement d'échelle est fait par echelleX et echelleY. Les paramètres deviationVerticale et deviationHorizontale vont déformer le contexte.

    Manipulation des pixels

    Méthode

    Description

    createImageData( largeur, hauteur, imageData)

    Crée un nouvel objet ImageData vide. Elle fonctionne de deux manières différentes, soit il faut utiliser les paramètres largeur et hauteur, soit elle prend les dimensions d'un autre objet du même type donné par le paramètre imageData.

    getImageData( posX, posY, largeur, hauteur)

    Retourne un objet ImageData qui copie les pixels pour une zone spécifiée du contexte. Le coin supérieur gauche de cette zone a pour coordonnées posX et posY. Ses dimensions sont données par largeur et hauteur.

    putImageData( imageData, posX, posY)

    Applique les informations de l'objet ImageData dans le contexte. Le paramètre imageData contient l'objet dont il faut appliquer les informations. Les coordonnées du coin supérieur gauche où est appliqué l'objet sont définis par posX et posY.

    Propriété

    Description

    width

    Retourne la largeur de l'objet ImageData.

    height

    Retourne la hauteur de l'objet ImageData.

    data

    Retourne un objet qui contient les informations de l'objet ImageData.

    Méthode

    Description

    save()

    Sauvegarde l'état du contexte en cours d'utilisation.

    restore()

    Retourne la dernière version sauvegardée du contexte.

    getContext('dimension')

    Accède au contexte de l'objet Canvas. Les dimensions du contexte sont à définir par le paramètre dimension.

     

    Webographie

    Le site w3schools est un site à connaître et à visiter régulièrement. Il présente l'ensemble des des fonctions, méthodes et autres propriétés des différents langages pour le web. Il est très utile car il informe lorsqu'il y a des problèmes de compatibilité avec les différents navigateurs.

    http://www.w3schools.com/

     

    Un article de Alvaris Falcon qui présente un ensemble d'applications de canvas ou d'animations très abouties. Site en anglais mais facile à comprendre:

    http://www.hongkiat.com/blog/48-excellent-html5-demos/

     

    Le tutoriel donné ici est écrit par idsquare, il est très complet et présente des exemples faciles à comprendre. Il n'aborde malheureusement pas les animations. Le site en lui-même est très intéressant car il présente un large choix de tutoriels pour la création de sites web.

    http://www.alsacreations.com/tuto/lire/1484-introduction.html

     

    Ce tutoriel du site wikibooks présente les bases de canvas, mais malheureusement lui aussi n'aborde pas les animations.

    http://fr.wikibooks.org/wiki/Programmation_objet_et_g%C3%A9om%C3%A9trie/La_balise_canvas

     

    Voici un article du site mozilla developer network très complet sur l'utilisation des images avec Canvas.

    https://developer.mozilla.org/fr/docs/Tutoriel_canvas/Utilisation_d'images

     

    Article écrit par Seif Abaza qui donne des exemples d'utilisation poussées de Canvas.

    http://www.veolinking.com/2010/11/canvas-api-html-5-dessiner-animer-creer-des-graphiques-des-images/

     

    Le site toulibre offre un ensemble d'exemples avec le code. Il manque peut être de texte mais si les bases de Canvas sont acquises alors l'ensemble est très facile à comprendre.

    http://toulibre.org/pub/2012-02-29-rencontre/presentation/exercices/parse_html_files.php@dir=exos_01_html5%252F200_canvas&nocrypt&solution&langage=html5.html

     

    L'exemple présent sur braincracking est un exemple que je présente moi-même (j'ai apporté quelques modification à ma version) dans le chapitre sur les animations.

    http://html5demo.braincracking.org/demo/canvas.php

     

    Open Class Room anciennement le site du zero est un site qui propose énormément de tutoriels très complets sur tout ce qui touche à l'informatique. Je recommande ce site à toutes les personnes qui souhaitent commencer avec des bases solides. De plus il a une communauté très active.

    http://fr.openclassrooms.com/

     

    Le site la ferme du web propose un tutoriel sur Canvas, bien que court, il contient une page très utile avec l'ensemble des méthodes et des propriétés propres à Canvas.

    http://www.lafermeduweb.net/tutorial/l-element-html-5-canvas-p23.html

     

     

     

     

     

     

     

    titre.gif (1044 octets)

    dsdem.gif (1088 octets)