A HTML5-ös szabvány egy nagyon hasznos újítása a <CANVAS> elem.
Ezzel egy raszteres rajzolási felületet hozunk létre a weboldalon, aminek tartalmát aztán JavaScript kódok segítségével alakíthatjuk.
A Canvas használata két részből áll.
Egyrészt definiálni kell a HTML kódban a rajzfelületet a <CANVAS> elem segítségével, másrészt meg kell írni az azt "telerajzoló" JavaScript kódot.
Mivel a JavaScript kódban hivatkoznunk kell a <CANVAS> elemre, biztosítanunk kell, hogy végrehajtásakor már létezzen a megfelelő objektum a DOM-ban.
Ezért vagy a <body onload="..."> konstrukciót használjuk, vagy a kódot a <CANVAS> elem definiálása után illesszük a html kódba, ahogy az a következő példában is van:
<!doctype html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<title>Canvas példák 1.</title>
</head>
<body>
<h1>Canvas példák 1.</h1>
<canvas id="rajz" width="400px" height="500px"></canvas>
<script>
var rajz=document.getElementById("rajz");
var rajzCt=rajz.getContext('2d');
with(rajzCt)
{
beginPath();
rect(100,200,200,200);
moveTo(100,200);
lineTo(200,60);
lineTo(300,200);
stroke();
}
</script>
</body>
</html>
1. példa: egyszerű vonalas rajz.
Látható, hogy a tulajdonképpeni rajzolási műveleteket nem közvetlenül a Canvas objektumon, hanem egy úgynevezett "drawing context"-en (magyarul ???) hajtjuk végre.
Ezt a context objektumot a Canvas getContext('2d') metódusával kapjuk meg. A rajzoló utasításokat a context objektum különféle metódusainek meghívásával adhatjuk ki.
Vonalas rajz esetén az azonos rajzi tulajdonságokal (szín, vastagság, kitöltés) rendelkező elemeket egy beginPath() és egy stroke() utasítás közé lell zárni.
A tényleges kirajzolás mindig a stroke() végrehajtásával történik meg.
Természetesen kitöltést is adhatunk a rajzi elemeknek, a fill() metódus használatával.
A kitöltés színét, esetleg mintáját a fillStyle tulajdonság értéke határozza meg, míg a vonalak színét a strokeStyle
...
with(rajzCt)
{
beginPath();
rect(100,200,200,200);
fillStyle="#ff8080";
strokeStyle="red";
fill();
stroke();
beginPath();
moveTo(100,200);
lineTo(200,60);
lineTo(300,200);
fillStyle="#80ff80";
strokeStyle="green";
fill();
stroke();
}
...
2. példa: egyszerű vonalas rajz, színekkel, kitöltéssel.
Lehetőségünk van "lyukas" poligonokat is létrehozni. Ehhez arra kell ügyelnünk, hogy a belső határokat a külsőhöz képest ellentétes körüljárási iránnyal definiáljuk.
(A rect() által rajzolt téglalap körüljárási iránya óramutató szerinti.)
...
beginPath();
rect(100,200,200,200);
moveTo(110,210);lineTo(110,300);lineTo(195,300);lineTo(195,210);lineTo(110,210);
moveTo(205,390);lineTo(290,390);lineTo(290,210);lineTo(205,210);lineTo(205,390);
fillStyle="#ff8080";
strokeStyle="red";
fill();
stroke();
...
2/a. példa: "lyukas" poligon kitöltéssel.
Ha fájlból szeretnénk egy raszteres képet a vászonra helyezni, először be kell azt tölrtnünk a memóriába, mint Image() objektumot.
Az objektum onload eseménykezelőjében kell a kép tényleges kirajzolását elvégezni.
Ez azért van, mert addig nem tudjuk megjeleníteni a képet, amíg be nem töltődött, viszont a képbetöltés aszinkron folyamat, tehát a programkód futása nem ál meg a töltés befejeztéig.
...
// bitkép létrehozása
var kep=new Image();
// betöltés után jelenítsük majd meg
kep.onload=function()
{
with(rajzCt)
{
drawImage(kep,105,205,190,190);
// a kép elé rajzoljuk a házfalat az ablakkal-ajtóval
beginPath();
rect(100,200,200,200);
moveTo(110,210);lineTo(110,300);lineTo(195,300);lineTo(195,210);lineTo(110,210);
moveTo(205,390);lineTo(290,390);lineTo(290,210);lineTo(205,210);lineTo(205,390);
fillStyle="#ff8080";
strokeStyle="red";
fill();
stroke();
// tető
beginPath();
moveTo(100,200);
lineTo(200,60);
lineTo(300,200);
fillStyle="#80ff80";
strokeStyle="green";
fill();
stroke();
}
}
kep.src="tj.jpg";
...
3. példa: kép betöltése fájlból.
A Canvas pixeleihez közvetlenül is hozzáférhetünk. A vászon egy téglalap alakú részének képadatai kinyerhetők a getImageData(x0,y0,w,h) metódussal.
Ennek eredménye egy ImageData objektum, melynek data adattagja egy egydimenziós tömbben tartalmazza a pixelek adatait.
Minden pixelt 4 egymást követő érték reprezentál (R,G,B,A), így az i. sor j. pixelének adatai a data[(i*w+j)*4] - data[(i*w+j)*4+3] helyeken vannak.
ImageData objektumot üresen is létrehozhatunk a createImageData(w,h) metódussal.
A putImageData(imageData,x0,y0) segítségével pedig a Canvas megfelelő helyére rakhatunk egy ImageData objektumot.
Így pl. átmásolhatjuk a kép egyes részeit máshova, vagy a módosított képrészletet visszarajzolhatjuk a helyére. A következő példában a képet gombnyomásra "negativizálhatjuk":
minden pixel (R, G, B) értéke (255-R, 255-G, 255-B)-re változik.
...
function negativ() // negatív kép létrehozása
{
var iData=rajzCt.getImageData(0,0,600,600);
var l=iData.data.length;
for(var i=0;i<l;i++)
if (i%4!=3)
iData.data[i]=255-iData.data[i];
rajzCt.putImageData(iData,0,0);
}
...
4. példa: pixelenkénti képmanipuláció.
x. példa: térkép rajzolás szövegfájl beolvasásával
y. példa: az előbbi térkép kiegészítése JSON formátumú adatok megjelenítésével
z. példa: Mandelbrot- és Julia-halmaz böngésző