À propos de ce cours
Chapitre 15 — Animations et graphismes avec Canvas · 15.2 Dessiner des graphismes avec l'API <canvas>
• créer une zone de dessin et obtenir son contexte 2D ;
• dessiner des rectangles, des chemins, des cercles et du texte ;
• utiliser couleurs, dégradés, ombres et images ;
• déplacer et faire tourner le repère avec
save, translate, rotate et restore. 1. La balise canvas
<canvas> est une zone de pixels dans laquelle JavaScript dessine. Contrairement au HTML ou au SVG, ce qu'on dessine
n'est pas un élément de la page : ce sont des pixels « peints ». Le canvas ne se souvient pas des formes, seulement de la couleur des pixels.
<canvas id="dessin" width="600" height="300"></canvas>
<script>
const canvas = document.querySelector("#dessin");
const ctx = canvas.getContext("2d"); // l'objet qui contient tous les outils de dessin
</script>
Donnez la taille avec les attributs
width et height (nombre de pixels), pas seulement en CSS.
Si le CSS impose une autre taille, le dessin est étiré et devient flou.
Figure 1 — Le repère du canvas et les angles de arc().
2. Rectangles et couleurs
📄 l2_rectangles.html
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"></head>
<body>
<canvas id="dessin" width="600" height="300" style="border: 1px solid #ccc"></canvas>
<script>
const canvas = document.querySelector("#dessin");
const ctx = canvas.getContext("2d"); // le « pinceau » 2D
// Rectangle plein : fillRect(x, y, largeur, hauteur)
ctx.fillStyle = "#1565c0";
ctx.fillRect(30, 30, 160, 100);
// Rectangle contour
ctx.strokeStyle = "#c62828";
ctx.lineWidth = 6;
ctx.strokeRect(230, 30, 160, 100);
// Couleur semi-transparente qui chevauche
ctx.fillStyle = "rgba(46, 125, 50, 0.6)";
ctx.fillRect(130, 90, 160, 100);
// Gommer une zone : clearRect
ctx.fillStyle = "#f9a825";
ctx.fillRect(430, 30, 140, 140);
ctx.clearRect(470, 70, 60, 60);
// Repères : l'origine (0, 0) est en HAUT à GAUCHE
ctx.fillStyle = "#000";
ctx.font = "14px sans-serif";
ctx.fillText("(0, 0)", 4, 16);
ctx.fillText("(30, 30)", 30, 150);
</script>
</body>
</html>

Résultat dans le navigateur
fillStyle et strokeStyle acceptent toutes les couleurs CSS : "red", "#1565c0", "rgba(…)", "hsl(…)". Ce sont des réglages du « pinceau » : ils restent actifs pour tous les dessins suivants.
3. Les chemins : lignes, triangles, cercles
Toute autre forme se dessine en chemin: beginPath() commence un nouveau tracé, moveTo lève le crayon,
lineTo trace un segment, arc un arc de cercle, puis fill() remplit et/ou stroke() trace le contour.
📄 l2_chemins.html
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"></head>
<body>
<canvas id="dessin" width="600" height="300" style="border: 1px solid #ccc"></canvas>
<script>
const ctx = document.querySelector("#dessin").getContext("2d");
// 1. Un triangle : beginPath → moveTo → lineTo… → closePath → fill/stroke
ctx.beginPath();
ctx.moveTo(40, 250);
ctx.lineTo(140, 60);
ctx.lineTo(240, 250);
ctx.closePath();
ctx.fillStyle = "#ffe082";
ctx.fill();
ctx.lineWidth = 4;
ctx.strokeStyle = "#ef6c00";
ctx.stroke();
// 2. Un visage : arc(x, y, rayon, angleDébut, angleFin) — angles en RADIANS
ctx.beginPath();
ctx.arc(420, 150, 110, 0, Math.PI * 2); // cercle complet = 2π
ctx.fillStyle = "#fff59d";
ctx.fill();
ctx.stroke();
ctx.fillStyle = "#263238"; // les yeux
for (const x of [380, 460]) {
ctx.beginPath();
ctx.arc(x, 120, 12, 0, Math.PI * 2);
ctx.fill();
}
ctx.beginPath(); // le sourire : demi-cercle
ctx.arc(420, 160, 60, 0.15 * Math.PI, 0.85 * Math.PI);
ctx.lineWidth = 6;
ctx.lineCap = "round";
ctx.stroke();
</script>
</body>
</html>

Résultat dans le navigateur
Oublier
beginPath() est l'erreur n° 1 : le nouveau tracé s'ajoute à l'ancien, et le prochain fill() recolore tout.4. Dégradés, ombres et texte
📄 l2_styles.html
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"></head>
<body>
<canvas id="dessin" width="600" height="300" style="border: 1px solid #ccc"></canvas>
<script>
const ctx = document.querySelector("#dessin").getContext("2d");
// Dégradé linéaire : le ciel
const ciel = ctx.createLinearGradient(0, 0, 0, 300);
ciel.addColorStop(0, "#0d47a1");
ciel.addColorStop(1, "#90caf9");
ctx.fillStyle = ciel;
ctx.fillRect(0, 0, 600, 300);
// Dégradé radial : le soleil
const soleil = ctx.createRadialGradient(480, 80, 5, 480, 80, 60);
soleil.addColorStop(0, "#fffde7");
soleil.addColorStop(1, "#ffb300");
ctx.fillStyle = soleil;
ctx.beginPath();
ctx.arc(480, 80, 60, 0, Math.PI * 2);
ctx.fill();
// Texte avec ombre
ctx.shadowColor = "rgba(0, 0, 0, 0.5)";
ctx.shadowBlur = 8;
ctx.shadowOffsetX = 3;
ctx.shadowOffsetY = 3;
ctx.font = "bold 44px sans-serif";
ctx.fillStyle = "#fff";
ctx.textAlign = "center";
ctx.fillText("Bonjour Canvas", 300, 180);
// Texte en contour, sans ombre
ctx.shadowColor = "transparent";
ctx.font = "24px sans-serif";
ctx.strokeStyle = "#fff";
ctx.lineWidth = 1;
ctx.strokeText("dégradés, ombres et texte", 300, 230);
</script>
</body>
</html>

Résultat dans le navigateur
5. Images
drawImage dessine une image (ou une vidéo, ou un autre canvas), à sa taille, redimensionnée, ou en découpant une partie :
📄 l2_image.html
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"></head>
<body>
<canvas id="dessin" width="600" height="300" style="border: 1px solid #ccc"></canvas>
<script>
const ctx = document.querySelector("#dessin").getContext("2d");
const img = new Image();
img.src = "fusee.svg"; // n'importe quelle image : .png, .jpg, .svg…
// On ne peut dessiner l'image qu'APRÈS son chargement (asynchrone !)
img.addEventListener("load", () => {
ctx.drawImage(img, 20, 50); // taille d'origine
ctx.drawImage(img, 180, 50, 200, 200); // redimensionnée
ctx.drawImage(img, 0, 0, 50, 50, // découpe : zone source…
420, 50, 150, 150); // …affichée agrandie
});
</script>
</body>
</html>

Résultat dans le navigateur
Le chargement d'une image est asynchrone: dessiner avant l'événement load ne donne rien.
6. Transformer le repère
Plutôt que de calculer la position de chaque pétale avec du sinus et du cosinus, on déplace et on fait tourner
le repère, puis on dessine toujours la même forme. save() et restore() mémorisent puis rétablissent l'état du pinceau
(repère, couleurs, épaisseur…).
📄 l2_transformations.html
<!DOCTYPE html>
<html lang="fr">
<head><meta charset="UTF-8"></head>
<body>
<canvas id="dessin" width="600" height="300" style="border: 1px solid #ccc"></canvas>
<script>
const ctx = document.querySelector("#dessin").getContext("2d");
// Dessine UN pétale autour de l'origine actuelle
function petale(couleur) {
ctx.beginPath();
ctx.ellipse(0, -45, 18, 40, 0, 0, Math.PI * 2);
ctx.fillStyle = couleur;
ctx.fill();
}
function fleur(x, y, nbPetales, couleur) {
ctx.save(); // mémorise l'état (origine, rotation, couleurs…)
ctx.translate(x, y); // déplace l'origine au centre de la fleur
for (let i = 0; i < nbPetales; i++) {
petale(couleur);
ctx.rotate((Math.PI * 2) / nbPetales); // tourne le repère
}
ctx.beginPath();
ctx.arc(0, 0, 16, 0, Math.PI * 2);
ctx.fillStyle = "#ffca28";
ctx.fill();
ctx.restore(); // revient à l'état mémorisé
}
fleur(110, 150, 6, "#e91e63");
fleur(300, 150, 8, "#7e57c2");
fleur(490, 150, 12, "#26a69a");
</script>
</body>
</html>

Résultat dans le navigateur
•
canvas.getContext("2d") donne le pinceau ; origine en haut à gauche, y vers le bas.• Rectangles :
fillRect, strokeRect, clearRect. • Autres formes :
beginPath → moveTo/lineTo/arc → fill/stroke. Angles en radians.• Styles :
fillStyle, dégradés, shadow…, font + fillText. •
drawImage après le chargement ; save/translate/rotate/restore pour transformer.🛠 Activité 2 — Dessiner un paysage
Mission : Dessinez sur un canvas de 800 × 500 un paysage : ciel en dégradé, soleil, montagnes, une maison (murs, toit, porte, fenêtres), trois arbres et un titre.
Questions pour avancer (répondez dans votre compte rendu, puis appliquez dans votre projet) :
- Faites d'abord un croquis sur papier quadrillé avec les coordonnées des éléments principaux. Où se trouve le point (0, 0) ?
- Quelles méthodes utilisez-vous pour le toit (triangle) ? Et pour le soleil ? Comment dessiner un demi-soleil qui se couche derrière une montagne ?
- Écrivez une fonction
arbre(x, y, taille)qui dessine un arbre complet, et appelez-la trois fois. Pourquoi est-ce mieux que de recopier le code ? - Votre maison doit pouvoir être dessinée ailleurs et plus grande. Utilisez
translateetscaleplutôt que de recalculer toutes les coordonnées. Pourquoi faut-ilsaveetrestore? - Dessinez 100 étoiles à des positions aléatoires dans le ciel. Rechargez la page : que constatez-vous ?
- Mettez le canvas à
width: 100%en CSS sans changer les attributs. Le dessin est-il net ? Expliquez, puis cherchez le rôle dewindow.devicePixelRatiopour un dessin net sur écran haute résolution.
Je vérifie / je rends :
- ☐ Le fichier
paysage.htmlet une capture du résultat.
← 15.1 Les animations JavaScript15.3 Animer un dessin Canvas (requestAnimationFrame) →