W3docs

Introduzione a Canvas

Impara l'elemento HTML <canvas>: sistema di coordinate, contesto di rendering 2D, scaling per schermi ad alta densità, accessibilità ed esempi.

L'elemento HTML <canvas> è una superficie di disegno rettangolare che controlli interamente tramite script. L'elemento stesso è solo un contenitore vuoto — non disegna nulla da solo. Si usa JavaScript per impartire comandi di disegno che dipingono pixel su di esso.

Questa pagina introduce l'elemento <canvas>, il suo sistema di coordinate, il contesto di rendering 2D e le operazioni di disegno più comuni: forme, testo, gradienti, linee e immagini.

Cos'è l'elemento <canvas>?

<canvas> fornisce una bitmap — una griglia di pixel su cui disegni immediatamente. Una volta che una forma è dipinta, il canvas non la ricorda come oggetto; è semplicemente pixel colorati. Questa è la differenza chiave rispetto a SVG, dove ogni forma rimane un nodo DOM che puoi ridefinire nello stile o animare individualmente.

Questo compromesso guida la scelta di quando usare il canvas:

  • Scegli <canvas> per il controllo a livello di pixel, migliaia di oggetti, animazioni veloci fotogramma per fotogramma, giochi, elaborazione di immagini, grafici con molti dati o effetti particellari. Poiché è in modalità "immediata", ridisegnare è economico.
  • Scegli SVG quando hai bisogno di vettori indipendenti dalla risoluzione, icone scalabili, un numero gestibile di forme da ispezionare, cliccare o animare tramite CSS/DOM.
  • Scegli CSS per layout, transizioni ed effetti su elementi HTML ordinari — non per disegno libero.
Suggerimento

Puoi inserire più di un elemento <canvas> nella stessa pagina HTML, ognuno con il proprio contesto.

Il sistema di coordinate

Un canvas utilizza una griglia di coordinate 2D. L'origine (0, 0) si trova nell'angolo in alto a sinistra. L'asse x cresce verso destra e l'asse y cresce verso il basso — nota che y cresce verso il basso, al contrario di un grafico matematico. Un punto (100, 60) si trova quindi a 100 pixel dal bordo sinistro e 60 pixel dall'alto.

L'area di disegno è definita dagli attributi width e height (in pixel CSS):

<canvas id="canvas" width="250" height="150"></canvas>
Pericolo

Imposta le dimensioni del canvas con gli attributi width e height, non con CSS. CSS width/height si limita a stirare la bitmap esistente, rendendo il disegno sfocato. Aggiungi un bordo con l'attributo style o una classe.

Il contesto di rendering 2D

Non si disegna mai direttamente sull'elemento <canvas> — si disegna tramite un contesto di rendering, un oggetto che espone l'API di disegno. Lo si ottiene con getContext():

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

getContext('2d') restituisce un CanvasRenderingContext2D, che contiene ogni metodo e proprietà usati di seguito (fillRect, arc, fillText, strokeStyle e così via). È il punto di partenza giusto per quasi tutto il disegno 2D.

Esistono altri tipi di contesto per esigenze diverse:

  • 'webgl' / 'webgl2' — 3D accelerato dalla GPU (e 2D ad alte prestazioni) tramite l'API OpenGL ES.
  • 'bitmaprenderer' — visualizza un ImageBitmap senza una propria API di disegno.

Questo capitolo usa solo il contesto '2d'.

Accessibilità: contenuto di fallback

Tutto ciò che inserisci tra i tag di apertura e chiusura <canvas> è contenuto di fallback. I browser che supportano canvas lo ignorano; i browser (o le tecnologie assistive) che non riescono a renderizzare il canvas lo mostrano al suo posto. Poiché i pixel disegnati sono invisibili agli screen reader, usa questo spazio per descrivere il grafico, oppure aggiungi un aria-label / role affinché il canvas venga annunciato in modo significativo.

<canvas id="canvas" width="250" height="150" role="img" aria-label="A blue circle on a white background">
  A blue circle on a white background.
</canvas>

Per i canvas interattivi (giochi, app di disegno), fornisci come fallback veri controlli HTML con focus all'interno dell'elemento, poiché i pixel stessi non possono ricevere il focus tramite tastiera.

Esempio del tag HTML <canvas>:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="canvas" width="250" height="150" style="border:1px solid #1c87c9;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
  </body>
</html>

Esempio del tag HTML <canvas> per disegnare un cerchio:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="200" height="200" style="border:1px solid #dddddd;">
      HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.beginPath();
      ctx.arc(100, 100, 60, 0, 2 * Math.PI);
      ctx.strokeStyle = '#009299';
      ctx.stroke();
    </script>
  </body>
</html>

Il metodo arc() accetta cinque argomenti: arc(x, y, radius, startAngle, endAngle). Qui (100, 100) è il centro del cerchio, 60 è il raggio in pixel e l'arco va dall'angolo 0 a 2 * Math.PI. Gli angoli si misurano in radianti e un cerchio completo è radianti, quindi da 0 a 2 * Math.PI si disegna il cerchio per intero. beginPath() avvia un nuovo percorso e stroke() lo traccia usando il strokeStyle corrente. Per riempirlo invece, imposta fillStyle e chiama fill(). Approfondisci in Canvas drawing e Canvas coordinates.

Esempio del tag HTML <canvas> per disegnare un testo:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="350" height="110" style="border:1px solid #dddddd;">
      HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.font = "40px Arial";
      ctx.fillStyle = '#262ac7';
      ctx.fillText("Canvas Text", 55, 65);
    </script>
  </body>
</html>

fillText(text, x, y) dipinge testo riempito alle coordinate indicate. La proprietà font usa la notazione abbreviata CSS standard per i font. Vedi Canvas text per allineamento, contorno del testo e misurazione della larghezza.

Esempio del tag HTML <canvas> per disegnare un gradiente lineare:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="300" height="140" style="border:1px solid #dddddd;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      const grd = ctx.createLinearGradient(0, 0, 300, 0);
      grd.addColorStop(0, "#359900");
      grd.addColorStop(1, "#ffffff");
      ctx.fillStyle = grd;
      ctx.fillRect(20, 20, 250, 100);
    </script>
  </body>
</html>

createLinearGradient(x0, y0, x1, y1) definisce la direzione del gradiente tramite due punti. Qui da (0, 0) a (300, 0) è un gradiente orizzontale da sinistra a destra. addColorStop(offset, color) posiziona un colore a una posizione da 0 (inizio) a 1 (fine), quindi il verde sfuma nel bianco. Assegnare il gradiente a fillStyle fa sì che fillRect(x, y, width, height) lo usi per dipingere. Approfondisci in Canvas gradients.

Esempio del tag HTML <canvas> per disegnare una linea:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="150" height="150" style="border:1px solid #cccccc;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      ctx.moveTo(0, 0);
      ctx.lineTo(150, 150);
      ctx.strokeStyle = '#86417d';
      ctx.stroke();
    </script>
  </body>
</html>

moveTo(x, y) solleva la "penna" su un punto di partenza senza disegnare, e lineTo(x, y) aggiunge un segmento rettilineo fino a quel punto. Nulla appare finché non chiami stroke(). Vedi Canvas drawing per percorsi a più segmenti, larghezza della linea e giunzioni.

Esempio del tag HTML <canvas> per disegnare un'immagine:

Per essere autonomo (ed evitare problemi di cross-origin — vedi la nota qui sotto), questo esempio usa una piccola immagine SVG inline come data URI anziché una foto remota:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <h2>Draw an image with canvas</h2>
    <canvas id="exampleCanvas" width="220" height="120" style="border:1px solid #dddddd;"></canvas>
    <script>
      const canvas = document.getElementById('exampleCanvas');
      const ctx = canvas.getContext('2d');
      const image = new Image();
      image.addEventListener('load', () => {
        // drawImage(image, dx, dy) draws at the given top-left position
        ctx.drawImage(image, 10, 10);
        // Scaled copy: drawImage(image, dx, dy, dWidth, dHeight)
        ctx.drawImage(image, 120, 10, 50, 50);
      });
      image.src =
        "data:image/svg+xml," +
        encodeURIComponent(
          '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">' +
          '<circle cx="50" cy="50" r="45" fill="#1c87c9" /></svg>'
        );
    </script>
  </body>
</html>

drawImage() accetta tre forme: drawImage(image, dx, dy), drawImage(image, dx, dy, dWidth, dHeight) per scalare, e drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) per ritagliare un rettangolo sorgente (s*) e posizionarlo in un rettangolo destinazione (d*). Disegna sempre all'interno dell'evento load dell'immagine in modo che i pixel siano pronti. Vedi Canvas images per saperne di più.

Pericolo

Problema CORS. Disegnare un'immagine proveniente da un'altra origine senza gli appositi header CORS "contamina" il canvas. Dopo di che, getImageData() e toDataURL() generano un errore di sicurezza. Se hai bisogno di leggere i pixel da un'immagine remota, questa deve essere servita con header CORS permissivi e caricata con image.crossOrigin = "anonymous" prima di impostare src.

Esempio del tag HTML <canvas> per disegnare un gradiente circolare:

<!DOCTYPE html>
<html>
  <head>
    <title>Title of the document</title>
  </head>
  <body>
    <canvas id="exampleCanvas" width="260" height="160" style="border:1px solid #cdcdcd;">
      The HTML5 canvas tag is not supported by your browser.
    </canvas>
    <script>
      const c = document.getElementById("exampleCanvas");
      const ctx = c.getContext("2d");
      const grd = ctx.createRadialGradient(150, 75, 10, 115, 90, 150);
      grd.addColorStop(0, "purple");
      grd.addColorStop(1, "white");
      ctx.fillStyle = grd;
      ctx.fillRect(20, 20, 220, 120);
    </script>
  </body>
</html>

createRadialGradient(x0, y0, r0, x1, y1, r1) sfuma tra due cerchi: un cerchio iniziale (centro (150, 75), raggio 10) e un cerchio finale (centro (115, 90), raggio 150). I color stop sfumano dal viola al cerchio interno fino al bianco a quello esterno, producendo il bagliore rotondo. Confronta con createLinearGradient sopra e approfondisci in Canvas gradients.

Display ad alta densità (Retina)

Negli schermi ad alta densità, un pixel CSS corrisponde a più pixel fisici del dispositivo. Un canvas dimensionato solo in pixel CSS risulta quindi sfocato su quei display. La soluzione è scalare la bitmap per window.devicePixelRatio e poi scalare il contesto in modo che le coordinate di disegno rimangano invariate:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const ratio = window.devicePixelRatio || 1;

// CSS size (layout) stays the same:
const cssWidth = 250;
const cssHeight = 150;
canvas.style.width = cssWidth + 'px';
canvas.style.height = cssHeight + 'px';

// Backing bitmap gets more device pixels:
canvas.width = cssWidth * ratio;
canvas.height = cssHeight * ratio;

// Scale once so you keep drawing in CSS-pixel coordinates:
ctx.scale(ratio, ratio);

Dopo questo, disegnare arc(100, 100, 60, …) produce un cerchio nitido sia su schermi standard che Retina.

Capitoli correlati

Esercitazione

Pratica
Quali sono le caratteristiche e l'utilizzo di HTML Canvas?
Quali sono le caratteristiche e l'utilizzo di HTML Canvas?
Was this page helpful?