Osservando la locandina del film, scelta nelle lezioni precedenti, notiamo come ci siano alcune peculiarità nella disposizione del testo, in particolare la spaziatura tra i caratteri (kerning) non è quella di default del font. Inoltre le due parole sono centrate rispetto al canvas e la dimensione dei caratteri varia non solo tra parola e parola ma anche all'interno della stessa.
Le API 2D del canvas mettono a disposizione una serie di metodi per la scrittura, per gestire le tematiche sollevate ci avvaliamo di due di queste funzioni:
Metodo | Descrizione |
---|---|
measureText(testo) |
restituisce un oggetto contenente una singola proprietà 'width' valorizzata con la larghezza del testo passato come argomento tenendo conto di tutte le impostazioni di stato del canvas, come il tipo e la dimesione del font |
fillText(testo, posizione_x, posizione_y) |
scrive il testo passato come argomento sul canvas allineando l'angolo in basso a sinistra con le coordinate ricevute. Anche in questo caso l'operazione è eseguita rispettando tutte le impostazioni di stato del canvas |
Ora progettiamo un algoritmo che, facendo leva su queste due funzioni, sappia costruire il testo secondo i vincoli imposti: l'idea alla base è calcolare la dimensione del riquadro contenente il testo, tenendo conto anche della spaziatura e di eventuali caratteri dalle dimensioni diverse, dopodiché procedere alla stampa di ogni singola lettera aggiungendo di volta in volta il kerning necessario e utilizzando le dimensioni del riquadro calcolato per centrare il tutto.
Aggiungiamo in coda alla funzione effettoLaMummia
:
function kerningAndSize(contesto, testo, pos_y, kerning, dimensione, eccezioni) {
contesto.save();
contesto.font = "" + dimensione + "px Esteban, Arial, serif";
eccezioni = eccezioni || {};
var dim_lettere = 0;
// calcolo la dimensione del box contenente il testo, comprensivo di kerning e
// di eventuali dimensioni difformi da quella standard
var box = (contesto.measureText(testo).width + kerning * (testo.length - 1));
// incremento o decremento la lunghezza del testo della differenza tra il font
// standard ed ogni font specificato nelle eccezioni
box = _.reduce(_.values(eccezioni), function(memo, num) {
return box + (num - dimensione); }, box);
// stampo ogni lettera singolarmente tenendo conto del kerning impostato, ritorno
// la posizione e la dimensione delle singole lettere
var lettere = _.map(testo.split(""),function(lettera, indice) {
contesto.font = "" + (eccezioni[indice] || dimensione) + "px Esteban, Arial, serif";
var pos_x = (contesto.canvas.width - box) / 2 + dim_lettere + kerning * indice;
contesto.fillText(lettera, pos_x , pos_y);
dim_lettere = dim_lettere + contesto.measureText(lettera).width;
return { x:pos_x, y:pos_y, w:contesto.measureText(lettera).width };
});
contesto.restore();
return lettere;
}
la funzione accetta in ingresso il contesto del canvas, la parola da stampare, la distanza tra una lettera e la successiva, la dimensione del font da utilizzare ed un array associativo { posizione: dimensione_font }
per gestire eventuali lettere di dimensioni diverse.
Con queste informazioni e utilizzando il metodo measureText
viene elaborata la dimensione della scritta; tale valore viene poi impiegato nel ciclo di stampa.
Le istruzioni contesto.save()
e contesto.restore()
garantiscono che all'uscita della funzione lo stato interno del canvas sia lo stesso di quello all'ingresso. Validiamo subito questa implementazione modificando il codice all'interno della funzione effettoLaMummia
:
function effettoLaMummia(canvas, prima_parola, seconda_parola) {
var contesto = canvas.getContext('2d');
contesto.fillStyle = 'rgba(242,211,83,0.8)';
var prima_parola_pos = kerningAndSize(contesto, prima_parola, 200, 60, 43);
var eccezioni = [],
posizione = Math.floor(seconda_parola.length/2);
eccezioni[posizione] = 120;
var seconda_parola_pos = kerningAndSize(contesto, seconda_parola, 330, 60, 73, eccezioni);
}
Aggiorniamo il progetto nel browser e ammiriamo il risultato ottenuto: