IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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 - 2D kontext plátna v JavaScriptu

V minulé lekci, Stylování obrázků a vložení textu na plátno v JavaScriptu, jsme se naučili obrázky na plátně stylovat a ukázali jsme si, jak vkládat na canvas externí obrázky nebo text.

V dnešním JavaScript tutoriálu se podíváme podrobněji na kontext plátna. Naučíme se jej posouvat, přetáčet nebo měnit jeho velikost. Ukážeme si také další barevné efekty jako je přidání stínu nebo barevná výplň obrázků.

Transformace kontextu

Velmi důležité jsou při zpracovávání obrázku transformace. Představme si, že chceme obrázku nastavit hodně specifický například 10 pixelů široký rámeček, který bychom jen v CSS nenastylovali. Samozřejmě všude můžeme vypisovat, aby se vykresloval na pozici x + 10, y + 10, ale jednodušší je využít posunu kontextu.

Uložení kontextu

Před jakoukoliv manipulací s kontextem si jej uložíme. Mohli bychom ho sice později vrátit do pozice x - 10 a y - 10, ale je to zbytečně pracné a navíc si musíme pamatovat tyto hodnoty. Proto má kontext metody save() a restore(). Ani jedna nepožaduje žádný parametr. Metoda save() si uloží aktuální stav kontextu a metoda restore() jej obnoví.

Jako příklad si vykreslíme obrázek s červeným rámečkem. Do těla HTML souboru doplníme obrázek a plátno o trochu větší než obrázek:

<img src="foto.jpg" id="obrazek" />
<canvas id="platno" width="510" height="340"></canvas>

Poté si načteme plátno, kontext a obrázek. Kontextu nastavíme barvu výplně na červenou a překreslíme jí celý <canvas>. Kontext metodou save() uložíme:

let platno;
let kontext;
let obrazek;

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

    // Sem později vložíme metodu scale() pro zmenšení obrázku

    kontext.fillStyle = "red";
    kontext.fillRect(0, 0, 510, 340);
    kontext.save();

    // Zde vzápětí doplníme zbývající kód
}

Posun kontextu

Posun kontextu provádíme metodou translate(), která přijímá parametry x a y pro souřadnice posunu. Nový nulový bod bude na těchto souřadnicích. My si plátno posuneme o kladných 10 px jak po ose x, tak po ose y a na nové pozici vykreslíme obrázek. Kontext plátna pak obnovíme:

kontext.translate(10, 10);
kontext.drawImage(obrazek, 0, 0);
kontext.restore();

V prohlížeči vidíme, že se obrázek nakreslil na pozici [10;10], i když jsme pro vykreslení zadali pozici [0;0]. Může za to právě náš posun:

Plátno
localhost

Zvětšení a zmenšení kontextu

Kontext můžeme také zmenšovat a zvětšovat. Slouží k tomu metoda scale(), která jako parametry přijímá násobky skutečné hodnoty pro souřadnice x a y. Pro zmenšování se zadávají desetinná čísla menší než 1. Doplňme do předchozí ukázky před vykreslení obrázku tento řádek:

kontext.scale(0.5, 0.5);

Obrázek je nyní v prohlížeči poloviční:

Plátno
localhost

Rotace

Poslední transformaci kontextu představuje rotace. Tu si vyzkoušíme opět na čtverci, který otočíme o 45 stupňů metodou rotate(). Ta jako parametr přijímá úhel v radiánech. V ukázce nejprve kontext uložíme, pak metodou translate() nastavíme posun, abychom vykreslili otočený čtverec celý. Doplníme metodu pro přetočení kontextu, vykreslíme náš čtverec a kontext obnovíme:

kontext.save();
kontext.translate(100, 100);

// Rotace o 45 stupňů převedených na radiány
kontext.rotate(45 * Math.PI / 180);

kontext.strokeRect(0, 0, 50, 50);
kontext.restore();

Výsledek:

Plátno
localhost

Mazání plátna

Kromě vykreslení obrázku budeme určitě někdy chtít vybraný obrázek nebo obsah celého plátna smazat. Můžeme použít metodu fillRect() a překreslit plátno na bílo. Vhodnější je však použít metodu clearRect(), která vymaže obsah plátna na dané ploše. Parametry má stejné jako metoda fillRect().

Plátno totiž ve výchozím stavu není bílé, ale je průhledné. Pokud tedy vymažeme plátno pomocí fillRect(), sice uvidíme bílou plochu, ale neuvidíme, co bylo pod plátnem.

Abychom viděli rozdíl mezi zmíněnými metodami, vložíme do těla HTML <div> se žlutým pozadím a plátnu nastavíme absolutní pozici, aby ho částečně překrývalo. Plátnu doplníme černý rámeček:

<div id="podklad" style="width: 200px; height: 200px; background-color: yellow;"></div>
<canvas id="platno" width="200" height="200" style="border: 1px solid black; position: absolute; left: 30px; top: 30px;"></canvas>

V JavaScriptu na plátnu namalujeme dva čtverce:

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

kontext.fillRect(20, 40, 30, 30);
kontext.fillRect(70, 40, 30, 30);
};

Výsledek v prohlížeči:

Plátno
localhost

Nyní zavoláme metodu fillRect() a přebarvíme levý čtverec bílou barvou. Druhý čtverec vymažeme metodou clearRect():

kontext.fillStyle = "white";
kontext.fillRect(20, 40, 30, 30);

kontext.clearRect(70, 40, 30, 30);

Výsledek:

Plátno
localhost

Kdybychom chtěli vymazat celé plátno, změníme poslední řádek takto:

kontext.clearRect(0, 0, platno.width, platno.height);

Stín

Obrázkům na plátně můžeme přidat stín. Vlastností shadowColor nastavíme barvu stínu, vlastnostmi shadowOffsetX a shadowOffsetY nastavíme posun stínu a pomocí shadowBlur určíme, jak moc bude stín rozostřený:

kontext.shadowColor = "red";
kontext.shadowOffsetX = 6;
kontext.shadowOffsetY = 3;
kontext.shadowBlur = 10;

kontext.strokeRect(10, 10, 50, 50);

Výsledek:

Plátno
localhost

Barevné přechody

Obrázkům kromě stínu můžeme také doplnit lineární nebo kruhové barevné přechody. Oba se dají nastavit jak pro výplň, tak pro obrys.

Lineární přechod

Lineární přechod vytvoříme pomocí metody createLinearGradient() na objektu kontextu. Předáváme jí čtyři parametry. Jsou to souřadnice x a y pro počátek a pro konec gradientu.

Nově vzniklý objekt disponuje metodou addColorStop(), která přidá gradientu další barvu. Tato metoda přijímá jako první parametr pozici "zastavení" v rozmezí 01 a jako druhý danou barvu. Objekt s takto nastaveným barevným přechodem předáme jako vlastnost fillStyle nebo strokeStyle:

let gradient = kontext.createLinearGradient(0, 0, 100, 0);

gradient.addColorStop(0, "yellow");
gradient.addColorStop(0.2, "orange");
gradient.addColorStop(0.4, "pink");
gradient.addColorStop(0.6, "red");
gradient.addColorStop(0.8, "green");
gradient.addColorStop(1, "blue");

kontext.fillStyle = gradient;
kontext.fillRect(0, 0, 100, 100);

kontext.font = "19px Calibri"
kontext.fillText("ITnetwork.cz", 0, 115);

Výsledek:

Plátno
localhost

Radiální přechod

Radiální neboli kruhový přechod se používá úplně stejně, jen vytvoří jiný efekt. Vytvoříme jej metodou createRadialGradient(), která přijímá šest parametrů. Souřadnice x a y pro počáteční bod, poloměr a to vše ještě jednou i pro koncový bod.

V hodnotách je poměrně zmatek. První pozice x a y je vlastně střed, první poloměr je poloměr, u kterého začne přechod. Pokud bude hodnota tohoto poloměru 0, přechod začne již od středu. Pokud uvedeme cokoli jiného, bude od středu první barva a až na zadaném poloměru začne přecházet v jinou.

Jestliže chceme docílit pravidelného kruhu, tak čtvrtý a pátý parametr bude kopírovat hodnoty prvního a druhého parametru. Šestý parametr poté udává, na jakém poloměru se přechod zastaví. Nastavování barev je stejné jako u lineárního gradientu:

let gradient = kontext.createRadialGradient(50, 50, 0, 50, 50, 75);

gradient.addColorStop(0, "yellow");
gradient.addColorStop(0.2, "orange");
gradient.addColorStop(0.4, "pink");
gradient.addColorStop(0.6, "red");
gradient.addColorStop(0.8, "green");
gradient.addColorStop(1, "blue");

kontext.fillStyle = gradient;
kontext.fillRect(0, 0, 100, 100);

kontext.font = "19px Calibri"
kontext.fillText("ITnetwork.cz", 0, 115);

Výsledek:

Plátno
localhost

Obrázková výplň

Další možnost, jak zpestřit naše obrázky, představuje obrázková výplň. Docílíme jí tak, že vytvoříme pattern (vzor) a ten nastavíme vlastnosti fillStyle. Vzor vytvoříme metodou createPattern(), které jako první parametr předáme obrázek. Ve druhém parametru nastavujeme způsob opakovaní. Máme na výběr ze čtyř hodnot:

  • repeat nebo prázdný řetězec "" – pro vyplnění po ose x a y,
  • repeat-x – pro horizontální výplň,
  • repeat-y – pro vertikální výplň,
  • no-repeat – výplň se nebude opakovat.

Obrázek načteme v těle HTML:

<img src="vzor.png" id="obrazek"/>

Počkáme, než se obrázek načte a metodou createPattern() vytvoříme vzor výplně. Nový vzor nastavíme vlastnosti fillStyle a vykreslíme vyplněný čtverec:

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

    let pattern = kontext.createPattern(obrazek, "repeat");
    kontext.fillStyle = pattern;
    kontext.fillRect(50, 50, 100, 100);
};

Výsledek:

Plátno
localhost

Tímto jsme si shrnuli základní možnosti práce s plátnem a jeho kontextem v JavaScriptu. Příklady si zkuste upravit a vyzkoušejte si, jak uvedené metody a vlastnosti s jinými parametry mění vzhled obrázků. Využijete je také u cvičení, která má tento kurz k dispozici.

V následujícím cvičení, Řešené úlohy k 23.-26. lekci JavaScriptu, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

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 885x (376.69 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Předchozí článek
Stylování obrázků a vložení textu na plátno v JavaScriptu
Všechny články v sekci
Základní konstrukce jazyka JavaScript
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 23.-26. lekci JavaScriptu
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Uživatelské hodnocení:
631 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