In questo articolo vediamo le funzioni trasformazione: traslazione (translating), rotazione e scalatura (scaling).
Quando si usano le trasformazioni è buona norma salvare lo stato prima del loro utilizzo, per poi ripristinare lo stato salvato all'occorenza.
Questo perchè con pochi passaggi puoi tornare allo stato iniziale senza dover riscivere tutto a ritroso.
Per capire come funziona il save / restore ho scritto un paragrafetto con un esempio esemplificativo.
SAVE e RESTORE
Il savataggio save() tiene in memoria gli stili e alcune funzioni, come le funzioni trasfosmazione, scritte in precendenza.
Gli stati salvati vengono impilati uno sopra l'altro e ripristinati dall'ultimo stato salvato.
-
ctx.save
: salva lo stato e lo impila in uno stack -
ctx.restore
: ripristina il primo stato in cima alla pila dei salvataggi (stack)
Analizziamo il programma nell'immagine sovrastante.
- nella prima riga salvo lo stato iniziale che sarà il primo stato della nostra pila (stack).
- poi aggiungo il metodo che colorerà gli elementi di blu.
- salvo di nuovo, in questo caso lo stato tiene in memoria lo stile blu e viene impilata sopra il salvataggio precendente.
- Cambiamo ancora colore, questa volta di verde e stampiamo a video un quadrato (1) che sarà di colore verde.
- Con ctx.restore() ripristiniamo il primo salvataggio della pila, quindi l'ultimo stato salvato.
- Ridisegnamo il quadrato (2), questa volta sarà di colore blu come lo stile salvato sullo stato.
- Ripristiniamo l'altro salvataggio di stato, che sarà quello che riporterà il tutto allo stato iniziale.
- come ultimo, disegnamo il quadrato che sarà di colore nero, il colore di default.
TRASLAZIONE
Questo metodo **sposta sugli assi x e y il canvas di una distanza che gli passeremo come argomento.
*ctx.translator(x,y)
.
Tutti gli oggetti disegnati dopo si sposterando di conseguenza.
ctx.fillStyle = "blue";
ctx.fillRect(10, 10, 20, 20);
ctx.translate(100, 100);
ctx.fillStyle = "green";
ctx.fillRect(10, 10, 20, 20);
Nello script vediamo due quadrati uguali per dimensioni e posizionati nelle stesse coordinate, ma di colori diversi.
Però il secondo quadrato sarà traslato di 100px in orizzonatale e 100px in verticale perchè abbiamo usato la funzione translate per spostare il canvas.
Nel esempio sottostante ho creato un grafico molto semplice che si crea dinamicamente trammite un array di numeri.
Il posizionamento orizzontale è stato fatto trammite un forEach dell'array che spostava i vari oggetti con traslate.
ROTAZIONE
Come dice si intuisce dal nome e da quello che abbiamo preso dalla traslazione, questa funzione ruota di il canvas come perno il punto di origine (0, 0).
- ctx.rotate(radianti);
La funzione rotate prende come valore i radianti e non i gradi, ma niente paura, sostituendo l'argomento con la formula (Math.PI / 180) * gradi possiamo tranquillamente usare i gradi.
Lo script ruota di 45gradi un quadrato, che come perno di rotazione ha il punto di origine del canvas (0,0).
const grade = 45;
ctx.save();
ctx.rotate( Math.PI / 180 * grade );
ctx.fillRect(200, 0, 60, 60);
ctx.restore()
Tutto questo è molto bello, ma poco utile, perché vorremmo scegliere il punto focale dove far ruotare l'oggetto.
In questo caso dobbiamo usare la transizione per scegliere il fulcro del asse di rotazione.
const grade = 45;
ctx.save();
ctx.translate(130, 130);
ctx.rotate( Math.PI / 180 * grade );
ctx.translate(-130, -130);
ctx.fillRect(100, 100, 60, 60);
ctx.restore()
In questo caso abbiamo spostato il punto di rotazione al centro del quadrato, 100 (coordinata) + 30 (metà del lato) = 130, abbiamo ruotato di 45 gradi e poi siamo ritornati alla posizione iniziale usando il traslate con gli stessi valori ma negativi.
SCALATURA
Lo Scaling ci permette di rimpicciolire e ingrandire il canvas e tutto quello che contiene.
- ctx.scale(x, y);
Il valore di default per entrambi gli argomenti è 1. Questo vuol dire che se volessimo raddoppiare il canvas il valore da passargli sarà 2 e se lo volessimo dimezzare sarà di 0.5 e così via.
ctx.fillStyle = 'blue'
ctx.fillRect(100, 100, 100, 100)
ctx.save();
ctx.scale(2, 2);
ctx.fillStyle = 'red'
ctx.fillRect(100, 100, 100, 100)
ctx.restore();
ctx.save();
ctx.translate(150, 150);
ctx.scale(.5, .5);
ctx.translate(-150, -150);
ctx.fillStyle = 'yellow'
ctx.fillRect(100, 100, 100, 100)
ctx.restore();
Il primo quadrato blue è grande 100x100px, il secondo quello rosso ha le stesse dimensioni del primo ma è stato ingrandito del 200%, mentre il terzo, il giallo, è stato rimpicciolito del 50% e come con la funzione rotate abbiamo usato due translate per scegliere il punto di scalatura (si dirà cosi?).
CONCLUSIONE
In questo articolo vediamo come funzionano le trasformazioni, che potrebbero sembrare ostiche al primo impatto ma che sono abbastanza semplici una volta capito il loro funzionamento.
Ne manca ancora una di trasformazione, quella un po' piu complessa (almeno per me) e quindi gli dedicherò un articolo a parte.
Spero che l'articolo ti sia piaciuto Se hai dei consigli, suggerimenti o critiche costruttive lasciami un commento qui sotto oppure contattami trammite i miei social.
Top comments (2)
Un altro articolo Fantastico! Bravissimo
Grazie mille, Vale.
Ma quanto è difficile cercare di spiegare qualcosa in maniera semplice. Adesso capisco la fatica che fai. ;-)