14. diel - Obrázky a kreslenie na canvas v JavaScripte
V minulej lekcii, Cykly v JavaScripte druhýkrát , sme sa naučili používať kľúčové slová break, continue, návestí a cyklus do-while.
Vítam vás u ďalšej lekcie o tvorbe webových aplikácií v JavaScripte. V minulej lekcii, Cykly v JavaScripte druhýkrát , sme si prehĺbili naše znalosti o dátových typoch a ukázali si ďalšie konštrukcie pre tvorbu podmienok. V tomto JavaScript tutoriálu sa pozrieme na zub obrázkom, čím začneme ďalšie väčšie kapitolu - práca s grafikou v JavaScriptu.
Na webe existujú dva typy obrázkov - statické a dynamické. Statické
obrázky už poznáte a moc sa s nimi nedá kúzliť. Sú to obyčajné obrázky
(tag <img>
), s ktorými môžete vykonávať len niekoľko
málo základných operácií. Poväčšine s nimi manipulujeme len ako s prvkom
domu. Dynamické obrázky už môžu byť v dokumente HTML znázornené 2
značkami - <svg>
a <canvas>
. Pričom
prvý menovaná síce nie je striktne statická, ale napospol v JavaScripte s
ňou toho veľa neurobíme (zatiaľ). Tag <canvas>
už je o
trochu zaujímavejšie a zároveň jediný, ktorého obsah nie je možné
definovať inak ako JavaScriptom. Prejdime si všetko postupne.
Statické obrázky
Ako som už spomenul v úvode, jedná sa o klasický obrázok, ktorý v HTML
definujeme tagom <img>
. Môžeme mu samozrejme obsluhovať
rôzne udalosti ako je kliknutie a to úplne rovnakým spôsobom ako napr. Pri
tlačidle. V JavaScriptu ho môžeme vytvoriť buď klasicky ako prvok DOM:
let obrazek = document.createElement("img");
Alebo môžeme vytvoriť nový objekt Image
, čo je skrátená
varianta tvorby prvku DOM:
let obrazek = new Image();
Načítaní obrázka
Veľkým problémom je načítanie obrázku (ostatne ako načítanie
čohokoľvek v JavaScriptu). Než s obrázkom začneme pracovať, musí sa
načítať. Ak máme obrázok v HTML a JavaScript spúšťame v obsluhe udalosti
onload
, nie je žiadny problém. Prehliadač zabezpečí, že
obsluha sa zavolá až po načítaní všetkého (i obrázka).
V prípade, že si obrázky vytvárame až v JavaScripte, musíme na
načítanie počkať. Poslúži nám k tomu udalosť onload
na
danom obrázku.
let obrazek = new Image(); obrazek.src = "cesta / k / obrazku.jpg"; obrazek.onload = function () { // Tu vieme, že je obrázok načítaný }
Príklad: Prepínač
Vytvoríme si prepínač. Iste poznáte prepínač ON-OFF. Obrázky si
stiahnite nižšie a ideálne pomenujte prepinac0.png
a
prepinac1.png
.
Vytvorme stránku, kde bude obrázok s id
#prepinac
a ako predvolené cestu mu dáme k obrázku prepinac0.png
.
<img src="prepinac0.png" id="prepinac" alt="Prepínač" />
Vytvoríme si skript, kde deklarujeme premennú prepinac a po načítaní
stránky do nej dosadíme náš element obrázka prepínača. Ďalej si
vytvoríme funkciu prepni()
a nastavíme ju ako obsluhu udalosti
pre kliknutia na obrázok.
let prepinac; function prepni() { } window.onload = function() { prepinac = document.getElementById("prepinac"); prepinac.onclick = prepni; }
Img.src vs. img.getAttribute ( "src")
Teraz už je to len o podmienke a zmene src
, ale ... Objekt
obrázku (u OOP zistíte, že sa volá HTMLImageElement
) má
vlastnosť src
. Ponúka sa teda možnosť zmeniť buď hodnotu HTML
atribút src
elementu <img>
alebo ju dosadiť
rovno do vlastnosti src
, ktorú element v JavaScripte má. Lenže
... Tieto dve možnosti sa v niektorých prehliadačoch správajú trochu
odlišne. Kým metóda getAttribute()
vráti presne tú hodnotu,
čo je v atribúte, vlastnosť src
vráti absolútnu cestu. Ak teda
budeme porovnávať, tak až na pár výnimiek budeme porovnávať s hodnotou v
atribútu. Na vyskúšanie si zdroj obrázku zmeníme cez vlastnosť
src
.
function prepni() { if (prepinac.getAttribute("src") == "prepinac0.png") { prepinac.src = "prepinac1.png"; } else { prepinac.src = "prepinac0.png"; } }
Stránku si otvoríte a vyskúšajte, prepínač by mal fungovať.
Všimnite si, že vôbec nemusíme ošetrovať, kedy sa obrázok načíta, pretože nás to nezaujíma. Užívateľ bude čakať tak či tak, ale my sme od toho odtienenie, pokiaľ s obrázkom ďalej nepracujeme.
Teraz sa presunieme k dynamickým obrázkom.
Dynamické obrázky
Dynamické obrázky sa kreslí na plátno, ktoré je reprezentované
elementom <canvas>
. Tento element
musí mať nastavené atribúty width
a
height
. Ak je neuvedieme alebo je nastavíme napr. V CSS,
niektoré prehliadače to nepochopia a plátno rozmažú. Na samotný element
<canvas>
však ešte kresliť nemôžeme, musíme si získať
jeho kontext. Možno si hovoríte na čo je to dobré, získavať ešte kontext?
Ono je totiž rozdiel, keď na plátno kreslíme 3D hru a 2D stromček. 3D sa v
súčasnosti ešte len presadzuje ako štandard WebGL a tým sa teraz zaoberať
nebudeme, nás bude zaujímať len kontext 2D.
Získanie kontextu plátna
Kontext plátna získame volaním metódy getContext()
a ako
parameter ju odovzdáme formou textového reťazca typ požadovaného kontextu.
V našom prípade je to "2d"
.
let platno = document.getElementById("platno"); let kontext = platno.getContext("2d");
Na tomto kontexte už môžeme volať rôzne metódy pre vykreslenie na plátno.
Obdĺžniky
Základným objektom je obdĺžnik. Máme preddefinované dve základné
metódy, ktorými môžeme obdĺžnik nakresliť. Sú nimi
fillRect()
a strokeRect()
. Obe majú rovnaké
argumenty a to x, y, výška a šírka. Funkcia fillRect()
obdĺžnik vyplní, strokeRect()
vykreslí len jeho obrys.
Html časť
<canvas width="320" height="200" id="platno"></canvas>
JS časť
let platno = document.getElementById("platno"); let kontext = platno.getContext("2d"); kontext.fillRect(50, 50, 100, 100); kontext.strokeRect(200, 50, 100, 100);
výsledok:
Čiary
Čiary sa na plátno kreslí pomocou tzv. Ciest. Tieto cesty musíme (resp.
Mali by sme) je začať a uzavrieť. Pre začatie cesty použijeme metódu
beginPath()
, pre uzatvorenie potom closePath()
.
Samotnú čiaru vykreslíme metódou lineTo(x, y)
. Čiara sa
nakreslí od poslednej nastavenej polohy kurzora (tá je na začiatku [0; 0]).
Túto pozíciu môžeme nastaviť metódou moveTo(x, y)
. Metóda
nevykreslí nič, len presunie kurzor plátna na danú pozíciu. Cestu
vykreslíme buď metódou fill()
, ktorá vyplní vnútro cesty
farbou (takto sa dajú kresliť vlastné tvary, preto je treba cesty
uzatvárať), alebo metódou stroke()
, ktorá vykreslí len obrys
danej cesty. Jednoduchý príklad nižšie vykreslí čiaru z bodu [20; 20] do
[40; 150].
kontext.beginPath(); kontext.moveTo(20, 20); kontext.lineTo(40, 150); kontext.closePath(); kontext.stroke();
výsledok:
Kruhy, kružnice a výseky
Ďalšie, čo môžeme na plátno kresliť, sú kruhy, kružnice a ich
výseče. To všetko vie metóda arc()
, ktorej syntax je
nasledujúca:
context.arc(x, y, polomer, pocatecniUhel, konecnyUhel, smer);
Argumenty x
a y
určujú opäť absolútnu
pozíciu, tu stredu. Argument polomer
udáva polomer kružnice,
pocatecniUhel
je uhol, od ktorého sa má kružnice resp. výseč
vykresliť. Je udaný v radiánoch. Z matematiky by sme si mali pamätať, že
plný uhol 2 * PI
a že stupňa sa prevedú na radiány ako
(PI / 180) * stupně
. Posledný argument je smer
. Ide
o logickú hodnotu (true
/ false
), ktorá udáva, či
sa bude kružnice vykresľovať v smere hodinových ručičiek alebo proti nemu.
Základni je nastavený na true
, teda v smere hodinových
ručičiek. Metódu musíme používať vnútri cesty.
Kruh teda nakreslíme takto:
kontext.beginPath(); kontext.arc(100, 100, 80, 0, Math.PI * 2); kontext.fill();
Odmenou za kód vyššie nám bude takýto kruh.
Výsledok v prehliadači:
Štýly
Aby naše kresby dobre vyzerali, naučíme sa používať štýly.
Rozlišujeme štýly pre vyplnenie (fill) a vykreslenie obrysu (stroke). Štýly
možno aplikovať na všetky objekty od obdĺžnikov po kruhy. Máme k
dispozícii dve základné vlastnosti, s ktorými ďalej pracujú metódy
stroke()
a fill()
. Jednak je to fillStyle
a potom tiež strokeStyle
. Hodnoty týchto vlastností sú zápisy
farieb. Môžeme použiť klasický hexadecimálne zápisnica z CSS, napr.
#ffffff
alebo rgb(255, 255, 255)
. Možno použiť aj
rgba(255, 255, 255, 0.5)
, kde posledná hodnota je tzv. Alfa kanál
(priehľadnosť), alebo hsl
a hsla
(rovnako ako v CSS
3). A poslednou možnosťou je uviesť názov, ak ho farba má (napr.
"green"
).
Ukážme si jednoduché štýlovanie objektov:
// Štýly musí byť vždy pred samotným vykreslením (zavolaním metódy `fill()`, `stroke()` alebo samovykreslovacích metód, ako sú `fillRect()`, `strokeRect()`...) kontext.fillStyle = "#a8c101"; kontext.fillRect(10, 10, 50, 50);
výsledok:
Externé obrázky
Na plátno samozrejme môžeme vykresľovať aj existujúce obrázky, napr.
Zo súborov. Musíme ich však mať načítané, inak sa nevykreslí.
Vykreslenie obrázku docielime jednoducho metódou drawImage()
,
ktoré ako prvý parameter odovzdáme obrázok a ako druhý a tretí parameter
pozície X a Y kam sa obrázok vykreslí. Existujú ešte metódy s parametrami
pre zväčšenie / zmenšenie a orezanie obrázkov.
obrázok:
výsledok:
Text
Okrem všakovakých tvarov môžeme na plátno vykresliť i text. To sa dá
využiť napríklad ako watermark na obrázkoch vo vašej galérii, menovkami ku
grafom alebo úplne inak, ako vám to len vaša fantázia dovolí. Základné
funkcie je fillText(text, x, y)
. Text tu zastupuje textový
reťazec, ktorý chceme vypísať. Argumenty x
a y
sú
absolútnou pozície. Jednoduchý text vykreslíme napríklad takto:
kontext.fillText("itnetwork.cz", 50, 50);
Text ale bude bez štýlov a celkom malý. Preto máme k dispozícii
vlastnosť context.font
, ktorú musíme ako trebárs
fillStyle
nastaviť ešte pred vykreslením textu. Hodnoty
premenné sú totožné so zápisom v CSS pri rovnomennej vlastnosti
font
. Nastavme veľkosť textu napr. Na 30 pixelov a použime font
sans-serif
.
kontext.font = "30px sans-serif"; kontext.fillText("ITnetwork.cz", 50, 50);
výsledok:
To by na úvod do canvasu stačilo. V budúcej lekcii, 2D kontext plátna v JavaScripte , sa pozrieme na plátno ešte podrobnejšie.
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é 1503x (14.87 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript