NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 26 - Obrázky a kreslení na canvas v JavaScriptu

V minulé lekci, Práce s čísly a knihovna Math v JavaScriptu, jsme si představili si knihovnu Math pro práci s čísly.

V dnešním tutoriálu se začneme věnovat další větší kapitole, práci s grafikou v JavaScriptu. Ukážeme si, jak lze z kódu vkládat do stránky obrázky reprezentované tagem <img> a představíme si tag <canvas> (v překladu plátno). Na plátno se pak naučíme nakreslit jednoduché geometrické tvary.

Práce s obrázky

Klasický obrázek v HTML definujeme tagem <img>. Můžeme mu samozřejmě nastavit obsluhu událostí, jako je kliknutí, a to úplně stejným způsobem jako například u tlačítka.

V JavaScriptu obrázek vytvoříme jako jakýkoliv jiný element DOM zápisem:

let obrazek = document.createElement("img");

Stejného výsledku dosáhneme také zápisem:

let obrazek = new Image();

Tato varianta zároveň umožňuje nastavit obrázku rozměry. Požadovanou šířku a výšku obrázku v pixelech zadáme jako parametry v závorce:

let obrazek = new Image(100, 200); // 100 je šířka a 200 je výška

Aby se obrázek na stránce zobrazil, je ve všech případech nutné jej nejprve vložit do dokumentu, například pomocí document.body.appendChild(obrazek);

Načtení obrázku

Než s obrázkem začneme pracovat, musí se načíst. Pokud máme obrázek v HTML a JavaScript spouštíme v obsluze události onload, není žádný problém. Prohlížeč zajistí, že náš kód bude zavolán až poté, co se načte celá stránka.

V případě, že si obrázky vytváříme v JavaScriptu, musíme na načtení počkat:

let obrazek = new Image();
obrazek.src = "cesta/k/obrazku.jpg";

obrazek.onload = function () {
    // ...
}

Použili jsme událost onload na daném obrázku, a díky tomu můžeme provádět všechny operace až ve chvíli, kdy víme, že obrázek je načtený a připravený.

Další důležitou událostí při práci s obrázky je událost onerror, která je aktivována, když dojde k chybě při načítání obrázku. Ke kódu výše doplníme:

obrazek.onerror = function() {
    console.error("Chyba při načítání obrázku: " + obrazek.src);
};

V tomto příkladu se v případě chyby při načítání obrázku zobrazí v konzoli uvedený text. Obsluhu chyby lze ovšem upravit i rozšířit o další akce, jako je nastavení náhradního obrázku nebo výpis informace o chybě na stránce.

Ukažme si stejný kód s obsluhou událostí pomocí metody addEventListener():

let obrazek = new Image();
obrazek.src = "cesta/k/obrazku.jpg";

obrazek.addEventListener('load', function() {
    console.log("Obrázek je načten a připraven k práci.");
});

obrazek.addEventListener('error', function() {
    console.error("Chyba při načítání obrázku: " + obrazek.src);
});

Všimněme si, že jsme událost načtení nenastavili jako DOMContentLoaded, ale jako load. Takto ověříme, že byly načteny i externí zdroje (jako například obrázky) a ne pouze struktura HTML stránky, tedy všechny tagy DOM elementů.

Přepínání obrázků

Pojďme si ukázat jednoduchý příklad, v němž budeme měnit obrázek na stránce. Vytvoříme si přepínač. Po kliknutí na obrázek se zapnutým přepínačem vložíme do stránky obrázek s vypnutým přepínačem a naopak. Obrázky jsou ke stažení níže, pojmenujeme je prepinac0.png a prepinac1.png a uložíme je do složky nového projektu:

Základní konstrukce jazyka JavaScript Základní konstrukce jazyka JavaScript

Vytvoříme stránku, kde bude v <body> obrázek s id prepinac a připojený skript z externího souboru prepinac.js. Jako výchozí obrázek použijeme prepinac0.png:

<!DOCTYPE html>

<html lang="cs-cz">
    <head>
        <meta charset="utf-8" />
        <title>Přepínání obrázků</title>
    </head>

    <body>
        <img src="prepinac0.png" id="prepinac" alt="Přepínač" />
        <script src="prepinac.js"></script>
    </body>
</html>

Ve složce s projektem vytvoříme soubor prepinac.js:

let prepinac;

window.onload = function() {
    prepinac = document.getElementById("prepinac");
    prepinac.onclick = prepni;
}

V souboru jsme nejprve deklarovali proměnnou prepinac a po načtení stránky do ní uložili náš obrázek přepínače. Obrázku jsme nastavili obsluhu události kliknutí, která spouští funkci prepni(). Tuto funkci si vzápětí doplníme.

Změna atributu src

Ve funkci prepni() budeme potřebovat zjistit a změnit aktuální hodnotu atributu src našeho obrázku:

function prepni() {
    if (prepinac.getAttribute("src") == "prepinac0.png") {
        prepinac.src = "prepinac1.png";
    } else {
        prepinac.src = "prepinac0.png";
    }
}

Tento atribut jsme získali pomocí metody getAttribute(), která vrací přesnou hodnotu uloženou v atributu. V podmínce jsme ji poté porovnali s názvem jednoho z obrázků a následně nastavili opačný obrázek.

Kdybychom v první části podmínky místo metody getAttribute("src") použili vlastnost src a zapsali prepinac.src, získáme absolutní cestu k souboru s obrázkem, například https://www.priklad.cz/obrazky/muj-obrazek.jpg.

Stránku si otevřeme a přepínač vyzkoušíme:

Přepínání obrázků
localhost

Plátno

Nyní si představíme plátno a ukážeme si, jak na něj kreslit. Plátno je vhodné použít pro případy, kdy potřebujeme vytvářet obrázky dynamicky, protože jeho obsah musíme definovat programově v JavaScriptu.

Plátno je reprezentováno párovým tagem <canvas>. Tento element musí mít nastavené atributy width a height přímo v tagu <canvas>. Pokud je nezadáme nebo je definujeme pouze v CSS, může to vést k rozmazanému nebo zkreslenému obsahu plátna v některých prohlížečích. Zatímco CSS mění velikost zobrazení plátna, nepřizpůsobuje jeho vnitřní rozlišení.

Do těla nové HTML stránky tedy vložíme plátno takto:

<canvas width="500" height="500" id="platno"></canvas>

Získání kontextu plátna

Abychom mohli na plátno začít kreslit, musíme si získat jeho kontext. Kontext určuje, jaký typ obsahu budeme vytvářet. Existují různé typy kontextů, my se zaměříme na 2D kontext, který je ideální pro většinu grafických úloh.

Pro práci s 3D grafikou poskytuje JavaScript knihovnu WebGL (Web Graphics Library). My si jí však v tomto kurzu základů představovat nebudeme a zaměříme se pouze na práci s 2D kontextem.

Kontext plátna získáme voláním metody getContext():

let platno;
let kontext;

window.onload = function () {
    platno = document.getElementById("platno");
    kontext = platno.getContext("2d");
}

Jako parametr jsme metodě předali formou textového řetězce typ požadovaného kontextu, v našem případě 2d. Na tomto kontextu již můžeme volat různé metody pro kreslení.

Obdélníky

Základním objektem je obdélník. Obdélník nakreslíme pomocí metody fillRect() nebo strokeRect():

let platno;
let kontext;

window.onload = function () {
    platno = document.getElementById("platno");
    kontext = platno.getContext("2d");

    kontext.fillRect(50, 50, 100, 100);
    kontext.strokeRect(200, 50, 100, 100);
}

Obě metody přijímají stejné argumenty. V prvních dvou zadáváme souřadnice levého horního rohu obdélníku (x a y). Pomocí dalších dvou argumentů nastavujeme výšku a šířku obdélníku (width a height). Metoda fillRect() obdélník vyplní, metoda strokeRect() vykreslí pouze jeho obrys.

Plnému čtverci jsme nastavili souřadnice x a y na hodnotu 50, výšku a šířku jsme nastavili na 100. Obrys čtverce má stejné hodnoty, pouze osa x je posunuta na pozici 200:

Plátno
localhost

Čáry a trojúhelníky

Čáry se na plátno kreslí pomocí tzv. cest. Tyto cesty musíme začít a uzavřít. Nejprve tedy voláme metodu beginPath(), která vytvoří novou cestu a přerušuje předchozí, pokud kreslíme více nezávislých obrazců. Pro uzavření cesty zavoláme metodu closePath().

Také v dalších příkladech musíme nejprve počkat na načtení dokumentu, poté získat element plátna z HTML souboru a nastavit mu kontext. V ukázkách však už budeme uvádět pouze kód pro kresbu jednotlivých geometrických tvarů.

Vykresleme si čáru z bodu [20;20] do [40;150]:

kontext.beginPath();
kontext.moveTo(20, 20);
kontext.lineTo(40, 150);
kontext.closePath();
kontext.stroke();

Čáru jsme vytvořili pomocí metody lineTo(). Čára se ve výchozím nastavení vykreslí z pozice [0;0] (levý horní roh plátna), tuto pozici jsme proto změnili metodou moveTo(). Metoda sama o sobě nevykreslila nic, pouze přesunula kurzor plátna na zadanou pozici. Obě uvedené metody přijímají parametry x a y, tedy souřadnice pozice. Samotnou čáru jsme vykreslili metodou stroke().

Přidáním druhé čáry pak vytvoříme obrázek trojúhelníku:

kontext.beginPath();
kontext.moveTo(120, 20);
kontext.lineTo(140, 150);
kontext.lineTo(200, 100);
kontext.closePath();
kontext.stroke();

Je to proto, že při zavření cesty dochází k propojení výchozího bodu s konečným bodem.

Nyní můžeme použít také metodu fill():

kontext.beginPath();
kontext.moveTo(270, 20);
kontext.lineTo(290, 150);
kontext.lineTo(350, 100);
kontext.closePath();
kontext.fill();

Metoda nám vyplnila vnitřek cesty barvou a vykreslila vyplněný trojúhelník:

Plátno
localhost

Kruhy, kružnice a výseče

Další metodou pro kreslení na plátno je metoda arc(). Ta umí nakreslit kruh, kružnici a jejich výseče. Její syntaxe je následující:

kontext.arc(x, y, polomer, pocatecniUhel, konecnyUhel, smer);

Každý úhel udáváme v radiánech. Plný úhel je 2 * PI, stupně se převedou na radiány jako (PI / 180) * stupně.

Kruh tedy nakreslíme takto:

kontext.beginPath();
kontext.arc(100, 100, 80, 0, Math.PI * 2);
kontext.closePath();
kontext.fill();

Parametry x a y určují pozici středu kruhu. Dále jsme uvedli jeho polomer. Následují parametry pocatecniUhel a konecnyUhel, kterými určujeme, zda vykreslit celou kružnici nebo její výseč. Metodu arc() musíme používat uvnitř cesty.

Přidejme si ke stávajícímu příkladu ještě ukázku na vykreslení kružnice:

kontext.beginPath();
kontext.arc(300, 100, 80, 0, Math.PI * 2);
kontext.closePath();
kontext.stroke();

V prohlížeči se zobrazí:

Plátno
localhost

Na závěr si ukážeme, jak nakreslit výseč:

kontext.beginPath();
kontext.arc(100, 100, 80, 0, Math.PI);
kontext.closePath();
kontext.stroke();

Takto jsme si nakreslili nevyplněný půlkruh. Poté vykreslíme plný půlkruh a v metodě arc() přidáme volitelný parametr určující směr vykreslování:

kontext.beginPath();
kontext.arc(300, 100, 80, 0, Math.PI, true);
kontext.closePath();
kontext.fill();

Kružnice se ve výchozím nastavení vykresluje ve směru hodinových ručiček. Toto jsme změnili přidáním volitelného parametru smer. Pokud je hodnota parametru smer nastavena na true, vykreslování se obrátí:

Plátno
localhost

Dnes jsme si ukázali kreslení základních geometrických tvarů. Plátno nabízí mnohem více dalších možností, které si ukážeme příště.

V příští lekci, Stylování obrázků a vložení textu na plátno v JavaScriptu, budeme pokračovat v práci s obrázky, naučíme se změnit jejich barvu, šířku čáry nebo doplnit na canvas text.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 1752x (14.87 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Předchozí článek
Práce s čísly a knihovna Math v JavaScriptu
Všechny články v sekci
Základní konstrukce jazyka JavaScript
Přeskočit článek
(nedoporučujeme)
Stylování obrázků a vložení textu na plátno v JavaScriptu
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Uživatelské hodnocení:
1067 hlasů
Autor se věnuje tvorbě aplikací pro počítače, mobilní telefony, mikroprocesory a tvorbě webových stránek a webových aplikací. Nejraději programuje ve Visual Basicu a TypeScript. Ovládá HTML, CSS, JavaScript, TypeScript, C# a Visual Basic.
Aktivity