Canvas
indica sia un nuovo elemento HTML che un'API per il disegno 2d all'interno
della finestra creata dall'elemento.
Tempo fa avevo scritto una guida simile che usava SVG. I miglioramenti di canvas permettono
adesso di avere un valido tool che si aggiunge e in alcuni casi puo' sostituire per la
grafica via Web sia SVG che flash e gli applet Java. Inoltre il suo uso e' relativamente
semplice.
Ma tenete conto che si tratta di programmare in Javascript!
Se non conoscete Javascript o addirittura la programmazione in un qualsiasi linguaggio, allora
non basterebbe un anno per imparare. Se poi voi siete gia' programmatori esperti di altri
linguaggi allora solo guardando le figure imparerete a programmare usando Canvas in un'ora.
Per ogni immagine e' riportato il programma completo che potete salvare su disco, provarlo
cosi com'e' e modificarlo a piacere. Per fare questo si consiglia di eseguire prima il programma e poi selezionare "File/Salva pagina con nome" scegliendo come formato "pagina web completa" : in questo modo saranno copiati automaticamente eventuali file aggiuntivi richiesti dal programma canvas.Nei primi esempi per semplicita' uso solo Javascript. Ma ormai e' risaputo che il
trattamento in maniera semplice ed efficace dell'interattivita' richiede l'uso di una
particolare libreria (o API) jQuery
. Questa viene introdotta poco a poco
negli ultimi esempi.
<html> <head> <title>Canvas tutorial</title> <script type="text/javascript"> function disegna(){ var canvas = document.getElementById('esempio'); if (canvas.getContext){ var cg = canvas.getContext('2d'); cg.fillStyle='rgb(255,255,0)'; cg.fillRect(25,25,100,100); cg.clearRect(45,45,60,60); cg.strokeStyle='red'; cg.strokeRect(50,50,50,50); } } </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body onload="disegna();"> <canvas id="esempio" width="150" height="150"></canvas> </body> </html>
fillRect()
disegna un
quadrato nero, clearRect()
disegna un quadrato trasparente, strokeRect()
disegna un quadrato
con i soli 4 lati. Gli argomenti sono ovvi ed e' chiaro anche come il sistema di riferimento
sia da sinistra a destra per la x e dall'alto in basso per la y.
strokeStyle
e fillStyle
permettono di definire il colore
usando la notazione dell'html.
canvas
dove
viene specificata la dimensionecanvas { border: 1px solid black; }
<body onload="disegna();">
indica a Javascript di eseguire
il metodo disegna() al caricamento della pagina. Questo metodo si accerta che esiste un elemento
canvas
nel DOM ed estrae le informazioni del contesto grafico caricandole nella
variabile cg
. Questa variabile sara' usata per richiamare tutti i metodi grafici
che si applicano a una canvas.
path
che permette di
generare forme qualsiasi in maniera molto compatta.Un path (cammino in inglese)
e' generato da una serie di punti collegati da segmenti di retta o anche da curve.
<head> <title>Canvas tutorial</title> <script type="text/javascript"> function disegna(){ var canvas = document.getElementById('esempio'); if (canvas.getContext){ var cg = canvas.getContext('2d'); cg.beginPath(); cg.arc(75,75,50,0,Math.PI*2,true); cg.moveTo(115,75); cg.arc(75,75,40,0,Math.PI*2,false); cg.strokeStyle='red'; cg.lineWidth=3; cg.stroke(); cg.closePath(); cg.beginPath(); cg.arc(75,75,30,0,Math.PI*2,true); cg.fillStyle='rgb(255,255,0)'; cg.fill(); } } </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body onload="disegna();"> <canvas id="esempio" width="150" height="150"></canvas> </body> </html>
beginPath()
indica l'inizio della definizione del path.
arc()
che disegna un arco di cerchio
moveTo()
serve solo a saltare al punto indicato senza disegnare
niente.Notate come questo sia necessario per avere i due cerchi separati. Il secondo cerchio
inoltre e' disegnato da destra a sinistra(come indica il false
nella chiamata).stroke()
disegna il path.closePath()
ci permette
di azzerare il path e ricominciare daccapo. Un nuovo cerchio e' disegnato e alla fine viene
rappresentato in nero con fill()
<html> <head> <title>Canvas tutorial</title> <script type="text/javascript"> function disegna(){ var canvas = document.getElementById('esempio'); if (canvas.getContext){ var cg = canvas.getContext('2d'); var cw = 200; gradiente = cg.createLinearGradient(0,0,cw,cw); gradiente.addColorStop(0,'yellow'); gradiente.addColorStop(1,'magenta'); cg.fillStyle= gradiente; cg.fillRect(0,0,cw,cw); cg.strokeStyle = "black"; cg.strokeRect(0,0,cw,cw); var sf=1; for (var i=0;i<10;i++){ cg.translate(cw/2,cw/2); cg.rotate(Math.PI/180*5*(i+1)); sf = sf*0.95; cg.scale(sf,sf); cg.translate(-cw/2,-cw/2); cg.fillRect(0,0,cw,cw); cg.strokeRect(0,0,cw,cw); } } } </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body onload="disegna();"> <canvas id="esempio" width="200" height="200"></canvas> </body> </html>
disegna
crea un gradiente lineare giallo-magenta
e lo usa per riempire il rettangolo piu' esterno della spirale.
<html> <head> <title>Canvas tutorial</title> <script type="text/javascript"> var cw; var cg; var i ; var im1; var vis; var posy=50; function init(){ im1 = new Image(); im1.src="srunning.gif"; var canvas = document.getElementById('esempio'); if (canvas.getContext){ cg = canvas.getContext('2d'); cw = 400; vis = 0.5; cg.fillStyle= "rgba(0,100,100,"+vis+")"; cg.fillRect(0,0,cw,cw); cg.font='40pt Arial Bold'; cg.textAlign='left'; cg.strokeText('Ciao a tutti',50,posy); cg.drawImage(im1,50,100,100,100); cg.save(); i=0; } } function ruota() { cg.restore(); cg.translate(100,150); cg.rotate(-Math.PI/180*5*(i)); cg.translate(-100,-150); cg.clearRect(0,0,cw,cw); vis = vis+.01; if(vis>1.)vis=0.; cg.fillStyle= "rgba(0,100,100,"+vis+")"; cg.fillRect(0,0,cw,cw); posy=posy+2;if(posy>cw-50)posy=50; cg.strokeText('Ciao a tutti',50,posy); cg.translate(100,150); cg.rotate(Math.PI/180*5*(i+1)); cg.translate(-100,-150); cg.drawImage(im1,50,100,100,100); i++; T=setTimeout("ruota()", 50) } function resetta() { cg.restore(); cg.translate(100,150); cg.rotate(-Math.PI/180*5*(i)); cg.translate(-100,-150); cg.clearRect(0,0,cw,cw); vis=0.5; i=0; posy = 50; clearTimeout(T); } </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body onload="init();"> <input value="START" type="button" onClick="ruota()"> <input value="STOP" type="button" onClick="clearTimeout(T)"> <INPUT onClick="resetta()" type="button" value=RESET><canvas id="esempio" width="400" height="400"></canvas> </body> </html>
init(), ruota(), resetta()
. Tutte le quantita' che
devono essere usate da piu' di una funzione sono dichiarate all'inizio
ruota()
che attraverso la setTimeout
richiama se stessa ogni 50 millisecondi.
restore()
piu' i comandi per
"disfare" la rotazione.
clearRect
save()
che salva lo stato iniziale per
permettere di recuperarlo quando e' necessario con restore()
.
strokeText()
esegue la scrittura di testi. Essa ha tutte le possibilita'
offerte dai programmi di grafica evoluti.
drawImage()
disegna un'immagine. Questa necessita la definizione di
un oggetto Image im
e il caricamento della stessa con im.src=url
.
Un'immagine
puo' essere anche un file svg oppure un'altra canvas.
<html> <head> <title>Canvas tutorial</title> <script type="text/javascript"> function disegna(){ var canvas = document.getElementById('esempio'); if (canvas.getContext){ var max = 1000; var redVal=0; var greenVal=0; var blueVal=0; var prevx = 512.; var prevy = 512.; var x = 0.; var y = 0.; var dis = 10; var an = 0; var c1 = Math.random()*1000; var inter = 5; cg = canvas.getContext('2d'); cw = 1024; cg.fillStyle= 'rgba(0,100,100,0.5)'; cg.fillRect(0,0,cw,cw); cg.beginPath(); cg.moveTo(512,512); for (var i=0; i<=max; i++) { x = prevx + dis * Math.sin(an); y = prevy + dis * Math.cos(an); if(x > 1024) break; if(x < 1) break; if(y > 1024) break; if(y < 1) break; x1 = Math.round(x); y1 = Math.round(y); cg.lineTo(x1,y1); prevx = x; prevy = y; dis = dis + inter; an = an + c1; } redVal = Math.round(Math.random()*255); greenVal = Math.round(Math.random()*255); blueVal = Math.round(Math.random()*255); cg.fillStyle ="rgb(" + redVal + "," + greenVal + "," + blueVal + ")"; redVal = Math.round(Math.random()*255); greenVal = Math.round(Math.random()*255); blueVal = Math.round(Math.random()*255); cg.strokeStyle="rgb(" + redVal + "," + greenVal + "," + blueVal + ")"; cg.fill(); cg.stroke(); } } </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body onload="disegna();"> <canvas id="esempio" width="1024" height="1024"></canvas> </body> </html>
onload
nel'elemento html body
path
)dipendente
da alcuni parametri scelti a caso . Anche la colorazione e' fatta a caso.
path
potete usare lo stesso schema
per generare un'infinita' di tipi di immagine. Ad esempio grafici di funzione,
disegni frattali tipo curva del dragone,figure di Lissajous, etc
<html> <head> <title>Canvas tutorial</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script type="text/javascript"> $(document).ready(function(){ var canvas = document.getElementById('esempio'); var cg = canvas.getContext('2d'); cg.fillStyle='rgb(255,255,0)'; cg.fillRect(25,25,100,100); cg.clearRect(45,45,60,60); cg.strokeStyle='red'; cg.strokeRect(50,50,50,50); }) </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body> <canvas id="esempio" width="150" height="150"></canvas> </body> </html>
disegna()
richiamata nell'elemento
body
. Il caricamento e' fatto da jQuery eseguendo l'istruzione:$(document).ready(function(){})Questa dice a jQuery di eseguire il codice contenuto tra {} quando il caricamento della pagina e' completo. Questa e' la maniera tipica di jQuery di gestire gli "eventi" che accadono durante la visualizzazione della pagina nel browser. Voi date il nome dell'oggetto interessato (in questo caso tutto il documento indicato in jQuery con $(document) e il nome della funzione che gestisce "l'evento" (ready) separati dal . e quindi definite quello che deve essere fatto.
<html> <head> <title>Canvas tutorial</title> <script src="jquery-1.js"></script> <script type="text/javascript"> var cw; var cg; var i ; var im1; var vis; var posy=50; im1 = new Image(); im1.src="srunning.gif"; function init(){ cg = $('#esempio')[0].getContext("2d"); cw = 400; vis = 0.5; cg.fillStyle= "rgba(0,100,100,"+vis+")"; cg.fillRect(0,0,cw,cw); cg.font='40pt Arial Bold'; cg.textAlign='left'; cg.strokeText('Ciao a tutti',50,posy); cg.save(); i=0; } function ruota() { cg.restore(); cg.translate(100,150); cg.rotate(-Math.PI/180*5*(i)); cg.translate(-100,-150); cg.clearRect(0,0,cw,cw); vis = vis+.01; if(vis>1.)vis=0.; cg.fillStyle= "rgba(0,100,100,"+vis+")"; cg.fillRect(0,0,cw,cw); posy=posy+2;if(posy>cw-50)posy=50; cg.strokeText('Ciao a tutti',50,posy); cg.translate(100,150); cg.rotate(Math.PI/180*5*(i+1)); cg.translate(-100,-150); cg.drawImage(im1,50,100,100,100); i++; T=setTimeout("ruota()", 50); } function resetta() { cg.restore(); cg.translate(100,150); cg.rotate(-Math.PI/180*5*(i)); cg.translate(-100,-150); cg.clearRect(0,0,cw,cw); vis=0.5; i=0; posy = 50; clearTimeout(T); } $(document).ready(function(){ $("#start").click(function(){ ruota(); }); $("#stop").click(function(){ clearTimeout(T) }); $("#reset").click(function(){ resetta(); }); $(im1).load(function(){ cg.drawImage(im1,50,100,100,100); }); init(); }) </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body> <input value="START" type="button" id="start"> <input value="STOP" type="button" id="stop" > <input type="button" id="reset" value=RESET><canvas id="esempio" width="400" height="400"></canvas> </body> </html>
init(),ruota() e resetta()
sono rimaste identiche
body e input
sono state eliminate le specifiche onload e onclick
$(document).ready(function(){})
con l'indicazione
di cosa deve essere fatto quando un bottone e' cliccato. Alla fine inizia
l'esecuzione col richiamo di init()
jQuery
si occupa anche di controllare il corretto caricamento dell'immagine. Infatti il disegno e' fatto solo se e quando l'immagine e' disponibile col codice $(im1).load(function(){
cg.drawImage(im1,50,100,100,100);
});
<html> <head> <title>Canvas tutorial</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script type="text/javascript"> var x = 150; var y = 150; var dx=2; var dy=4; var r = 10; var larghezza; var lunghezza; var cg; function init() { cg = $('#esempio')[0].getContext("2d"); larghezza = $('#esempio').width(); lunghezza = $('#esempio').height(); return setInterval(disegna, 10); } function disegna() { cg.clearRect(0,0,larghezza,lunghezza); cg.beginPath(); cg.arc(x, y, r, 0, Math.PI*2, true); cg.closePath(); cg.fill(); if(x+dx > larghezza || x+dx < 0) dx = -dx; if(y+dy > lunghezza || y+dy < 0) dy = -dy; x += dx; y += dy; } $(document).ready(function(){ init(); }) </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body> <canvas id="esempio" width="150" height="150"></canvas> </body> </html>
init()
e disegna()
$(document).ready(function(){
contiene solo la chiamata a init()
che provvede a caricare varie costanti e a far partire l'animazione.
setInterval(disegna, 10)
che cambiando l'incremento dx,dy
delle coordinate tra un frame e l'altro.
width() e height()
applicate all'oggetto canvas
$('#esempio')
permettono di ottenerne la larghezza e la lunghezza.
<html> <head> <title>Canvas tutorial</title> <style type="text/css"> canvas { background: rgb(220,220,220) } </style> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> <script type="text/javascript"> var dis var i=0 var y= new Array() var x= new Array() var vx = 10 function pallino(x,y,color){ dis.strokeStyle = color dis.fillStyle = color dis.beginPath() dis.arc(x, y, 10, 0, Math.PI*2,true) dis.closePath() dis.stroke() dis.fill() } function barretta(x,y,color){ dis.strokeStyle = color dis.beginPath() dis.moveTo(x,y) dis.lineTo(x+20,y) dis.stroke() } function draw() { if(i==10) return y[i]=30+(10*Math.pow(i,2))/2 x[i]=200+i*vx dis.clearRect(21,0,758,444) pallino(100,y[i],"red"); pallino(x[i], y[i],"green") barretta(0,y[i],"red") barretta(780,y[i],"green") if(i>0){ dis.beginPath() dis.strokeStyle = "red" dis.moveTo(100,y[0]) for (tq = 1; tq < i+1; tq=tq+1) { dis.lineTo(100,y[tq]) } dis.stroke() dis.beginPath() dis.strokeStyle = "green" dis.moveTo(200,y[0]) for (tq = 1; tq < i+1; tq=tq+1) { dis.lineTo(x[tq],y[tq]) } dis.stroke() } i++ T=setTimeout("draw()", 500) } function disegno() { dis = $('#prova')[0].getContext("2d"); dis.strokeStyle = "rgb(200,0,0)" pallino(100,30,"red"); pallino(200,30,"green") dis.strokeStyle = "rgb(0,0,200)" dis.beginPath() dis.moveTo(0,445) dis.lineTo(800,445) dis.closePath() dis.stroke() } function resetta() { dis.clearRect(0,0,800,444) i=0 pallino(100,30,"red"); pallino(200,30,"green") clearTimeout(T) } $(document).ready(function(){ $("#start").click(function(){ draw(); }); $("#stop").click(function(){ clearTimeout(T) }); $("#reset").click(function(){ resetta(); }); disegno(); }) </script> <style type="text/css"> canvas { border: 1px solid black; } </style> </head> <body> <input value="START" type="button" id="start"> <input value="STOP" type="button" id="stop" > <input type="button" id="reset" value=RESET> <p> <canvas id="prova" width="800" height="500"> </body> </html>
pallino(),barretta(),draw(),disegno(),resetta()
pallino() e barretta()
servono a semplificare il disegno.
disegno()
al caricamento del documento, draw()
al pulsante START e resetta()
a RESET.