Canvas aneb grafika JavaScriptem
Možná jste si toho už všimli, možná ještě ne. HTML5 se stává
standardem, na kterém vzniká stále více aplikací. Této nové technologii
se nevyhýbají ani velké společnosti, jako třeba Google. Hodně lidí si pod
pojmem HTML5 představuje novou verzi HTML a je tomu opravdu tak. Avšak
nejedná se pouze o nové tagy, kterých je tu spousta, ale i o nové
technologie. Jedním z mnoha nových prvků je právě tag
<canvas>
. Canvas je plátno, na které můžeme kreslit. Jako
první ho uvedla firma Apple ve svém OS a poté ho zabudovala i do svého
prohlížeče Safari. Postupem času se canvas dostal i do dalších
prohlížečů a dnes je již podporován všemi moderními prohlížeči.
Syntaxe, nebo chcete-li zápis, je velmi podobný tagu
<img />
. Jediný rozdíl je v tom, že canvas je párový
tag. Zápis by mohl vypadat takto.
<canvas width="800" height="600" id="platno"> Váš prohlížeč nepodporuje tag canvas. </canvas>
Tento kód vytvoří prázdné plátno o velikosti 800x600 pixelů. Nastavíme mu atribut ID, abychom na něj mohli kreslit JavaScriptem. Atributy width a height nastaví výšku a šířku kontextu, na který budeme kreslit. Tyto rozměry nelze nastavit pomocí CSS, jelikož bychom nastavili rozměry plátna, nikoli kontextu. Pokud je ovšem nenastavíme vůbec, budou automaticky nastaveny na 300x150 pixelů.
Element je sice podporován moderními prohlížeči, avšak v prohlížeči Internet Explorer až od verze 9.0. Abychom upozornili uživatele, můžeme použít obsah tagu canvas. Tento obsah bude ignorován všemi prohlížeči, které tag podporují a zobrazí se tak jen tam, kde je ho potřeba.
2D vykreslovací kontext
Canvas podporuje zatím jen pár vykreslovacích kontextů. Jednak to je 2d, který umí, jak už asi tušíte, kreslit 2D objekty a pak také WebGL (zatím většinou jen experimental-WebGL), který umí vykreslovat i 3D objekty. Nás však zatím bude zajímat ten 2D kontext.
Systém souřadnic
Ještě než začneme kreslit, řeknu něco málo k systému souřadnic. Systém je stejný jako je to v případě CSS tedy souřadnice [0;0] určují levý horní roh plátna, nikoli stránky. Jelikož zde funguje většinou absolutní pozicování, všechny souřadnice vycházejí z bodu nula. Pozice se udává v pixelech.
Kontext plátna
Jak už jsem zmínil, kreslíme na kontext plátna. Ten musíme získat z elementu canvas. Pro každé plátno je právě jeden kontext. Tady je ukázka, jak to udělat v JavaScriptu.
// Najdeme náš canvas element var canvas = document.getElementById("platno"); // Získáme kontext plátna var context = canvas.getContext("2d"); // Syntaxe v jQuery: var canvas = $('#platno').get(0); // Kontext var context = canvas.getContext("2d");
Metoda getContext elementu Canvas získá kontext plátna s daným
vykreslovacím režimem. U zápisu v jQuery si dejte pozor, abyste metodu volali
z objektu elementu Canvas a ne z objektu jQuery, proto .get(0)
.
Nyní můžeme kreslit. Přidejte následující kód za definici proměnné
context
.
context.fillRect(20, 20, 100, 100);
Výsledek bude vypadat nějak takto:
Teď jste nakreslili váš první objekt na canvas. Je to jednoduché, ne?
Základní objekty a tvary
Základním objektem je obdélník. Máme předdefinované tři metody, kterými můžeme obdélník nakreslit. Jsou jimi fillRect, strokeRect a clearRect. Všechny tři mají stejné argumenty a to x, y, výška a šířka. Funkce fillRect odbélník vyplní, strokeRect vykreslí pouze jeho obrys a clearRect vymaže oblast daného obdélníku.
// Vyplní čtverec o velikosti a = 100 na pozici 20, 20 context.fillRect(20, 20, 100, 100); // Vymažeme vevnitř toho čtverce pole 80x80 context.clearRect(30, 30, 80, 80); // A vykreslíme si tam obrys context.strokeRect(40, 40, 60, 60);
Výsledek:
Shrnutí zápisu:
// Vyplní obdélník na x,y o velikostech width*height context.fillRect(x, y, width, height); // Vykreslí obrys obdélníku context.strokeRect(x, y, width, height); // Vymaže oblast obdélníku context.clearRect(x, y, width, height);
Čáry
Čáry se na plátno kreslí pomocí tzv. cest. Tyto cesty musíme (resp. měli bychom) je začít a uzavřít. Pro vytvoření cesty použijeme funkci beginPath(), pro uzavření pak closePath(). Samotnou čáru vykreslíme metodou lineTo(x, y). Pozice se odvíjí od poslední nastavené pozice kurzoru (zprvu 0;0), kterou nastavíme funkcí moveTo(x, y). Tato funkce nevykreslí nic, pouze přesune kurzor plátna na danou pozici. Cestu vykreslíme buďto metodou fill(), která vyplní celou cestu barvou (takto se dají kreslit vlastní tvary - proto je třeba cesty uzavírat), nebo funkcí stroke(), která vykreslí pouze čáry z dané cesty. Jednoduchý příklad vykreslí čáru z bodu 20;20 do 20;150.
context.beginPath(); context.moveTo(20, 20); context.lineTo(20, 150); context.closePath(); context.stroke();
Další příklad kreslení čar je třeba toto vykreslení mřížky:
context.beginPath(); for(var x = 0; x < canvas.width; x += 40) { context.moveTo(0.5 + x, 0); context.lineTo(0.5 + x, canvas.width); } for(var y = 0; y < canvas.height; y += 40) { context.moveTo(0, 0.5 + y); context.lineTo(canvas.height, 0.5 + y); } context.closePath(); context.stroke();
Výsledek skriptu:
Shrnutí zápisu:
// Začne cestu context.beginPath(); // Přesune kurzor na x, y context.moveTo(x, y); // Vykreslí čáru z kurzoru na x, y context.lineTo(x, y); // Uzavře cestu context.closePath(); // Vykreslí cestu context.stroke(); // Vyplní cestu context.fill();
Kruhy, kružnice a výseče
Další, co můžeme na plátno kreslit jsou kruhy, kružnice a jejich výseče. To vše umí funkce context.arc(), jejíž syntaxe je následovná:
context.arc(x, y, radius, pocatecniUhel, konecnyUhel, smer);
Argumenty x a y určují opět absolutní pozici. Radius udává poloměr kružnice, pocatecniUhel je úhel, od které se má kružnice resp. výseč vykreslit. Je udán v radiánech. Z matematiky všichni samozřejmě víme, že obvod kružnice je 2*PI a že stupně se převedou na radiány (PI/180)*stupně. Poslední proměnná je smer. Jedná se o logickou hodnotu (true/false), která udává, jestli se bude kružnice vykreslovat ve směru hodinových ručiček nebo proti němu. Základně je nastaveno true, tedy ve směru hodinových ručiček.
Kruh tedy nakreslíme takto:
context.arc(100, 100, 80, 0, Math.PI*2);
Odměnou za tak složitý skript nám bude takovýto kruh.
Styly
Někdy je třeba, aby kresba nějak vypadala. Na to jsou tu styly.
Rozlišujeme styly pro vyplnění (fill) a vykreslení obrysu (stroke). Styly
lze aplikovat na všechny objekty od obdélníků po kruhy. Máme k dispozici
dvě dvě základní proměnné, se kterými počítají metody stroke() a
fill(). Jednak je to fillStyle
a pak také
strokeStyle
. Jak už jsem říkal, jsou to proměnné a jejich
hodnoty jsou zápisy barev. Můžeme použít klasický hexadecimální zápis z
CSS např. #ffffff nebo rgb(255,255,255). Lze použít také
rgba(255,255,255,0.5), kde poslední hodnota je tzv. alfa kanál
(průhlednost) nebo hsl a hsla (stejně jako v CSS3). Jednoduché stylování
objektů:
// Styly musí být vždy před samotným vykreslením (zavoláním metody fill, stroke nebo samovykreslovacích metod, jako jsou fillRect, strokeRect ...) context.fillStyle = "#a8c101"; context.fillRect(10, 10, 50, 50);
Styly čar
Krom barvy vykreslení můžeme stylovat i jiné věci. Například pro styly
čar jsou dostupné proměnné lineWidth
- velikost vykreslených
čar, lineCap
- zakončení čar. Hodnoty jsou "butt", "round",
"square".
Ukázka stylování čar:
// Nastavíme výchozí tloušťku čar context.lineWidth = 10; context.beginPath(); context.moveTo(10, 10); context.lineTo(10, 50); // Zakulacené zakončení context.lineCap = "round"; context.stroke(); context.beginPath(); context.moveTo(40, 10); context.lineTo(40, 50); // Rovné zakončení context.lineCap = "square"; context.stroke(); context.beginPath(); context.moveTo(70, 10); context.lineTo(70, 50); // Rovné zakončení bez přesahu context.lineCap = "butt"; context.stroke();
Všimněte si, že neuzavírám cestu metodou closePath(). Je to z důvodů, že lineCap platí pouze pro jednotlivé čáry, nikoli pro komplexní cesty. Pro ty tu je proměnná lineJoin, která má opět tři možné hodnoty a to: "round" - zakulacené, "bevel" - bez přesahu a "miter" - špičaté.
Externí obrázky
Kromě toho, že na plátno můžete kreslit, je tu také možnost vykreslit i nějaký externí obrázek. Jen můžeme načíst z objektu Image (klidně i z tagu img). Nejdřív se ale musíme ujistit, že je obrázek načtený a na to slouží v DOM klasicky onload. Na plátno pak obrázek dostaneme metodou drawImage(obrazek, x, y).
Uvedu jednoduchý příklad. Je třeba na pozadí opakovat obrázky, které jsme si vytvořili. Použijeme proto metodu drawImage:
var obrazek = new Image(); obrazek.onload = function() { for(var x = 0; x < canvas.width; x++) { for(var y = 0; y < canvas.height; y++) { context.drawImage(this, x*this.width, y*this.height); } } }; obrazek.src = "images/pixel.png";
A výsledek? Obrázek typu se nám bude opakovat přes celé plátno, přičemž jsme ho načetli pouze jednou a jen vícekrát vykreslili.
Dále je možné obrázku měnit velikost. Jiný způsob zápisu funkce drawImage je následující:
context.drawImage(obrazek, x, y, vyska, sirka);
A komu by ani tohle ještě nestačilo, poslední možný zápis je:
context.drawImage(obrazek, x1, y1, vyska1, sirka1, x2, y2, vyska2, sirka2);
Parametry x1, x2 určují pozici výřezu obrázku. vysla1, sirka1 velikost výřezu. Dále x2, y2 pozici skutečného obrázku a vyska2, sirka2 určují rozměry opět skutečného obrázku. To už je složitější, avšak časem na to přijdete.
Kreslení textu
Kromě všelijakých tvarů můžeme na plátno vykreslit i text. To se dá
využít třeba jako watermark na obrázcích ve vaší galerii, popisky ke
grafům nebo úplně jinak, jak vám to jen vaše fantazie dovolí Základní funkce je
fillText(text, x, y)
. Text zde zastupuje textový řetězec, který
chceme vypsat. X a Y jsou absolutní pozice. Jednoduchý text vykreslíme třeba
takto:
var text = "itnetwork.cz"; context.fillText(text, 10, 10);
Text bude ale bez stylů a celkem malý. Proto máme k dispozici proměnnou
context.font
, kterou musíme jako třeba fillStyle volat ještě
před vykreslením textu. Hodnoty proměnné jsou totožné se zápisem v CSS u
stejnojmenné vlastnosti font. Nastavíme velikost textu třeba na 30
pixelů a použijeme font sans-serif.
var text = "itnetwork.cz"; context.font = "30px sans-serif"; context.fillText(text, 5, 35);
A vložili jsme na plátno text.
Tím bych dnešní článek ukončil. Pokud jste byli vytrvalí a dočetli jste se až sem, měli byste zvládat základní manipulaci s prvkem canvas.
Tip na závěr: Metoda
canvas.toDataUrl(mimeType)
vrací tzv. data URL plátna. Jedná se
o zakódovaný řetězec hashem Base64 a lze ho použít v img tagu místo
adresy obrázku nebo v CSS u backgrund-image. Data URL vypadá třeba:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAADFBMVEXx9vnw9fj+/v7///+vmeNIAAAAKklEQVQIHQXBAQEAAAjDoHn6dxaqrqpqAAWwMrZRs8EKAzWAshkUDIoZPCvPAOPf77MtAAAAAElFTkSuQmCC
Použití v HTML např.:
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAMAAAC67D+PAAAADFBMVEXx9vnw9fj+/v7///+vmeNIAAAAKklEQVQIHQXBAQEAAAjDoHn6dxaqrqpqAAWwMrZRs8EKAzWAshkUDIoZPCvPAOPf77MtAAAAAElFTkSuQmCC" alt="Moje kresba" />