W3docs

Disegno su Canvas

Impara a disegnare sull'HTML canvas con JavaScript: rettangoli, contorni, percorsi, linee, cerchi e archi, con esempi di codice eseguibili.

L'elemento <canvas> è semplicemente una superficie di disegno vuota e trasparente. Da solo non mostra nulla — non è possibile disegnare su di esso con HTML o CSS. Tutto il disegno su un canvas viene eseguito con JavaScript, attraverso un oggetto chiamato contesto di rendering. Questa pagina illustra passo dopo passo le operazioni di disegno 2D fondamentali: riempire rettangoli, tracciare contorni, disegnare percorsi a forma libera e disegnare cerchi e archi.

Se non hai ancora creato un elemento <canvas>, inizia con il tag HTML <canvas> e l'introduzione a Canvas.

Il sistema di coordinate del canvas

Ogni metodo di disegno utilizza coordinate in pixel. La griglia del canvas ha la sua origine (0, 0) nell'angolo in alto a sinistra. L'asse x cresce verso destra e l'asse y cresce verso il basso (nota che y aumenta man mano che ci si sposta verso il basso, al contrario di un grafico matematico). Quindi il punto (0, 0) è il pixel in alto a sinistra, e (width, height) è l'angolo in basso a destra.

Per un approfondimento sulla griglia, vedi Coordinate del canvas.

1. Trovare l'elemento canvas

Per prima cosa, ottieni un riferimento all'elemento <canvas> nel DOM con getElementById():

const canvas = document.getElementById("canvas");

2. Ottenere il contesto di rendering 2D

Chiama il metodo getContext() per ottenere un contesto di disegno. Passando "2d" si ottiene un oggetto CanvasRenderingContext2D, che contiene tutte le proprietà e i metodi usati per disegnare:

const ctx = canvas.getContext("2d");

La variabile ctx (abbreviazione di "context") è quella su cui si chiamano tutti i comandi di disegno.

getContext() restituisce null se il browser non può fornire il contesto richiesto (ad esempio, se "2d" è scritto in modo errato, o se l'elemento non è effettivamente un <canvas>). È buona pratica gestire questo caso prima di disegnare, così un contesto mancante non genera errori silenziosi sulla riga successiva:

const ctx = canvas.getContext("2d");
if (!ctx) return; // bail out if the 2D context is unavailable; only valid inside a function

In uno <script> inline semplice (che non è il corpo di una funzione), racchiudi il disegno in if (ctx) { ... } come fanno gli esempi seguenti.

3. Disegnare un rettangolo pieno

La proprietà fillStyle imposta il colore usato per riempire le forme. Può essere qualsiasi colore CSS, un pattern o un gradiente:

ctx.fillStyle = "#1c87c9";

Poi fillRect(x, y, width, height) disegna un rettangolo pieno. I primi due parametri sono le coordinate x e y dell'angolo in alto a sinistra, seguite da larghezza e altezza in pixel:

ctx.fillRect(0, 0, 230, 130);

Esempio di disegno di un rettangolo pieno:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" role="img"
            aria-label="A blue filled rectangle" style="border:1px solid #dddddd;">
      Your browser does not support the canvas element.
    </canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      if (ctx) {
        // only draw when the 2D context is available
        ctx.fillStyle = "#1c87c9";
        ctx.fillRect(0, 0, 230, 130);
      }
    </script>
  </body>
</html>

Rendere il canvas accessibile

Tutto ciò che disegni su un canvas è solo pixel — non ha struttura, quindi gli screen reader non possono leggerlo. Non c'è nulla da annunciare e gli utenti che usano la tastiera non possono accedere a nulla al suo interno. Fornisci alla tecnologia assistiva un equivalente testuale in due modi:

  • Il contenuto di fallback va tra i tag <canvas>. I browser che renderizzano il canvas lo ignorano; la tecnologia assistiva (e i browser molto vecchi) lo usano al suo posto. Metti qui una descrizione significativa, non "il tuo browser non supporta canvas."
  • role="img" insieme ad aria-label descrive il disegno completato come una singola immagine, allo stesso modo in cui il testo alt descrive un <img>.
<canvas id="chart" width="250" height="150" role="img"
        aria-label="Bar chart: sales doubled from Q1 to Q2.">
  A bar chart showing sales doubling from Q1 to Q2.
</canvas>

Per qualsiasi elemento interattivo (aree cliccabili, controlli), fornisci anche elementi DOM reali e focalizzabili — il canvas da solo non è accessibile da tastiera.

Contorno senza riempimento

A volte si vuole solo il contorno di una forma invece di un riempimento solido. Usa la proprietà strokeStyle per impostare il colore del contorno e strokeRect(x, y, width, height) per disegnare un rettangolo non riempito. La proprietà lineWidth controlla lo spessore del contorno:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" role="img"
            aria-label="A blue rectangular outline" style="border:1px solid #dddddd;">
      A rectangle drawn as an outline.
    </canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      if (ctx) {
        ctx.strokeStyle = "#1c87c9";
        ctx.lineWidth = 4;
        ctx.strokeRect(20, 20, 200, 100);
      }
    </script>
  </body>
</html>
Result

Cancellare una parte del canvas

clearRect(x, y, width, height) cancella il rettangolo specificato, rendendolo nuovamente completamente trasparente. Viene comunemente usato per pulire l'intero canvas prima di ridisegnare (ad esempio, a ogni frame di un'animazione):

// Erase everything on a 250 × 150 canvas
ctx.clearRect(0, 0, 250, 150);

Nell'esempio seguente vengono disegnati due rettangoli blu, e poi clearRect() ritaglia un buco trasparente nel mezzo del canvas — nota che il rettangolo di destra viene parzialmente cancellato:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" role="img"
            aria-label="Two blue squares with a cleared rectangle cut out of the middle"
            style="border:1px solid #dddddd;">
      Two filled squares with a cleared region.
    </canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      if (ctx) {
        ctx.fillStyle = "#1c87c9";
        ctx.fillRect(20, 20, 100, 100);
        ctx.fillRect(130, 20, 100, 100);
        ctx.clearRect(90, 50, 70, 50); // erase a rectangle across both
      }
    </script>
  </body>
</html>
Result

Disegnare percorsi (linee e forme personalizzate)

I rettangoli sono comodi, ma la maggior parte dei disegni usa i percorsi — sequenze di punti collegati da linee o curve. Un percorso viene costruito con un insieme ristretto di metodi e non è visibile finché non si chiama stroke() (per disegnare il contorno) o fill() (per riempire l'area racchiusa).

MetodoCosa fa
beginPath()Avvia un nuovo percorso vuoto.
moveTo(x, y)Sposta il "pennino" in (x, y) senza disegnare.
lineTo(x, y)Aggiunge una linea retta dal punto corrente a (x, y).
closePath()Disegna una linea di ritorno al punto iniziale del percorso.
stroke()Renderizza il percorso come contorno.
fill()Riempie l'area racchiusa dal percorso.

Inizia sempre con beginPath()

beginPath() cancella l'elenco di punti che il contesto sta attualmente tracciando e avvia un nuovo percorso. Questo è importante perché il canvas ricorda ogni sotto-percorso finché non viene azzerato. Se disegni una forma e poi aggiungi punti per una seconda forma senza chiamare beginPath(), i vecchi punti sono ancora nel percorso — quindi il successivo stroke() o fill() ridisegna anche la prima forma, spesso con il nuovo colore e spessore di linea. Il risultato è che le forme "sconfinano" l'una nell'altra.

Regola pratica: chiama beginPath() prima di ogni nuova forma. Ogni esempio qui sotto inizia in questo modo.

Esempio: una singola linea

Per disegnare una linea, inizia un percorso, spostati nel punto di partenza, traccia una linea fino al punto finale e poi applicale il contorno:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" role="img"
            aria-label="A diagonal blue line" style="border:1px solid #dddddd;">
      A diagonal line drawn across the canvas.
    </canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      if (ctx) {
        ctx.beginPath();
        ctx.moveTo(20, 20);   // start point (x, y)
        ctx.lineTo(220, 120); // end point (x, y)
        ctx.lineWidth = 3;
        ctx.strokeStyle = "#1c87c9";
        ctx.stroke();         // make the line visible
      }
    </script>
  </body>
</html>
Result

Esempio: un triangolo

Concatenare più chiamate a lineTo() crea una forma a più lati. closePath() collega l'ultimo punto al primo, e fill() riempie l'area racchiusa:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" role="img"
            aria-label="A filled green triangle" style="border:1px solid #dddddd;">
      A filled green triangle.
    </canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      if (ctx) {
        ctx.beginPath();
        ctx.moveTo(125, 20);  // top vertex
        ctx.lineTo(220, 130); // bottom-right vertex
        ctx.lineTo(30, 130);  // bottom-left vertex
        ctx.closePath();      // back to the top vertex
        ctx.fillStyle = "#8ebf42";
        ctx.fill();
      }
    </script>
  </body>
</html>
Result

Disegnare cerchi e archi

Il metodo arc() disegna cerchi e segmenti curvi:

ctx.arc(x, y, radius, startAngle, endAngle, counterclockwise);
  • x, y — le coordinate del centro dell'arco.
  • radius — il raggio in pixel.
  • startAngle, endAngle — gli angoli di inizio e fine in radianti (non in gradi). L'angolo 0 punta lungo l'asse x positivo — dritto verso destra, la direzione delle ore 3 — e per default gli angoli aumentano in senso orario (perché l'asse y del canvas cresce verso il basso). Un cerchio completo è 2 * Math.PI radianti.
  • counterclockwise — un boolean opzionale. Passa true per percorrere l'arco in direzione opposta (il valore predefinito è false).

Poiché gli angoli sono in radianti, è comodo convertire i gradi con una piccola funzione di supporto:

function toRadians(degrees) {
  return degrees * Math.PI / 180;
}

// e.g. a quarter turn:
ctx.arc(125, 75, 50, 0, toRadians(90));

Quindi 90 gradi corrisponde a Math.PI / 2, 180 gradi a Math.PI e 360 gradi a 2 * Math.PI.

Un cerchio completo va da 0 a 2 * Math.PI. Come per qualsiasi percorso, è necessario chiamare stroke() o fill() per renderlo visibile:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" role="img"
            aria-label="A blue filled circle" style="border:1px solid #dddddd;">
      A filled blue circle.
    </canvas>
    <script>
      const canvas = document.getElementById("canvas");
      const ctx = canvas.getContext("2d");
      if (ctx) {
        ctx.beginPath();
        ctx.arc(125, 75, 50, 0, 2 * Math.PI); // center (125,75), radius 50, full circle
        ctx.fillStyle = "#1c87c9";
        ctx.fill();
      }
    </script>
  </body>
</html>
Result

Per disegnare invece un semicerchio, termina l'arco a Math.PI radianti invece che a 2 * Math.PI.

Dove andare dopo

Una volta che hai familiarità con forme e percorsi, esplora il resto del tutorial su Canvas:

Esercitazione

Pratica
Cosa restituisce la chiamata getContext('2d') su un elemento canvas?
Cosa restituisce la chiamata getContext('2d') su un elemento canvas?
Pratica
Perché dovresti chiamare beginPath() prima di disegnare ogni nuova forma?
Perché dovresti chiamare beginPath() prima di disegnare ogni nuova forma?
Was this page helpful?