Facebook RSS feed

Canvas aneb grafika JavaScriptem

Zpět do sekce Základní konstrukce jazyka JavaScript

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 vypada nějak takto:

Metoda fillRect v Canvasu

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:

Mřížka – Canvas
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.

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);
Nastylovaný obdélník
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();
Styly zakončení čar

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 = "devbook.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 = "devbook.cz";
context.font = "30px sans-serif";
context.fillText(text, 5, 35);

A vložili jsme na plátno text.

Text na plátně

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. Na závěr uvedu nějaké užitečné odkazy:

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" />

 

Článek pro vás napsal Drahomír Hanák (drahoš)
Avatar
Jmenuji se Drahomír Hanák a jsem student střední průmyslové školy. Zajímám se o programování a webovou grafiku. Vytvářím interaktivní webové aplikace v jazycích JavaScript & PHP/Nette, ve kterých používám relační (PostgreSQL, MySQL) nebo objektové d...

Jak se vám líbí článek?
Celkem (5 hlasů):
4.64.64.64.64.6


 


Předchozí článek
Základy práce s DOM a události v JavaScriptu
V tutoriálu si vysvětlíme co je to DOM a jak z něj načítat elementy z webové stránky. Naprogramujeme webovou kalkulačku pomocí událostí onclick a onload.
Všechny články v sekci
Základní konstrukce jazyka JavaScript
Tutoriály v sekci se věnují vysvětlení základních konstrukcí jazyka JavaScript pro úplné začátečníky. Naučíte se programovat jednoduché webové aplikace.
Další článek
JavaScript & canvas - Mandelbrotova množina
Nakreslete si fraktál Mandelbrotovi množiny na plátno (canvas) v JavaScriptu.


 

 

Vaše komentáře:
Zobrazit starší komentáře (20)

Avatar
Michal Žůrek (misaz):

Ahoj,
nevím proč, ale já když chci vykreslit obrázek, tak se mi akorát vykreslí bílé místo. Proč?

Odpovědět 29.6.2013
Nesnáším {}, proto se jim vyhýbám.
Avatar
Odpovídá na Michal Žůrek (misaz)
Michal Žůrek (misaz):

Už jsem na to přišel, width a height jsem definoval pouze v css a on se bez definice v html asi neobejde.

Možná by se to hodilo doplnit do článku.

Odpovědět 29.6.2013
Nesnáším {}, proto se jim vyhýbám.
Avatar
Zdeněk Pavlátka:

Chci v js dělat hry a tam budu potřebovat obrázky.

Odpovědět 30.6.2013
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Kit
Redaktor
Avatar
Odpovídá na Zdeněk Pavlátka
Kit:

Tak si je slep do jednoho velkého a při prezentaci si vždy potřebný kousek vyřízni a napozicuj.

Odpovědět 30.6.2013
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Zdeněk Pavlátka:

Událost onload je součástí jQuery?

Odpovědět 19.9.2013
Kolik jazyků umíš, tolikrát jsi programátor.
Avatar
Kit
Redaktor
Avatar
Odpovědět 19.9.2013
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
1Pupik1989
Člen
Avatar
1Pupik1989:

Já bych už jen dodal, že pro opakované vykreslení obrázku lze použít pattern.

http://www.w3schools.com/…epattern.asp

 
Odpovědět   +1 21.ledna
Avatar
Odpovídá na 1Pupik1989
Drahomír Hanák (drahoš):

To je pravda. Díky za tip, určitě to do článku někdy doplním.

Odpovědět 21.ledna
Deadline je čas, kdy už by se mělo začít pracovat ...
Avatar
Nensen
Redaktor
Avatar
Nensen:

Ahoj myslim ze tam kde vykreslujes mriezku mas zle nastavenu LineTo ktora by pre pozadovany vyseldok mala brat v prvom cykle height a v druhom width.
http://jsfiddle.net/GBx9n/ ,http://jsfid­dle.net/hFZsA/. Ak nie tak sa ospravedlnujem :)

Editováno 11. dubna
 
Odpovědět 11.dubna
Avatar
Odpovídá na Nensen
Drahomír Hanák (drahoš):

Máš pravdu, díky za upozornění.

Odpovědět 11.dubna
Deadline je čas, kdy už by se mělo začít pracovat ...

 

Zobrazeno 10 z 30 zpráv

Zobrazit všechny komentáře k článku

Přidat novou zprávu

Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlaš. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.