Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
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í.

15. diel - 2D kontext plátna v JavaScripte

V minulej lekcii, Obrázky a kreslenie na canvas v JavaScripte , sme sa venovali obrázkom a naučili sa pracovať s canvas. V dnešnom JavaScript tutoriálu sa na plátno pozrieme podrobnejšie. Prejdeme si postupne všetky jeho možnosti.

Mazanie obdĺžnikov

V minulom diele sme zľahka načali kreslenie obdĺžnikov. Uviedli sme si metódy fillRect() a strokeRect(). K obdélníkům sa ešte viaže metóda clearRect(), ktorá vymaže obsah plátna na danej ploche. Parametre má rovnaké ako dve vyššie spomínané metódy. Aký je však rozdiel medzi clearRect() a fillRect(), keď nastavíme výplň na bielu? Plátno totiž v predvolenom stave nie je biele, ale je priehľadné. Ak teda vymažeme plátno pomocou fillRect(), síce uvidíme bielu plochu, ale neuvidíme pozadia plátna a to čo bolo pod plátnom.

Obdĺžnik v ceste

Poslednou možnosťou ako vykresliť obdĺžnik ich vložiť ho do cesty. Hoci by sa to na prvý pohľad mohlo zdať zbytočné, keď máme metódy fillRect() a strokeRect(), tak je to veľmi výhodné, keď chceme vyfarbiť obdĺžnik a dať mu zároveň rámček. Jednoducho obdĺžnik vykreslíme ako cestu, vykreslíme obsah a rámček.

kontext.beginPath();
kontext.rect(10, 10, 60, 60);
kontext.closePath();
kontext.fillStyle = "red";
kontext.strokeStyle = "blue";
kontext.stroke();
kontext.fill();

výsledok:

Plátno
localhost

Transformácie kontextu

Veľmi dôležité sú pri spracovávaní obrázku transformácie. Čas od času sa bude hodiť, keď pozície nula nebude nulou. Asi ten najjednoduchší prípad je, keď okolo canvasu budeme mať nejaký veľa špecifický 10px široký rámik, ktorý by sme len v CSS nenastylovali. Samozrejme všade môžeme vypisovať, aby sa vykresľovali na x + 10, y + 10, ale jednoduchí pre nás bude využiť posunu kontextu. U rotáciou to bude o to zaujímavejšie a mnohokrát jediná cesta ako docieliť daného výsledku.

Uloženie kontextu

Pred akoukoľvek manipuláciou s kontextom je dobré si ho uložiť. My ho síce potom môžeme vrátiť do pozície x -10 ay -10, ale je to zbytočne pracné a navyše si musíme pamätať tieto hodnoty. Preto má kontext metódy save() a restore(), ani jedna nepožaduje žiaden parameter. Metóda save() si uloží aktuálne transformácie a metóda restore() je obnoví.

Ako príklad si vykreslíme obrázok s červeným rámčekom, hoci je toto najjednoduchšie riešiť s pomocou CSS, skúsime to v JavaScripte.

Najprv si načítame plátno, kontext a obrázok, to už zvládnete sami. Kontexte nastavíme farbu výplne napr. Na červenú a prekreslíme jej celý <canvas>. Potom kontext uložíme.

kontext.fillStyle = "#f00";
kontext.fillRect(0, 0, 510, 340);

kontext.save();

Posun kontextu

Posun kontexte vykonávame metódou translate(), ktorá prijíma parametre x a y pre súradnice posunu. Nový nulový bod bude na týchto súradniciach. My si plátno posunieme o kladných 10px ako po osi x, tak po osi y.

kontext.translate(10, 10);

Teraz na pozíciu [0; 0] vykreslíme obrázok a kontext plátna obnovíme.

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

Keď si teraz aplikáciu otvoríme, všimneme si, že hoci sme zadali, nech sa obrázok nakreslí na [0; 0], tak sa vykreslil na [10; 10]. Môže za to práve náš posun.

Plátno
localhost

Nezabudnite vrátiť kontext, keby ste s ním ešte niekedy potrebovali pracovať.

Zväčšenie / zmenšenie

Kontext môžeme zmenšovať a zväčšovať. Slúži na to metóda scale(), ktorá ako parametre prijíma násobky skutočné hodnoty pre súradnice X a Y. Pre zmenšovanie sa zadávajú desatinné čísla menšie ako 1.

Plátno
localhost

Rotácie

Posledný operácií je rotácia. Často potrebujeme niečo otočiť. Napr. keď potrebujeme urobiť kosoštvorec alebo kosodĺžnik, nie je nič jednoduchšie ako otočiť kontext. Samozrejme by sme mohli body prepočítavať, ale bolo by to zbytočne komplikované. Kontext otáčame metódou rotate(), ktorá ako parameter prijíma uhol v radiánoch.

kontext.save();
kontext.translate(100, 100);
kontext.rotate(45 * Math.PI / 180);
kontext.strokeRect(0, 0, 50, 50);
kontext.restore();

výsledok:

Plátno
localhost

Tieň

Všetky operácie, ktoré niečo na canvas nakreslí, môžeme vykonávať s tieňom. Vlastnosťou shadowColor nastavíme farbu tieňa. Vlastnosťami shadowOffsetX a shadowOffsetY nastavíme posun tieňa a pomocou shadowBlur ako veľmi bude rozostrený.

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

výsledok:

Plátno
localhost

Farebné prechody

Občas sa hodí obrázok "vylepšiť" farebnými prechodmi. Existujú 2 typy prechodov - lineárne a kruhové (radiálne). Obaja sa dajú nastaviť ako pre výplň, tak pre obrys.

Lineárny prechod

Lineárny prechod je jednoduchý, farby sa postupne mení ako povieme a to za sebou. Vytvára sa metódou createLinearGradient() na objekte kontextu a odovzdávame jej 4 parametrami. Sú to súradnice x a y pre začiatok a pre koniec gradientu. Novovzniknutý objekt disponuje metódou addStopColor(), ktorá pridá gradientu ďalšiu farbu. Táto metóda prijíma ako prvý parameter pozíciu "zastavenie" v rozmedzí 0 - 1 a ako druhý danú farbu.

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ýsledok:

Plátno
localhost

Radiálne prechod

Radiálne čiže kruhový prechod sa používa úplne rovnako, len vytvorí iný efekt. Metóda, ktorá ho vytvorí, sa nazýva createRadialGradient() a prijíma 6 parametrov. x a y pre počiatočný bod, polomer a to všetko ešte raz aj pre koncový bod.

V hodnotách je pomerne zmätok. Prvá pozícia x a y je vlastne stred, prvý polomer je polomer, u ktorého začne prechod. Pokiaľ bude nula, prechod začne už od stredu. Ak čokoľvek iné, bude od stredu prvej farba a až na zadanom polomere začne prechádzať. Pokiaľ chcete docieliť pravidelného kruhu, tak 4. a 5. parameter bude kopírovať prvý a druhý. Šiesty parameter potom udáva na akom polomere sa prechod zastaví, ďalej už bude len posledná farba. Nastavovanie farieb je rovnaké.

Plátno
localhost

Obrázková výplň

Jedna z ďalších možností výplne (dostupná aj pre obrys) je obrázková výplň. Docielime jej tak, že vytvoríme pattern (vzor) a ten nastavíme výplni (alebo obrysu). Pattern vytvoríme metódou createPattern(), kde ako prvý parameter odovzdáme obrázok a ako druhý spôsob opakovaní. Pre opakovanie po osi X aj Y môžeme ponechať prázdny String.

let vzor = kontext.createPattern(obrazek, "");
kontext.fillStyle = vzor;

výsledok:

Plátno
localhost

Ako vzor môžeme použiť aj iný element <canvas>.

Práca s pixely

Až doteraz za nás nejaké pixely riešil JavaScript, ale občas sa hodí, aby sme aj my mohli pracovať s jednotlivými pixely.

Obrázková dáta

2D kontext plátna poskytuje objekt ImageData. Získame ho metódou getImageData(), ktoré ako parametre odovzdáme súradnice ľavého horného rohu a veľkosť výrezu. Tento objekt bude mať pole data, v ktorom sú všetky RGBA hodnoty pixelov v tomto výbere. Pixely sú radené postupne, riadok po riadku, zľava doprava.

Práca s pixely na canvasu v JavaScripte - Základné konštrukcie jazyka JavaScript

Vytvorme si aplikáciu, ktorá invertuje farby obrázka. Načítame si zas plátno, kontext a obrázok. Na plátno vykreslíme obrázok az obrázku si získame obrázková dáta.

kontext.drawImage(img, 0, 0);
let dataObrazku = kontext.getImageData(0, 0, platno.width, platno.height);

Teraz cyklom prejdeme všetky farby, každý pixel je v poli zastúpený 4 ×, respektíve každá jeho zložka (R, G, B, A) tam má hodnotu. Cyklus teda nebude mať klasickú inkrementácia, ale iteračné premennú zvýšime o 4.

for (let i = 0; i < dataObrazku.data.length; i += 4) {
}

V cykle potom hodnotám i (R), i + 1 (G), i + 2 (B) nastavíme novú farbu. V našom prípade odčítame hodnotu farby od 255, čo je maximálna hodnota. Tým hodnoty otočíme a docielime efektu negatívu. Alfa kanál nebudeme meniť.

dataObrazku.data[i + 0] = 255 - dataObrazku.data[i + 0];
dataObrazku.data[i + 1] = 255 - dataObrazku.data[i + 1];
dataObrazku.data[i + 2] = 255 - dataObrazku.data[i + 2];

Nakoniec vložíme upravená ImageData do obrázka metódou putImageData() na pozíciu [0; 0].

kontext.putImageData(dataObrazku, 0, 0);

výsledok:

Plátno
localhost

Teraz by ste už mali byť schopní ovládať <canvas> v JavaScripte. Odporúčam vyskúšať si cvičenie. V budúcej lekcii, Riešené úlohy k 14. a 15. lekcii JavaScriptu , sa pozrieme na časovača a animácie.

V nasledujúcom cvičení, Riešené úlohy k 14. a 15. lekcii JavaScriptu, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 873x (376.69 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript

 

Predchádzajúci článok
Obrázky a kreslenie na canvas v JavaScripte
Všetky články v sekcii
Základné konštrukcie jazyka JavaScript
Preskočiť článok
(neodporúčame)
Riešené úlohy k 14. a 15. lekcii JavaScriptu
Článok pre vás napísal Michal Žůrek - misaz
Avatar
Užívateľské hodnotenie:
2 hlasov
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