Tandis qu’il est possible d’utiliser CSS et JavaScript pour animer les images vectorielles SVG - puisqu’elles sont définies par le balisage - cette manière n’est pas efficace pour créer des animations de jeux, des scènes 3D, et autres animations graphiques généralement traitées par les langages de bas niveau tels que C++ ou Java.
<canvas>
et l’API Canvas permet de créer des images bitmap scriptées. Ce n’est pas très utile pour créer des images statiques mais plutôt pour créer des images dynamiquement, comme des animations 2D et visualisations de données en temps réel.
Il existe également une implémentation de canvas 3D, WebGL, une API qui permet de créer de véritables graphiques 3D dans le navigateur web. Nous ne l’aborderons pas dans cet article
Pour créer une scène 2D ou 3D sur une page, il faut nécessairement avoir un élément <canvas>
. Du contenu alternatif peut être mis à l’intérieur, il ne sera affiché que si le navigateur ne prend pas en charge les canvas.
<canvas width="320" height="240">
<p>Votre navigateur ne prend pas en charge canvas!</p>
</canvas>
Les attributs width
et height
sont facultatifs. Les dimensions par défaut sont de 300 pixels par 150. On peut également les mettre à jour via JavaScript.
var canvas = document.querySelector('canvas'),
width = canvas.width = window.innerWidth,
height = canvas.height = window.innerHeight;
Notez que si vous définissez les dimensions du canvas aux dimensions de la fenêtre, il est nécessaire de supprimer les margin
du <body>
pour ne pas avoir de scrollbar.
body {
margin: 0;
overflow: hidden;
}
Par défaut, le canvas n’affiche rien du tout, il faut utiliser JavaScript pour afficher du contenu à l’écran.
La taille du canvas doit être spécifié soit via les attributs HTML soit via JavaScript. En utilisant CSS pour dimensionner le canvas, le dimensionnement du canvas est effectué après que le contenu du canvas n’ait été calculé, et comme toute autre image, elle peut devenir pixelisée/déformée (puisque le canvas une fois affiché n’est plus qu’une simple image).
Pour dessiner sur le canvas, la première chose à faire est de récupérer une référence à la zone de dessin, appelé le contexte du canvas.
if(!canvas.getContext) {
return;
}
var ctx = canvas.getContext('2d');
Toutes les opérations de dessin impliqueront d’utiliser cet objet.
Au début le canvas est complètement vide, il ne s’agit que d’un rectangle transparent.
À l’intérieur de ce contexte, on peut ajouter différentes formes, comme des rectangles, lignes, cercles, etc.
Les éléments sont dessinés dans l’ordre dans lequel ils apparaissent dans le code: les premiers se trouvent en dessous des derniers.
Lorsque qu’une forme est dessinée, il est impossible de la modifier - ce ne sont plus que des pixels sur une image bitmap.
Les éléments sont dessinés par rapport à l’origine du canvas, qui est par défaut le point supérieur gauche du canvas (0,0).
La valeur de x
déplace la forme vers la droite, et la valeur de y
vers le bas.
Il n’existe pas de méthode à proprement parler pour changer la couleur de fond du canvas. Pour ce faire, on ajoute un rectangle qui recouvre toute la surface du canvas.
Exemple:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Définit la taille du canvas
canvas.width = 100;
canvas.height = 100;
// Ajoute un rectangle noir pour créer le fond
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, 100, 100);
// Dessine deux rectangles
ctx.fillStyle = 'white';
ctx.fillRect(5, 5, 50, 50);
ctx.fillStyle = 'red';
ctx.fillRect(10, 10, 50, 50);
Différentes propriétés peuvent être définies sur le contexte pour customiser la mise en forme: couleur du fond, couleur de la bordure, épaisseur du trait, etc. Une fois que les propriétés sont définies, on peut appeler les méthodes du contexte pour tracer la forme.
Pour créer une forme avec des bords arrondis, il n’existe pas de propriété border-radius
, il est nécessaire de “tricher”: on définit la propriété lineJoin = "round"
et on crée une bordure de la même couleur que le fond. JsFiddle border-radius.
Comme pour tout élément du canvas, il faut au préalable définir les propriétés du contexte (couleur, épaisser du trait…) avant de tracer la forme.
ctx.lineWidth = 5; // définit l'épaisseur du contour
ctx.fillStyle = 'rgb(0, 255, 0)'; // définit la couleur du contour
ctx.strokeStyle = 'rgb(255, 255, 255)'; // définit la couleur du fond
Dessiner un rectangle plein
Pour dessiner un rectangle, on peut utiliser la méthode fillRect(x, y, width, height)
pour tracer le rectangle directement, ou alors le définir dans un premier temps avec rect(x, y, width, height)
avant de le tracer avec fill()
.
ctx.fillRect(25, 25, 100, 100);
ctx.rect(25, 25, 100, 100);
ctx.fill();
Dessiner les contours d’un rectangle
Même principe que pour un rectangle plein mais en appelant stroke
plutôt que fill
.
ctx.strokeRect(25, 25, 100, 100);
ctx.rect(25, 25, 100, 100);
ctx.stroke();
Dessiner un rectangle plein avec des contours
ctx.strokeRect(25, 25, 100, 100);
ctx.fillRect(25, 25, 100, 100);
ctx.rect(25, 25, 100, 100);
ctx.stroke();
ctx.fill();
On peut dessiner des lignes droites et/ou courbes.
Pour ce faire, on a plusieurs méthodes qui permettent de spécifier où déplacer le stylo sur le canvas.
Les méthodes utiles pour tracer des lignes droites:
Méthode | Description |
---|---|
beginPath() |
Commence un nouveau chemin au point où se situe le stylo sur le canvas. Sur un nouveau canvas, le stylo commence au point (0, 0). |
moveTo() |
Déplace le stylo à un point différent sur le canvas, sans tracer de ligne - le stylo “saute” simplement vers une nouvelle position. |
lineTo() |
Ajoute une ligne droite qui part de la position actuelle du stylo et va aux coordonnées spécifiées - le stylo est déplacé vers cette nouvelle position. |
closePath() |
Ajoute une ligne droite qui part de la position actuelle du stylo et va au point de départ du chemin en cours. |
Une fois que le chemin est spécifié, alors on peut alors tracer le trait avec stroke()
et/ou remplir la forme avec fill()
.
Exemple:
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Définit la taille du canvas
canvas.width = 100;
canvas.height = 100;
// Ajoute un fond
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, 100, 100);
// Dessine une triangle
ctx.beginPath(); // ouvre un nouveau chemin
ctx.moveTo(10,10); // définit le point de départ du chemin
ctx.lineTo(100,10); // ajoute la 1ère ligne droite
ctx.lineTo(60,60); // ajoute la 2ème ligne droite
ctx.closePath(); // ferme le triangle (ajoute la 3ème ligne droite)
ctx.fillStyle = "lightblue";
ctx.fill(); // remplit la forme
Pour dessiner des lignes courbes, plutôt que lineTo()
, on a le choix entre deux méthodes:
quadraticCurveTo()
, pour des courbes de Bézier cubiques, ou bezierCurveTo()
, pour ces courbes de Bézier quadratiques.
Une courbe de Bézier quadratique a un point de départ, un point d’arrivée et seulement un point de contrôle.
ctx.quadraticCurveTo(cp1x, cp1y, x, y)
cp1x, cp1y
x, y
Une courbe de Bézier cubique a un point de départ, un point d’arrivée et deux points de contrôle.
ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
cp1x, cp1y
cp2x, cp2y
x, y
Exemple:
ctx.beginPath();
ctx.strokeStyle = "white";
ctx.lineWidth = 3;
var left = 5,
top = 10,
right = left + 50,
bottom = top + 80;
ctx.moveTo(left, top);
// Origine: (left, top)
ctx.bezierCurveTo(right, top, left, bottom, right, bottom);
// Point de controle 1 : courbe (right, top)
// Point de controle 2 : courbe (left, bottom)
// Destination : (right, bottom)
ctx.stroke();
ctx.closePath();
Pour tracer des cercles ou des arcs de cercle, on utilise la méthode arc()
. Cette méthode prend 6 paramètres:
arc(x, y, rayon, angle_debut, angle_fin, sens_antihoraire)
Paramètres | Description |
---|---|
x, y |
Position du centre du cercle |
rayon |
Rayon du cercle |
angle_debut, angle_fin |
Angles de début et de fin, en radians, pour dessiner l’arc (donc des angles de 0 et 360 degrés donnent un cercle fermé) |
sens_antihoraire |
Définit si le cercle doit être dessiné dans le sens des aiguilles d’une montre ou dans le sens inverse (false pour le sens horaire) |
Exemple:
Dessine un cercle complet, de rayon 40 pixels:
ctx.beginPath();
ctx.arc(50, 50, 40, degToRad(0), degToRad(360), false);
ctx.fillStyle = "lightblue";
ctx.fill();
Dessine un Pacman, de rayon 50 pixels, aux coordonnées (200,106):
ctx.beginPath();
ctx.arc(50, 50, 40, degToRad(-45), degToRad(45), true);
ctx.lineTo(50, 50);
ctx.fillStyle = 'yellow';
ctx.fill();
Fonction degToRad:
La fonction degToRead
est utilisée pour convertir une valeur en degrés vers une valeur en radians. Chaque fois que devez fournir une valeur d’angle en JavaScript, ce sera presque toujours en radians - mais les humains pensent généralement en degrés.
function degToRad(degrees) {
return degrees * Math.PI / 180;
}
Il existe deux méthodes pour dessiner du texte: fillText()
pour dessiner un texte rempli, strokeText()
pour dessiner un contour de texte. Toutes deux prennent trois paramètres:
fillText(text, x, y)
Par défaut, les coordonnées (x,y) définissent la position du coin inférieur gauche de la zone de texte. Il est possible de modifier ce comportement grâce aux propriétés textAlign
(pour l’alignement horizontal) et textBaseline
(pour l’alignement vertical). La police et la taille du texte peuvent être définies avec la propriété font
(même format que la propriété CSS font
).
Exemple:
Dessiner le contour du texte:
ctx.strokeStyle = 'white';
ctx.lineWidth = 1;
ctx.font = '36px arial';
ctx.strokeText('Canvas text', 50, 50);
Dessiner un texte rempli:
ctx.fillStyle = 'white';
ctx.font = '36px georgia';
ctx.fillText('Text', 10, 36);
Modifier l’alignement du texte:
ctx.fillStyle = 'white';
ctx.font = '36px sans';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.fillText('Text', 50, 10);
Il est possible d’inclure une image externe dans un canvas. Pour ce faire, on doit au préalable récupérer un élément HTMLImageElement
: soit on sélectionne une image présente dans la page (balise img
), soit on la charge dynamiquement avec le constructeur Image()
.
var image = new Image();
image.src = 'firefox.png';
Une fois l’image chargée, elle peut être ajoutée au canvas avec drawImage()
.
Cette méthode peut prendre 3 arguments ou 9.
Il faut donner au minimum trois paramètres: l’image et les coordonnées (x,y) du coin supérieur gauche de l’image.
drawImage(resource, x, y)
image.onload = function() {
ctx.drawImage(image, 50, 50);
}
La version complète permet en plus de tronquer et redimensionner l’image. Elle prend 9 paramètres:
drawImage(resource, sx, sy, sWidth, sHeight, x, y, width, height)
Paramètres | Description |
---|---|
resource |
L’élément HTMLImageElement |
sx, sy |
Les coordonnées à partir d’où découper l’image, relativement au coin supérieur gauche de l’image d’origine. Tout ce qui est à gauche de sx ou au-dessus de sy ne sera pas dessiné. |
sWidth, sHeight |
La largeur et la hauteur de l’image que l’on veut découper, à partir du coin supérieur gauche de la découpe. |
x, y |
Les coordonnées de l’image sur le canvas, relativement au coin supérieur gauche du canvas. |
width, height |
La largeur et hauteur affichée de l’image. En spécifiant des dimensions différentes de sx, sy , l’image est redimensionnée/déformée. |
Exemple:
ctx.drawImage(
image,
20, 20, // couper 20 pixels à gauche et 20 pixels en haut
185, 175, // dimensions de la découpe
50, 50, // position sur le canvas
185, 175 // dimensions affichée (en l'occurence, identique à l'origine)
);
L’objet Path2D permet de garder en mémoire des instructions de dessin, ce qui permet de factoriser le code. Disponible dans les navigateurs récents.
var shape = new Path2D();
shape.rect(10, 10, 50, 50);
Path2D permet également d’utiliser des trajets SVG sur le canvas.
var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
Exemple:
// Définit une forme
var shape = new Path2D();
shape.rect(5, 5, 50, 50);
// Dessine la forme en blanc
ctx.fillStyle = 'white';
ctx.fill(shape);
// Déplace l'origine du canvas et dessine la forme en rouge
ctx.translate(5, 5);
ctx.fillStyle = 'red';
ctx.fill(shape);
La propriété ctx.fillStyle
est utilisée pour définir la couleur de fond en cours.
Tous les éléments ajoutés sur le canvas (des rectangles, des cercles, etc) prendrons cette couleur pour couleur de fond.
Les valeurs de couleur acceptées sont les mêmes qu’en CSS (nom de couleur, rgb, rgba…).
Ainsi, il est possible de rendre un canvas semi-transparent en utilisant des couleurs semi-transparentes:
ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';
Il est possible de créer des gradients et d’affecter cet objet aux propriétés fillStyle
ou strokeStyle
(cf createLinearGradient()
).
Outre la couleur de fond, on peut définir la couleur de trait en cours avec ctx.strokeStyle
.
Même principe que fillStyle
sauf que strokeStyle
définit la couleur du contour de l’élément et non de la couleur de remplissage.
ctx.strokeStyle = 'rgb(255, 255, 255)';
Par défaut, l’épaisseur de trait est de 1 pixel. On peut le rendre plus épais en spécifiant le nombre de pixels du trait via la propriété ctx.lineWidth
.
ctx.lineWidth = 5;
La propriété lineCap
définit comment les extrêmités de chaque ligne sont dessinées.
Il y a trois valeurs possibles:
butt
(par défaut): L’extrémité des lignes est droitround
: L’extrémité des lignes est arrondisquare
: L’extremité des lignes en droit, en ajoutant une extension d’une largeur égale à la ligne et une hauteur égale à la moitié de la largeur de la lignectx.lineCap = "round";
La propriété lineJoin
définit comment deux segments (lignes, arcs ou courbes) sont joints ensemble.
lineJoin
n’a pas d’effet si les deux segments connectés ont la même direction, parce qu’aucune zone de jointure ne sera ajoutée dans ce cas.
Il existe trois valeurs possibles:
round
: Arrondit les angles. Le rayon de ces angles arrondis est égal à la moitié de la largeur du traitbevel
: Ajoute un triangle à l’extérmité des segments connectésmiter
(par défaut): Les segments connectés sont reliés en prolongeant leurs bords extérieurs pour se connecter en un seul point, avec pour effet de remplir une zone supplémentaire en forme de losange.ctx.lineJoin = "round";
Pour les jointures de type miter
, il est possible de spécifier la longueur maximale du bord extérieur ajouté avec la propriété miterLimit
. Plus l’angle est aigu, plus la distance est elevée. La valeur par défaut est 10. Au-delà de cette valeur, une jointure en biseau (bevel
) sera affichée à la place.
La méthode setLineDash()
accepte une liste de nombres qui spécifie les distances pour dessiner alternativement une ligne et un espace.
La propriété lineDashOffset
définit un décalage pour commencer le motif.
ctx.setLineDash([4, 2]);
ctx.lineDashOffset = 2;
Il existe 4 méthodes pour créer une ombre
shadowOffsetX
: spécifie la distance horizontale sur laquelle l’ombre doit s’étendre à partir de l’objetshadowOffsetY
: spécifie la distance verticale sur laquelle l’ombre doit s’étendre à partir de l’objetshadowBlur
: spécifie la taille de l’effet de floutageshadowColor
: spécifie la couleur de l’ombreExemple:
ctx.shadowOffsetX = 5;
ctx.shadowOffsetY = 5;
ctx.shadowBlur = 2;
ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
ctx.font = '36px sans';
ctx.fillStyle = 'black';
ctx.fillText('Text', 10, 36);
Il est possible de spécifier le type d’opération de composition à appliquer lorsqu’on dessine de nouvelles formes. Par défaut, on dessine les formes par-dessus le contenu existant. Il est possible d’effectuer des multiplications, des soustractions, sur le même principe que les layers Gimp.
Remplit le chemin en cours avec le style définit par ctx.fillStyle
.
Quand on essaie de remplir un chemin qui n’est pas fermé, la navigateur ajoute une ligne droite entre le début et la fin du chemin et remplit la forme créée (n’affecte pas ctx.stroke()
).
Exemple:
ctx.beginPath();
ctx.moveTo(5,5);
ctx.lineTo(90,20);
ctx.lineTo(60,60);
ctx.lineWidth = 5;
ctx.strokeStyle = "red";
ctx.fillStyle = "lightblue";
ctx.fill();
ctx.stroke();
Il est possible de spécifier l’algorithme à utiliser pour déterminer si un point est à l’intérieur ou à l’extérieur du chemin:
"nonzero"
: utiliser la règle de remplissage extérieur/intérieur non nul - par défaut (à gauche).
Le nombre de croisements d’une ligne correspond au nombre total de fois où une ligne croise une partie du tracé allant de gauche à droite moins le nombre total de fois où une ligne croise une partie du tracé allant de droite à gauche.
Si une ligne tracée dans une direction quelconque à partir du point possède un nombre de croisements égal à zéro, le point est à l’extérieur, sinon, il est à l’intérieur.
"evenodd"
: utiliser la règle de remplissage pair/impair (à droite).
Si une ligne tracée depuis un point et dans une direction quelconque croise le tracé selon un nombre impair, le point est à l’intérieur, dans le cas contraire, le point est à l’extérieur.
Exemple:
var shape = new Path2D();
shape.moveTo(96.50,50.00);
shape.bezierCurveTo(96.50,62.84,0.22,99.82,50.74,47.17);
shape.bezierCurveTo(100.18,0.58,62.84,96.50,50.00,96.50);
shape.bezierCurveTo(24.32,96.50,3.50,75.68,3.50,50.00);
shape.bezierCurveTo(3.50,24.32,24.32,3.50,50.00,3.50);
shape.bezierCurveTo(75.68,3.50,96.50,24.32,96.50,50.00);
// Nonzero en bleu clair
ctx.lineWidth = 2;
ctx.fillStyle = "lightblue";
ctx.fill(shape, "nonzero");
ctx.stroke(shape);
// Evenodd en rouge clair
ctx.translate(100, 0);
ctx.fillStyle = "lightcoral";
ctx.fill(shape, "evenodd");
ctx.stroke(shape);
Remplit le chemin en cours avec le style définit par ctx.strokeStyle
et l’épaisseur de trait définit par ctx.lineWidth
.
ctx.rect(75, 75, 100, 100);
ctx.lineWidth = 5;
ctx.strokeStyle = 'rgb(255, 0, 0)';
ctx.stroke();
On peut utiliser la méthode clip()
à la place de closePath()
.
Cela a pour effet de créer, non pas une forme, mais un détourage: toutes les formes qui seront ajoutées par la suite au canvas seront tronquées, limitées à l’intérieur du détourage.
Exemple:
// Définit un clip: tout ce qui suit est limité à un cercle
ctx.beginPath();
ctx.arc(50,50,40, degToRad(0), degToRad(360), false);
ctx.clip();
// Dessine un rectangle rouge
ctx.fillStyle = "red";
ctx.fillRect(0,0,100,100);
// Dessine un rectangle blanc
ctx.fillStyle = "white";
ctx.fillRect(0,0,50,100);
NB Le détourage fait bien partie de l’état du canvas, il est donc sauvegardé par save()
.
Il est possible d’utiliser un gradient comme couleur de remplissage.
Pour ce faire, il faut
créer un nouveau gradient, linéaire ou radial:
createLinearGradient(x1, y1, x2, y2)
pour créer un dégradé linéaire.
x1, y1
est le point de départ du gradient,
x2, y2
est le point d’arrivée
createRadialGradient(x1, y1, r1, x2, y2, r2)
pour créer un dégradé radial.
x1,y1,r1
est le premier cercle - de coordonnées (x1,y1) et rayon r1,
x2,y2,r2
est le deuxième cercle
assigner des couleurs avec gradient.addColorStop(position, color)
.
Chaque appel à addColorStop
ajoute une nouvelle couleur au gradient. On définit la position de la couleur entre 0 (le début du gradient) et 1 (la fin du gradient).
Exemple:
Gradient linéaire:
var gradient = ctx.createLinearGradient(0,0,200,0);
gradient.addColorStop(0, "green");
gradient.addColorStop(1, "white");
ctx.fillStyle = gradient;
ctx.fillRect(10,10,200,100);
Gradient radial:
var gradient = ctx.createRadialGradient(100, 100, 50, 100, 100, 100);
gradient.addColorStop(0, 'white');
gradient.addColorStop(1, 'green');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 200, 200);
Autre gradient radial:
var gradient = ctx.createRadialGradient(45, 45, 30, 52, 50, 50);
gradient.addColorStop(0, '#A7D30C');
gradient.addColorStop(0.9, '#019F62');
gradient.addColorStop(1, 'rgba(1, 159, 98, 0)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 150, 150);
Il est également possible d’utiliser une image comme remplissage.
Pour ce faire, créer un motif avec createPattern(image, repeat)
.
Exemple:
var img = new Image();
img.src = 'https://gist.githubusercontent.com/a-mt/372caa0b4114d22ac2fca4c52aeaff4e/raw/ccb6b5562bafd61cbf57f8eed5502ae3cea6f32d/index.png';
img.onload = function() {
var pattern = ctx.createPattern(img, 'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, 200, 100);
};
Par défaut, l’origine des coordonnées se situe au coin supérieur gauche du canvas (0,0).
Il est possible de déplacer l’origine des coordonnées, par exemple pour le mettre au centre du canvas:
ctx.translate(width/2, height/2);
Cette fonction est particulièrement utile lorsqu’on ajoute plusieurs formes identiques, plutôt que de modifier les coordonnées de la forme, on modifie l’origine du repère.
ctx.fillRect(20,20,50,50); // rectangle 1
ctx.translate(30,30);
ctx.fillRect(20,20,50,50); // rectangle 2, en décalage de (30,30) pixels par rapport au premier
La fonction rotate()
permet de faire pivoter le canvas. Elle prend un angle de rotation horaire (en radians) en paramètre. Utiliser des angles négatifs pour un sens anti-horaire.
ctx.rotate(45 * Math.PI / 180);
Le centre de la rotation est l’origine du canvas. Pour changer le centre, il faut déplacer l’origine du canvas.
scale(x,y)
permet d’augmenter ou diminuer les unités de la grille du canvas. Les valeurs inférieures à 1.0 réduisent la taille (0.5 = moitié de la taille) et les valeurs supérieures à 1.0 augmentent la taille (2.0 = double de la taille), tandis que la valeur 1.0 laisse le canvas à la même taille.
En utilisant des nombres négatifs, on peut réaliser une mise en miroir d’un axe.
ctx.scale(1, -1);
ctx.font = '48px serif';
ctx.fillText('Hello World', 0, 0);
ctx.scale(-1, 1);
ctx.font = '48px serif';
ctx.fillText('Hello World', -width, 48);
setTransform()
permet d’appliquer une matrice de transformation au canvas.
La matrice de transformation est décrite par
// Matrice par défaut
ctx.fillStyle = "green";
ctx.setTransform(1,0,0,1,0,0);
ctx.fillRect(0,0,100,100);
// Skew
ctx.fillStyle = "red";
ctx.setTransform(1,1,0,1,0,0);
ctx.fillRect(0,0,100,100);
resetTransform()
réinitialise la transformation en cours à la matrice identité.
C’est un raccourci pour setTransform(1, 0, 0, 1, 0, 0)
.
La méthode save()
permet de sauvegarder l’état du canvas dans sa globalité. Sont sauvegardés:
La méthode restore()
restore la sauvegarde la plus récente du canvas.
La méthode ctx.clearRect()
permet d’effacer le canvas. Elle prend quatre paramètres:
clearRect(x,y,width,height)
Paramètres | Description |
---|---|
x,y |
Coordonnées du coin supérieur gauche de la zone à effacer |
width,height |
Largeur et hauteur de la zone |
Cette méthode va effacer la zone spécifiée (tout, y compris l’arrière-plan). Ou on peut utiliser ctx.fillRect()
.
L’objet ImageData permet de lire et écrire le canvas pour manipuler les pixels un par un.
La méthode getImageData(x,y,width,height)
permet de récupérer un ImageData et putImageData(imageData,x,y)
d’appliquer un ImageData au canvas.
Exemple:
Récupérer la couleur du canvas à un endroit donné:
var pixel = ctx.getImageData(x, y, 1, 1),
data = pixel.data,
rgba = 'rgba('
+ data[0] + ', '
+ data[1] + ', '
+ data[2] + ', '
+ (data[3] / 255)
+ ')';
Inverser les couleurs du canvas:
var imageData = ctx.getImageData(0, 0, width, height),
data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // rouge
data[i + 1] = 255 - data[i + 1]; // vert
data[i + 2] = 255 - data[i + 2]; // bleu
}
ctx.putImageData(imageData, 0, 0);
Mettre en niveau de gris:
var imageData = ctx.getImageData(0, 0, width, height),
data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
var moy = (data[i] + data[i + 1] + data[i + 2]) / 3;
data[i] = moy; // rouge
data[i + 1] = moy; // vert
data[i + 2] = moy; // bleu
}
ctx.putImageData(imageData, 0, 0);
La méthode toDataURL()
du canvas (et non du contexte) prend un type MIME en paramètre (image/png
si omis) et retourne l’image dans le format spécifié (URI).
Pour une image jpeg, il est possible de préciser la qualité de l’image (entre 0 et 1) en deuxième paramètre.
L’uri retournée peut être utilisée pour créer un élément image dans la page, ou ouvrir l’image dans un nouvel onglet.
var uri = canvas.toDataURL(),
img = document.createElement('img');
img.src = uri;
document.body.appendChild(img);
La fonction window.requestAnimationFrame()
prend en paramètre une fonction qui sera exécutée dès que le navigateur est prêt. Si votre fonction de callback met à jour le canvas puis appelle de nouveau window.requestAnimationFrame()
, et ce continuellement, le résultat obtenu est une animation fluide et agréable pour l’oeil humain - avec un taux de rafraichissement idéal de 60 images par seconde.
Le navigateur s’occupe des détails complexes tels qu’exécuter l’animation à une vitesse constante, et ne pas gaspiller de ressources en animant des choses qui ne sont pas visibles.
function loop() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.25)';
ctx.fillRect(0, 0, width, height);
while(balls.length < 25) {
var ball = new Ball();
balls.push(ball);
}
for(i = 0; i < balls.length; i++) {
balls[i].draw();
balls[i].update();
balls[i].collisionDetect();
}
requestAnimationFrame(loop);
}
loop();
Voir exemple Canvas 2D de balles rebondissantes
Une fois que le canvas est dessiné, il est impossible modifier les formes existantes. Pour modifier le canvas, il nécessaire d’effacer et de redessiner, soit en effaçant tout, soit en effaçant la zone minimale nécessaire (en gardant du code pour).
Pour des scènes complexes, on peut empiler plusieurs canvas positionnés en absolu et utiliser les canvas comme des calques - un canvas pour le fond, un pour le menu, un pour le jeu à proprement parler…
La boucle s’arrête lorsque vous vous arrêtez d’appeler window.requestAnimationFrame()
ou si vous appelez window.cancelAnimationFrame()
avant que votre fonction de callback n’ait été exécutée. C’est une bonne pratique de le faire, pour s’assurer qu’aucune mise à jour n’attend d’être exécutée.
Pour aller plus loin: 31 days of Canvas tutorials