September discount week
Pouze tento týden sleva až 80 % na e-learning týkající se MS Office
50 % bodů zdarma na online výuku díky naší Slevové akci!

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
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

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

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í.


 

Stiahnuť

Stiahnuté 302x (232.19 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
Článok pre vás napísal Michal Žůrek - misaz
Avatar
Ako sa ti páči článok?
Ešte nikto nehodnotil, buď prvý!
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 (1)

 

 

Komentáre

Avatar
Patrik Pastor:30.3.2019 21:21

chtel bych se zeptat, kdyz neudelam tag <img> ale vytvorim ho v javascriptu a potom mu dam src hodnotu, jak to ze to nejde? Cestu mam spravne. Vykresli se pouze cerna barva, bez obrazku jako patternu, nevite v cem to je?

<script>
let platno;
let kontext;
let obrazek;
window.onload = function(){
platno = document.getE­lementById("plat­no");
kontext = platno.getCon­text("2d");

obrazek = new Image();
obrazek.src = "fotky/lamp1.png";

let pattern = kontext.create­Pattern(obrazek, "");

kontext.fillStyle = pattern;
kontext.fillRec­t(50, 50, 100, 100);

kontext.begin­Path();
kontext.arc(100, 225, 50, 0, Math.PI * 2);
kontext.close­Path();
kontext.fill();

}
</script>

 
Odpovedať
30.3.2019 21:21
Avatar
Lubor Pešek
Člen
Avatar
Lubor Pešek:15. marca 11:49

Tak tato sekce tutoriálu je pěkně odfláklá.
V podstatě je to úplně stejné, jako kdybyste vypsali možné metody třídy canvas a pod to připsali: použití si vygooglete.
U víc jak půlky příkladů jsem to musel udělat. Je to tu hůř popsané, než kdybych si o tom přečetl rovnou dokumentaci.
Snad poprvé tady na stránkách kritizuji bohužel celou sekci:(

Příklad:

Zvětšení/zmenšení
Kontext můžeme 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.

Ale to, že se musí metoda scale volat před vykreslováním obrázku, to jsem si musel vygooglit.

Odpovedať
15. marca 11:49
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Vojtech Palec:15. marca 17:54

To ano, ale to je dál za touhle sekcí. :-)

Editované 15. marca 17:57
 
Odpovedať
15. marca 17:54
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
Lubor Pešek
Člen
Avatar
Odpovedá na Vojtech Palec
Lubor Pešek:15. marca 17:56

A nebo (objektově) můžeš vytvořit instanci čtverce a pak s ní pracuješ, voláš její metody a modifikuješ ji.

Odpovedať
15. marca 17:56
Existují dva způsoby, jak vyřešit problém. Za prvé vyhoďte počítač z okna. Za druhé vyhoďte okna z počítače.
Avatar
Marek
Člen
Avatar
Marek:13. septembra 21:49

Ahoj, nesetkal se někdo během používání metody getImageData() s takovouto chybou ?

Uncaught DOMException: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': The canvas has been tainted by cross-origin data.

Google zatím nepomohl. Obrázek mám lokálně ve složce..

Díky,
Marek

 
Odpovedať
13. septembra 21:49
Avatar
Marek
Člen
Avatar
Odpovedá na Marek
Marek:15. septembra 22:11

Vyřešeno lokálním serverem přes node.js + browsersync. Myslím, že toto během návodu nebylo zmíněno, že je třeba lokální server.

Z nějakého důvodu chrome blokuje při využití některých funkcí canvasu lokální cestu k souboru.

 
Odpovedať
15. septembra 22:11
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zobrazené 6 správy z 6.