Disegnare una griglia interattiva con Canvas HTML5

by Anastasia P.
SHARE
Disegnare una griglia interattiva con Canvas HTML5
© Guida-HTML5.it

Introduzione

Canvas è uno degli strumenti più versatili di HTML5 per creare grafica 2D in modo dinamico. A differenza degli elementi HTML tradizionali, Canvas non descrive una struttura visibile predefinita: offre invece una superficie “vuota” su cui disegnare tramite JavaScript. Questo lo rende ideale per applicazioni interattive, editor visuali, mini-tool grafici e dashboard personalizzate.

In questo tutorial vedremo un caso molto pratico: costruire una griglia interattiva su Canvas, dove ogni cella può essere attivata o disattivata con il click del mouse. È un esempio utile perché introduce diversi concetti fondamentali della grafica 2D: coordinate, gestione degli eventi, ridisegno completo della scena e organizzazione dello stato interno.

Questo tipo di approccio è la base di molti strumenti reali, come editor di livelli, mappe a blocchi, prototipi di giochi, pannelli di selezione e sistemi di pianificazione visuale.

Codice completo

<canvas id="gridCanvas" width="600" height="400"></canvas>

<script>
  const canvas = document.getElementById("gridCanvas");
  const ctx = canvas.getContext("2d");

  // Configurazione della griglia
  const cellSize = 40;
  const cols = Math.floor(canvas.width / cellSize);
  const rows = Math.floor(canvas.height / cellSize);

  // Stato della griglia: true = cella attiva, false = cella vuota
  const grid = Array.from({ length: rows }, () =>
    Array.from({ length: cols }, () => false)
  );

  function drawGrid() {
    // Pulisce tutto il canvas prima di ridisegnare
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    for (let row = 0; row < rows; row++) {
      for (let col = 0; col < cols; col++) {
        const x = col * cellSize;
        const y = row * cellSize;

        // Colore della cella in base allo stato
        if (grid[row][col]) {
          ctx.fillStyle = "#4caf50";
          ctx.fillRect(x, y, cellSize, cellSize);
        } else {
          ctx.fillStyle = "#ffffff";
          ctx.fillRect(x, y, cellSize, cellSize);
        }

        // Bordo della cella
        ctx.strokeStyle = "#cccccc";
        ctx.strokeRect(x, y, cellSize, cellSize);
      }
    }
  }

  function getCellFromMouseEvent(event) {
    const rect = canvas.getBoundingClientRect();

    // Coordinate del mouse relative al canvas
    const mouseX = event.clientX - rect.left;
    const mouseY = event.clientY - rect.top;

    const col = Math.floor(mouseX / cellSize);
    const row = Math.floor(mouseY / cellSize);

    return { row, col };
  }

  canvas.addEventListener("click", (event) => {
    const { row, col } = getCellFromMouseEvent(event);

    // Controllo di sicurezza per evitare accessi fuori dalla griglia
    if (row >= 0 && row < rows && col >= 0 && col < cols) {
      grid[row][col] = !grid[row][col];
      drawGrid();
    }
  });

  // Disegno iniziale
  drawGrid();
</script>

Spiegazione

Il punto chiave di questo esempio è separare chiaramente stato e rendering. La griglia vera e propria non è salvata come pixel sul canvas, ma come una struttura dati JavaScript: un array bidimensionale di valori booleani. Ogni elemento rappresenta una cella attiva o inattiva.

1. Il canvas come superficie di disegno

Il tag <canvas> definisce un’area con larghezza e altezza. Per disegnare usiamo il contesto 2D ottenuto con getContext("2d"). Da quel momento possiamo usare funzioni come fillRect, strokeRect e clearRect.

2. La struttura dati della griglia

Per gestire la logica interattiva, creiamo una matrice:

  • ogni riga contiene più celle;
  • ogni cella è inizialmente false;
  • quando l’utente clicca su una cella, il suo valore viene invertito.

Questo approccio è molto più robusto rispetto al tentativo di “leggere” lo stato visivo dal canvas, perché il canvas è un’area di rendering, non un database del disegno.

3. Conversione coordinate mouse → cella

Quando l’utente clicca, riceviamo coordinate della pagina. Per capire quale cella è stata selezionata, calcoliamo la posizione relativa al canvas usando getBoundingClientRect(). Poi dividiamo per la dimensione della cella e usiamo Math.floor() per ottenere indice di colonna e riga.

Questo passaggio è fondamentale in qualunque applicazione canvas interattiva: strumenti di disegno, giochi a griglia, mappe tile-based, selettori di aree e simulatori visivi.

4. Ridisegno completo

Ogni volta che cambia lo stato, non aggiorniamo solo la cella cliccata: richiamiamo drawGrid() e ridisegniamo tutto. Questo è un metodo semplice e affidabile, ottimo per interfacce piccole e medie. In scenari più complessi si possono introdurre ottimizzazioni, ma per iniziare questa strategia è la più chiara.

5. Separazione tra logica e grafica

Il codice è organizzato in tre parti:

  • configurazione: dimensioni, numero di righe e colonne;
  • stato: matrice delle celle attive;
  • rendering e interazione: funzioni di disegno e gestione del click.

Questa separazione rende il progetto facile da estendere. Ad esempio, potresti aggiungere un pulsante per svuotare la griglia, un tool per trascinare il mouse o persino esportare i dati in JSON.

Best practice

Quando lavori con Canvas e grafica 2D, alcune abitudini migliorano molto la qualità del progetto:

  • Conserva lo stato fuori dal canvas: usa array, oggetti o strutture dedicate in JavaScript.
  • Ridisegna in modo deterministico: ogni frame o aggiornamento deve partire da una scena pulita.
  • Usa dimensioni coerenti: cellSize, canvas.width e canvas.height devono essere pensati insieme per evitare celle tagliate o disallineate.
  • Valida sempre gli indici: anche se il calcolo sembra corretto, controlla che row e col siano dentro i limiti.
  • Evita logica di rendering troppo complessa: mantieni le funzioni brevi e riutilizzabili.
  • Prevedi l’evoluzione del progetto: se in futuro vuoi aggiungere zoom, drag o selezione multipla, struttura il codice fin dall’inizio in modo modulare.

Un altro consiglio importante è quello di tenere separata la dimensione “logica” della cella dalla dimensione visuale, soprattutto se vuoi supportare schermi ad alta densità o scaling responsivo. In quel caso, potresti adattare il canvas al device pixel ratio per ottenere bordi più nitidi.

Riepilogo

In questo tutorial abbiamo costruito una griglia interattiva con HTML5 Canvas, un esempio semplice ma molto utile per capire come funziona la grafica 2D dinamica. I concetti principali sono:

  • Canvas è una superficie di disegno gestita via JavaScript;
  • la grafica va ridisegnata quando cambia lo stato;
  • le coordinate del mouse devono essere convertite in coordinate locali del canvas;
  • lo stato dell’interfaccia deve vivere in strutture dati JavaScript, non nel canvas stesso.

Questo pattern è la base di moltissime applicazioni interattive. Una volta compreso, potrai evolverlo facilmente in un editor di mappe, in un sistema di pixel art, in un selettore di celle per simulazioni o in una mini interfaccia per giochi strategici.

Approfondisci con risorse ufficiali

  • MDN Web Docs - Canvas API: documentazione completa su contesto 2D, forme, immagini e trasformazioni.
  • MDN Web Docs - HTMLCanvasElement: proprietà e metodi dell’elemento canvas.
  • WHATWG HTML Living Standard: specifica ufficiale dell’elemento canvas.
  • MDN Web Docs - MouseEvent: utile per comprendere coordinate e gestione degli input.

Se vuoi fare il passo successivo, il miglior esercizio è aggiungere al progetto la possibilità di trascinare il mouse per attivare più celle in sequenza. È un’estensione perfetta per consolidare il rapporto tra eventi, coordinate e rendering su Canvas.

SHARE