Sommario
< Home
Stampa

Canvas

Cosa è il Canvas

L’oggetto canvas (rappresentato in html col tag <canvas>) è uno strumento che permette di creare un’area all’interno della pagina web in cui è possibile disegnare programmaticamente linee, forme, figure. E’ quindi un’area di grafica 2D. 

I canvas sono molto usati nelle pagine html per questi scopi:

– arte visuale: ad esempio scritte artistiche, scritte a scorrimento, ecc. in particolare nel coding creativo[1]

– animazioni (in alternativa a SVG[2]

– grafici (es. a istogramma, barra, torta, ecc.)

– videogiochi

– è alla base della libreria WebGL per la grafica 3D

Vediamo come funziona.

Creazione ed utilizzo

L’area (rettangolare) in html la si inizializza con questo codice:

<canvas id=”canvas” width=”500″ height=”500″></canvas>

(larghezza ed altezza sono modificabili anche via CSS che JS).

Il resto dell’attività si svolge in Javascript.

Per usare il canvas bisogna eseguire prima di tutto queste due istruzioni:

const canvas = document.getElementById(“canvas”);

const ctx = canvas.getContext(“2d”);

L’oggetto ctx (Context) sarà l’oggetto che ci permette di disegnare nel canvas.

Il canvas è internamente una griglia dove ogni punto ha coordinate (x,y) con la posizione (0,0) in alto a sinistra.

L’attività di disegno consiste quindi nel disegnare forme all’interno della griglia, dando le coordinate e le dimensioni.

Rettangoli

ComandoEsempioNote
ctx.fillRect(x, y, width, height);ctx.fillRect(25, 25, 100, 100);Crea un rettangolo (pieno) dalle coordinate x,y e dimensioni width ed height.
ctx.strokeRect(x, y, width, height);ctx.strokeRect(45, 45, 60, 60);Crea un rettangolo (vuoto) dalle coordinate x,y e dimensioni width ed height.
ctx.clearRect(x, y, width, height);ctx.clearRect(50, 50, 50, 50); 

Se si eseguono le seguenti 3 istruzioni:

ctx.fillRect(25, 25, 100, 100);
ctx.strokeRect(45, 45, 60, 60);
ctx.clearRect(50, 50, 50, 50);

Spiegazione:

fill crea un rettangolo pieno

stroke un rettangolo pieno

clear cancella tutto quanto c’è nel rettangolo

Cosa si ottiene?

Notare che clearRect può essere usato per cancellare tutto il canvas.

Disegnare forme con path

E’ possibile disegnare forme complesse utilizzando il path.

Vediamo un esempio: se voglio disegnare una linea che va da 100, 100 a 300, 300 uso queste istruzioni:

ctx.beginPath();
ctx.moveTo(100,100);
ctx.lineTo(300,300);
ctx.moveTo(100,300);
ctx.lineTo(300, 300);
ctx.moveTo(100,100);
ctx.lineTo(100, 300);
ctx.lineWidth = 2;

ctx.stroke();

Si dovrebbe ottenere un triangolo rettangolo.

Riassumendo:

– beginPath da inizio al disegno;

– moveTo sposta la “penna” su una coordinata;

– lineTo disegna una linea dalla coordinata attuale alla nuova coordinata;

– lineWidth da la dimensione della linea (istruzione non obbligatoria);

– stroke esegue la “commit”, ovvero rende il disegno effettivo.

Archi, cerchi e circonferenze

Vediamo ora come si disegna una circonferenza:

ctx.beginPath();
ctx.arc(250, 250, 200, 0, 2 * Math.PI);
ctx.lineWidth = 1;

ctx.stroke();

Come si può vedere, arc riceve 5 parametri:

  • le coordinate x ed y;
  • la dimensione del raggio;
  • gli ultimi due parametri sono l’angolo di inizio e di fine dell’arco: nel caso del cerchio sono 0 e 2π.

Se invece vogliamo un cerchio pieno usiamo fill.

ctx.beginPath();
ctx.arc(250, 250, 50, 0, 2 * Math.PI);
ctx.lineWidth = 1;

ctx.fill();

Riassumendo:

– stroke indica un disegno solo del contorno;

– fill indica un disegno della forma piena.

Se vogliamo disegnare più forme diverse con strutture diverse è sufficiente che replichiamo la struttura:

ctx.beginPath();

...

ctx.stroke() o ctx.fill();

I colori

Si può disegnare a colori con queste istruzioni:

ctx.fillStyle = "#ff0000";
ctx.strokeStyle = "#00cc22";

dove il codice altro non è che la terna RGB esadecimale.

Esempio: movimento di una pallina 2D

In questo esempio si proverà a simulare il comportamento di una pallina in 2D. Qui uno screenshot di come si può vedere la “pallina” (che altro non è che un cerchio).

Vediamo nello specifico il funzionamento di questo algoritmo. 

1) La pallina viene disegnata da una funzione render 

Questa riceve come parametro una coppia di coordinate (x,y) e che prima cancella l’intero canvas (clearRect sull’intera dimensione del canvas) e poi ridisegna la pallina nella posizione richiesta. La pallina come detto viene simulata disegnando un cerchio di piccole dimensioni (5-10 pixel).

2) Il refresh

L’effetto visivo dello spostamento della pallina si ottiene mediante aggiornamento della posizione (x,y) della pallina stessa. Dobbiamo quindi scrivere una funzione refresh che calcola le nuove coordinate in cui si dovrà trovare la pallina in base alla sua velocità e la sua direzione. Questa funzione dovrà essere eseguita periodicamente tramite setInterval con una frequenza abbastanza veloce da rendere il movimento fluido per l’occhio umano. E’ in questo modo che funzionano tutti i videogiochi.

Riassumendo: ad ogni esecuzione di setInterval verrà eseguita:

– refresh(): funzione che ricalcola le nuove coordinate (x,y)

– render(): ridisegna la pallina 

3) Come calcolare le nuove coordinate.

La pallina ha una direzione (angolo  ) e una velocità. La nuova posizione va aggiornata ogni t millisecondi, e corrisponderà ad uno spostamento in diagonale, ovvero sia orizzontale (verso destra o sinistra) che verticale (verso l’alto o verso il basso). Qui un esempio di spostamento con algolo di π/6 (30 gradi):

La traslazione della pallina ha una componente orizzontale, che corrisponde al coseno di  ed una componente verticale pari al seno di , entrambi moltiplicati per la velocità della pallina stessa.

Quindi una pallina che all’istante t è nella posizione (x,y) nell’istante t’ (ad esempio dopo 20 millisecondi) si troverà nella posizione (x’,y’):

Quindi se ad esempio all’istante t la pallina si trova nella posizione (100,100) ed ha velocità di 1 pixel/ms e angolo 30° all’istante t’ (=t+20ms) si troverà:

Ricordare sempre che nei canvas il punto in alto a sinistra è (0,0). Quello che si deve fare nell’esercizio è quindi semplicemente calcolare le nuove posizioni con la formula sopra riportata.

4) Urti con le pareti.

In caso di urto con le pareti supponiamo che sia elastico, quindi la velocità rimane la stessa, ciò che cambia è l’angolo di uscita, che per effetto del rimbalzo cambia secondo la seguente regola:

– se l’urto è verso le pareti verticali (dx o sx) il nuovo angolo è: 

 se l’urto è verso le pareti orizzontali (sopra o sotto) il nuovo angolo è:

A livello di codice, dopo ogni traslazione bisogna verificare se la pallina sta uscendo dall’area del canvas. Se si vede che sta uscendo bisogna ricalcolare il nuovo angolo, così alla traslazione successiva la pallina avrà cambiato direzione, per effetto appunto del rimbalzo. 

Qui un esempio di codice:

const refresh = (ball) => {
  let newx = ball.x + ball.speed * Math.cos(ball.angle);
  let newy = ball.y + ball.speed * Math.sin(ball.angle);
  if (newx < size || newx > width-size) {
    ball.angle = Math.PI - ball.angle;
  } else if (newy < size || newy > height-size) {
    ball.angle = 2 * Math.PI - ball.angle;
  } else {
    ball.x = newx;
    ball.y = newy;
  }
};

Dove size è la dimensione in pixel della pallina, ball è un dizionario che contiene x, y, speed e angle della pallina.

Si lascia allo studente il resto dell’elaborazione come semplice esercizio.

Eventi da tastiera

Per intercettare un evento da tastiera in una pagina web è sufficiente eseguire il seguente codice:

document.onkeydown = function(e) {
    console.log(String.fromCharCode(e.keyCode)+" --> "+e.keyCode);
};
 
Il valore di keyCode indica il codice numerico del tasto premuto.

Qui un elenco di codici.

Keyboard key PressedJavaScript Key Code value
backspace8
tab9
enter13
shift16
ctrl17
alt18
pause/break19
caps lock20
escape27
page up33
Space32
page down34
end35
home36
arrow left37
arrow up38
arrow right39
arrow down40
print screen44
insert45
delete46
048
149
250
351
452
553
654
755
856
957
a65
b66
c67
d68
e69
f70
g71
h72
i73
j74
k75
l76
m77
n78
o79
p80
q81
r82
s83
t84
u85
v86
w87
x88
y89
z90
left window key91
right window key92
select key93
numpad 096
numpad 197
numpad 298
numpad 399
numpad 4100
numpad 5101
numpad 6102
numpad 7103
numpad 8104
numpad 9105
multiply106
add107
subtract109
decimal point110
divide111
f1112
f2113
f3114
f4115
f5116
f6117
f7118
f8119
f9120
f10121
f11122
f12123
num lock144
scroll lock145
semi-colon186
equal sign187
comma188
dash189
period190
forward slash191
open bracket219
back slash220
close braket221
single quote222

[1] Il “coding creativo” è l’uso della programmazione per produrre applicazioni visuali, che mostrano disegni ed animazioni: possono essere sfondi, salvaschermi, scritte in movimento, ecc. tutte prodotte da algoritmi generativi.

[2] il formato SVG permette di disegnare oggetti vettoriali tramite una descrizione testuale in XML