HTML5: Introduzione al Canvas

Una delle novità più interessanti per il supporto di HTML5 in Internet Explorer 9 è sicuramente rappresentata da supporto per il tag Canvas. Il Canvas è definito nella specifica HTML5 e offre un elemento che aggiunto alle nostre pagine, permette il rendering di grafica su una superfice bitmap dipendente dalla risoluzione. Per disegnare sulla superfice grafica offerta da questo nuovo elemento standard dell'HTML, si utilizzando dei "contesti" accessibili tramite specifiche API JavaScript, quali il contesto Canvas 2D, indicato nelle specifiche del W3C Canvas 2D API. Internet Explorer 9, introduce il supporto per le API di disegno 2D Canvas, consentendone lo sfruttamento attraverso l'accelerazione grafica come tutte le funzionalità di rendering e composizione grafica di IE9, consentendo di ottenere ottime performance. Potete ad esempio provare le demo sul test drive di IE9, in particolare trovate il famoso "acquario" assieme a tante altre demo del test drive di IE che potete provare installando la beta di IE9 o l'ultima Platform Preview . 

 Il Canvas permette di disegnare scenari che includono i rectangles, paths, lines, fills, arcs, le curve di Bézier e le quadratic curves. Canvas è un modo per implementare elementi di grafica sul web. Il tag consente di disegnare in "modo immediato" (i comandi di disegno via JS vengono inviati direttamente con l'hardware grafico), la superficie di disegno si può utilizzare per fornire grafici in tempo reale, animazioni o giochi interattivi, direttamente usando HTML e JavaScript. Le API definite da HTML Canvas 2D Context specification, consentono i seguenti scenari di disegno che includono: 

 

Il link collegati alle caratteristiche elencate sopra , vi portano su una specifica pagina demo sul test drive center di IE9 che si chiama Canvas Pad , dove potete vedere l'uso delle diverse API JS offerte dal Canvas  ad anche l'utilizzo delle stesse per gestire delle animazioni e delle trasformazioni. 

Per riassumere quello che abbiamo discusso finora:
- Canvas fornisce una superficie di disegno immediato
- Gli sviluppatori Web utilizzano le API JS esposte dal Canvas per disegnare varie primitive grafiche direttamente sulla superfice del Canvas stesso
- Le animazioni sono realizzate sulla base di JavaScript chiamando le API Canvas.

Per un uso efficace del Canvas è necessario comprendere le primitive che supporta, la specifica è vasta e ci occuperemo elementi più importanti. La prima cosa da capire riguarda il sistema di coordinate. Avvio del sistema di coordinate è in alto a sinistra nello schermo punto con coordinate (0,0) .

L'elemento Canvas in Internet Explorer 9 supporta gli attributi larghezza e altezza. (I valori di default per la larghezza e l'altezza sono 300 e 150 pixel, rispettivamente, e il colore predefinito è nero trasparente.).
È possibile ottenere e impostare le dimensioni del canvas nel DOM:

document.getElementById ('canvas1') .width =larghezza
document.getElementById ('canvas1') .height = altezza

L'utilizzo del Canvas in una pagina HTML5 è semplice. Il primo passo consiste nel definire il tag all'interno della pagina in cui vogliamo utilizzarlo,  assegnandogli un id per poi poterlo utilizzare dalle API JS come dal seguente esempio:

 

  <!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="500" height="500">
Canvas is not supported.
</canvas>
</body>
</html>

 Definito il Canvas possiamo via JavaScript acquisire un riferimento al 2D Context su cui effettuare le operazioni di disegno. Ad esempio per disegnare un cerchio utilizzando le API del 2D Context e impostando le coordinate :

<script language=javascript> …
myCanvas = document.getElementById ("myCanvas");
if (myCanvas.getContext)
{
ctx= myCanvas.getContext("2d");
ctx.arc (50, 50, 30, 0, Math.PI *2, true);
ctx.fillStyle = "rgba(0, 162, 232, .5)";
ctx.fill ();
</script>

Potete provare lo script usando il Canvas Pad degli esempi precedenti o creando una semplice pagina.

Come vedete dall'esempio, sopra il tag consente anche di gestire direttamente dall'HTML un eventuale fallback per i browser che non supportano il Canvas. Infatti all'inteno del tag, possiamo inserire il contenuto HTML alternativo da mostrare per i browser che non supportano il tag. Come per le altre funzionalità dell'HTML5 si utilizza un approccio feature detection. Oltre a gestire il fallback per i browser che non supportando il Canvas si può utilizzare lo stesso approccio feature detection via JS. Ecco di seguito un esempio di funzione che provede a verificare il supporto del Canvas, senza entrare nel merito del tipo di browser (browser detection code), approccio quest'ultimo di gestire il riconoscimento del browser e non della specifica funzionalità che è da evitare in generale perchè fonte di codice meno robusto e riutilizzabile. Ecco l'esempio di feature detection del Canvas via JS:

 function supports_canvas()
{ return !!document.createElement('canvas').getContext; }

La funzione crea un elemento di tipo canvas e verifica la presenza del metodo getContext(), disponibile solo su istanze dell'elemento canvas. Nella pagina possiamo usare un if supports_canvas() per gestire appunto la verifica ed eseguire in conseguenza del codice alternativo.

Disponibili librerie come Modernizr che offrono una serie di funzioni precostruite per effettuare la feature detection delle principali funzionalità del HTML5 con maggiore semplicità. Ad esempio per quanto riguarda il Canvas, se nella pagina abbiamo referenziato Modernizr.js possiamo determinare il supporto di questo tag con molta seplicità usando la specifica funzione prevista come mostrato di seguito:

if (Modernizr.canvas)
{ // Canvas supported ! }
else
{ // no canvas support available}
 

Siccome le implementazioni non sono sempre omogenee nel senso che non tutte le api grafiche del canvas sono implementate su tutti i browser che supportando il canvas, si può con lo stesso approccio di cui sopra verificare anche la presenza di specifiche features. Ad esempio per verificare che nel browser in cui si sta eseguendo la nostra pagina il canvas supporti il testo:

if (Modernizr.canvastext)
{ // draw text! }
else
{ // no native canvas text support }

invece senza la libreria Modernizr :

 function supports_canvas_text()
{
if (!supports_canvas())
{
return false;

}
var dummy_canvas = document.createElement('canvas');
var context = dummy_canvas.getContext('2d');
return typeof context.fillText == 'function';
}

Dove utiliziamo la funzione sopra per verificare il canvas e poi acquisito il contesto di un canvas generato per il test, si verifica che ci sia il metodo fillText e che sia una function.

Abbiamo visto nel precedente esempio che è veramente facile da disegnare elementi come il cerchio dell'esempio colorati nel modo desiderato.
Con le proprietà fillStyle e strokeStyle si può facilmente impostare i colori utilizzati per il rendering di forme riempite . I valori di colore è possibile utilizzare sono gli stessi in CSS: codici hex, rgb (), RGBA () e anche HSLA (), entrambi supportati in IE9 .
Con fillRect è possibile disegnare rettangoli pieni. Con strokeRect è possibile disegnare rettangoli utilizzando solo i confini, senza ripieno. Se si desidera cancellare una parte specifica del canvas dal contenuto disegnato, è possibile utilizzare clearRect. Questi tre metodi utilizzano tutti gli stessi argomenti: x, y, larghezza, altezza. I primi due argomenti raccontare la (x, y) le coordinate, e gli ultimi due argomenti si impostano le dimensioni larghezza e l'altezza per il rettangolo

  // Draw black rect
ctx.fillRect(50, 20, 145, 145);

  // Draw blue rect
ctx.fillStyle = "rgb(0, 162, 232)";
ctx.fillRect(135, 85, 125, 125);

  // Increase line width
ctx.lineWidth = 5;

// Draw black rect outline
ctx.strokeStyle = "rgb(0, 0, 0)";
ctx.strokeRect(50, 335, 145, 145);

  // Draw blue rect outline
ctx.strokeStyle = "rgb(0, 162, 232)";
ctx.strokeRect(135, 275, 125, 125);

  // Draw transparent yellow rect
ctx.fillStyle = "rgba(255, 255, 0, 0.75)";
ctx.fillRect(210, 180, 125, 125);

Ecco il risultato:

Oltre alle precedenti API con il canvas si possono usare i paths e le line consentono di disegnare forme personalizzate. Per creare una forma personalizzata è semplice, per iniziare a disegnare il percorso si usa beginPath uso, quindi si compone la forma utilizzando linee, curve e altre primitive. Una volta fatto, chiamata riempimento e traccia se si vuole riempire la forma o il disegno del tracciato, quindi chiamare stroke per finire la tua forma. Di seguito un esempio per disegnare uno Smile:

 ctx= myCanvas.getContext("2d");
ctx.beginPath();
ctx.arc(75,75,50,0,Math.PI*2,true); // cerchio viso
ctx.moveTo(110,75);
ctx.arc(75,75,35,0,Math.PI,false); // bocca
ctx.moveTo(65,65);
ctx.arc(60,65,5,0,Math.PI*2,true); // occhio
ctx.closePath();
ctx.moveTo(95,65);
ctx.arc(90,65,5,0,Math.PI*2,true); // occhio
ctx.stroke();

Ecco il risultato:

Si possono gestire anche gradienti e shadows e potete vedere gli esempi nel Canvas Pad. Ad esempio per i gradienti:

// Define gradients
var gradient1 = ctx.createLinearGradient(0, 0, 0, 500);
gradient1.addColorStop(0, "#00ABEB");
gradient1.addColorStop(1, "white");

// Draw
ctx.fillStyle = gradient1;
ctx.fillRect(0,0,400,500);

si ottiene:

In un canvas è anche possibile disegnare un immagine con la specifica api. Ad esempio di seguito un esempio:

function draw(){

var image = document.getElementById("myimg");
ctx.drawImage(image, -10, 45, 400, 400);
}

dove myimg è il riferimento ad un elemento di tipo immagine che avete all'interno della pagina. Il tipico uso di un immagine per poi gestire animazioni o altro su un canvas, parte genericamente dall'utilizzo di un immagine, spesso nascosta, che viene caricata nel dom. Per manipolare l'immagine solo al termine del download della stessa si inserisce genericamente il codice nell'evento load della pagina:

 window.addEventListener("load",draw, false);

Si può anche utilizzare un elemento Image e per capire quando l'immagine è disponibile ed ha terminato il download genericamente si usa l'questo tipo di approccio:

img = new Image();

img.addEventListener("load", function(){

imgWidth = 100;
imgHeight = 100;
ctx.drawImage(img, 0, 0, imgWidth, imgHeight);

}, false);

 

img.src = "IELogo.png";

 

 Potete provare sempre sul Canvas Pad il supporto per le immagini.

L'HTML5 consente anche l'utilizzo di video con lo specifico tag video che viene supportato anche in IE9 ed è possibile anche utilizzare anche un video all'interno di un canvas per gestrire particolari effeti grafici:

// Create a timer to draw the video
timer1 = setInterval(drawVideo, 16);

function drawVideo()
{
if (!isNaN(video.duration))
{
// Play the video
video.play();

// Draw the video
ctx.drawImage(video, 0, 0, 400, 500);
}
}

Il timer impostato a 16ms consente di disegnare nel canvas  il video contenuto nel tag html con la funzione drawImage. 

E' possibile anche sovrapporre direttamente un canvas sopra un tag video con l'opportuno z-index, per avere appunto sopra al video delle animazioni, banner pubblicitari e contenuti interattivi. In un prossimo post illustrerò proprio un esempio di questo tipo.

Si possono anche applicare delle trasformazioni aal canvas e in conseguenza agli elementi rappresentati nello stesso. Possiamo applicare spostamenti, rotazioni, scaling. anche qui avvalendosi con IE9 di tutta la potenzialità di sfruttare per queste operazioni l'accelerazione hardware e le potenzialità della GPU.

Di seguito aggiungo un esempio di video ridisegnato in un canvas ruotato e translato che viene aggiornato a 60 frame al secondo. Anche qui abbiamo un  timer impostato a 16ms per presentare ridisegnare il video, e postete vedere la rotazione sul canvas con la specifica funzione:

<!DOCTYPE html>
<html xmlns="
https://www.w3.org/1999/xhtml ">
<head>
<title></title>
<script language='javascript' type='text/javascript'>

     window.addEventListener("DOMContentLoaded", Init, false);

        function Init() {
var video = document.getElementById("vid");
var canvas = document.getElementById("can");
var ctx = canvas.getContext("2d");

ctx.translate(100, 10);
ctx.rotate(-0.2);

            var waiting = setInterval(function () {
if (video.readyState ==2) {
setInterval(function () {
ctx.drawImage(video, 0, 200, 640, 360);
}, 50);

clearInterval(waiting);
}

}, 200);
}

    </script>

</head>
<body>
<video style="display: none" id="vid" src="fish.mp4" width="640" height="360" controls
autoplay></video>
<canvas id="can" width="1000" height="600"></canvas>
</body>
</html>

Come vedete dal codice terminato il caricamento del DOM viene eseguita la funzione Init che accede al contesto 2D dell'elemento canvas di nome can  inserito nella pagina e che  applica allo stesso una translazione e una rotazione, per poi avviare un intervallo che attende l'avvio del video. Appena avviato il video viene rimosso, l'intervallo con la funzione di attesa del caricamento del video, ed avviato un timer di 16 millisecondi che ridisegna a 60 frame al secondo il video, che questa volta appare ruotato, proprio per la rotazione dell'intero canvas. Di seguito avete l'immagine di come si presenta il video nel canvas trasformato opportunamente:

 

 

 

Possiamo ad esempio, anche effettuare uno scale di un video, ed anche qui avvalendosi con IE9 di tutta la potenzialità di sfruttare per queste operazioni l'accelerazione hardware nell'operazione di rendering e scale:

  <html >

<head>
<script type="text/javascript" src="default.js"></script>
<style>
span {left: 450px; position: absolute; opacity:.75}
.Inc {top: 50px}
.Dcr {top: 80px}
button {width: 150px}
</style>
 

</head>
<body>

<video id="myVideo" src="fish.mp4" loop autoplay style="display: none">
Video is not supported.
</video>

<canvas id="myCanvas" height="480" width="640" style="left: 0px; top: 0px; position: absolute;" >
Canvas is not supported
</canvas>
<span class="Inc"> <button type="button" onclick="scaleFunc(1)"> Zoom in </button></span>
<span class="Dcr"> <button type="button" onclick="scaleFunc(-1)";> Zoom out </button></span>
</body>
</html>

Di seguito la funzione scalefunction che effettua lo scaling:

 function scaleFunc( scaleFactor) {
ctx.clearRect (0, 0, 645, 485);
if (scaleFactor==1) {scale = 1.1;}
else {scale = .9;
}
ctx.scale (scale, scale);
}

 ometto la funzione che ridisegna il video in un interval che abbiamo già descritto prima.

 Per continuare a provare il canvas ed approfondire le API vi ricordo il Canvas Pad .

Segnalo anhce un interessante plugin disponibile per convertire da Adobe illustrator a codice per il Canvas su cui trovate maggiori informazioni qui .

In un prossimo post vedremo come gestire le animazioni nel canvas attraverso il JavaScript .