16. diel - Časovača a animácie v JavaScripte
V predchádzajúcom cvičení, Riešené úlohy k 14. a 15. lekcii JavaScriptu, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.
Vítam vás u ďalšej lekcie nášho on-line kurzu JavaScriptu. V minulej lekcii, Riešené úlohy k 14. a 15. lekcii JavaScriptu , sme sa venovali 2D kontextu plátna. V tomto JavaScript tutoriálu sa pozrieme ako môžeme rôzne veci časovať a na to nadviažeme efektom animácie.
Časovača
Časovača môžeme v JavaScripte obsluhovať pomocou dvoch funkcií.
SetInterval () a setTimeout ()
Funkcia setInterval()
a setTimeout()
prijímajú
dva parametre. Funkciu, ktorá sa bude volať, a časový interval (ako často
alebo za ako dlho sa bude volať). Časové intervaly sa udávajú v
milisekundách (1 sekunda = 1000 milisekúnd). Rozdiel medzi týmito dvoma
funkciami je vcelku zásadný. Kým setInterval()
bude metódu
volať každých X milisekúnd, setTimeout()
ju zavolá iba raz
jediný raz a to za X milisekúnd.
Príklad
Cieľom bude vytvoriť text, ktorý sa bude postupne vypisovať. Najprv bude
vidieť písmeno "A"
, o sekundu neskôr priskočí "h"
a budú pokračovať napríklad písmená "o"
, "j"
,
"s"
, "v"
, "ě"
, "t"
,
"e"
. Akonáhle budú vypísaná všetky písmená, text sa vymaže
a začne to celé znova.
Teraz nebudeme mať už v HTML žiadny element, vytvoríme ho až v
JavaScripte (implementácia je len na nás, ale pre zopakovanie domov necháme
<body>
prázdne ).
Do premennej text
uložíme text, ktorý sa bude vypisovať, a
vytvoríme element <p>
. Pretože aj <body>
ešte nemusí byť načítané (pokiaľ importujeme skript v
<head>
), element <p>
pridáme do elementu
<body>
až po načítaní stránky.
let text = "Ahoj svete"; let element = document.createElement("p"); window.onload = function() { document.body.appendChild(element); }
Teraz prejdeme k samotnej funkcii, ktorá bude meniť text v našom elementu.
function zmenText() { }
V tejto funkcii si najskôr overíme, či sme už nevyzvali na predloženie
všetky písmená. Ak by sme totiž získali ďalšie písmeno v poradí (keď
sme na konci a žiadne ďalšie písmeno neexistuje), dostali by sme chybu. Ak
sa zadanie (premenná text
) už zhoduje s obsahom elementu,
zmeníme hodnotu elementu na prázdny textový reťazec, aby sa mohol text
začať vypisovať znova. Pripravíme si aj ďalšie vetva, kam budeme písať
ďalšie kód.
if (element.textContent == text) { element.textContent = ""; } else { }
Ďalej si zoberieme písmeno (znak), ktoré pridáme k textu elementu. Už
vieme, že length
obsahuje dĺžku reťazca. Vezmeme teda ďalší
znak v poradí tak, že zmeriame dĺžku reťazca, ktorý je vypísaný na
obrazovku, a pripočítame k nej 1. Lenže to má háčik. Kým dĺžka reťazca
sa počíta od 1 (1 znak = dĺžka 1
), tak znak na určitej
pozícii (index) sa počíta od nuly (1. znak = index 0
). Preto
musíme ešte jedničku odpočítať, nakoniec sa +1 a -1 vynuluje, takže
vezmeme znak na indexe aktuálnu dĺžku textu vypísaného na obrazovke.
let pismenoKpridani = text[element.textContent.length];
A písmeno pridáme k textu zobrazenom v elementu.
element.textContent += pismenoKpridani;
Teraz už nezostáva než len spustiť interval. Do obsluhy udalosti
onload
pridajme volanie metódy setInterval()
, ktoré
ako prvý parameter odovzdáme názov metódy zmenText
(bez
zátvoriek) a ako druhý číslo 1000
, aby bol interval zmeny textu
presne 1 sekundu.
setInterval(zmenText, 1000);
Interval sa spustí až po jednej sekunde. Dovtedy sa bude aplikácia javiť
ako že 1 sekundu nereaguje, preto predtým ešte spustíme raz metódu
zmenText()
ručne:
zmenText(); setInterval(zmenText, 1000);
Aplikáciu si ešte môžete vylepšiť, pretože u medzery sa aplikácia bude javiť ako že sa zasekla.
Zložitejšie animácie
Istoiste by bolo pekné mať na webe nejakú zložitejšie animáciu. Tie jednoduché dá vyriešiť v CSS, ale tie zložitejšie už musíme riešiť JavaScriptom. Celá pointa animácií je, že v nejakom intervale ovplyvňujeme vlastnosti animovaného objektu.
Vezmeme si napríklad jesenné výzdobu webu. Naprogramujeme skript, ktorý
nechá padať lístie odhora nadol. Obrázky lístia budeme mať v koreňovom
elemente <body>
a každý obrázok bude mať dáta-atribút
data-podzim
. Cielene budeme vyberať len tieto obrázky, pretože
nie webu môžu (a bývajú) aj iné obrázky a tie nechceme ovplyvňovať.
Stiahnite si obrázok listu nižšie a vložte ho do nového projektu s nasledujúcim HTML obsahom:
<img src="list.jpg" data-podzim /> <img src="list.jpg" data-podzim /> <img src="list.jpg" data-podzim /> <img src="list.jpg" data-podzim /> <img src="list.jpg" data-podzim />
Do projektu si pridajme CSS štýl, v ktorom nastavíme obrázkom absolútnu
pozíciu (opäť budeme nastavovať len našim jesenným) a
<body>
nastylujte tak, aby nezobrazovalo scrollbar.
body > img[data-podzim] { position:absolute; } body { overflow:hidden; }
Nadefinujte si premenou listy
, kam si po načítaní stránky
uložíme obrázky listov s data atribútom data-podzim
.
let listy; window.onload = function () { listy = document.querySelectorAll("body > img[data-podzim]"); }
Listy prejdeme cyklom:
for (let i = 0; i < listy.length; i++)
Budeme im chcieť nastaviť východiskovú pozíciu, ktorá bude zľava pätina šírky okna pre každý (pozri ďalej, tak aby sa presne rozprestreli) a zhora mínus ich výška (tak aby pri načítaní stránky začali schádzať z hornej hrany).
Veľkosť okna
Občas (ako napr. Teraz) je potrebujeme pracovať s veľkosťou okna. Existuje niekoľko spôsobov a vlastností, ktoré s touto veľkosťou súvisia.
Skutočná veľkosť obrazovky
Úplne tú najskutočnejší veľkosť obrazovky vám povedia vlastnosti
width
a height
na objekte screen.
Oblasť obrazovky vyhradené aplikáciám
Jedná sa o veľkosť, ktorú môžu použiť aplikácie. Inými slovami v
podstate o veľkosť obrazovky vyššie mínus veľkosť systémových panelov
(napr. Taskbaru). Vlastnosti nájdeme opäť na objekte screen
ako
availWidth
a availHeight
.
Veľkosť okna webovej stránky
Nakoniec si necháme tú najdôležitejšiu. Veľkosť plochy, ktorú môže
zaberať naše aplikácie. Vlastnosti nájdeme tentoraz na objekte
window
a to ako innerWidth
a
innerHeight
.
Nastavovanie CSS vlastností
Zatiaľ nám ešte chýba jedna podstatná informácia a to ako sa nastavujú vlastnosti CSS elementom domov.
Všetky elementy domov majú vlastnosť style
, ktorá obsahuje
vlastnosti pomenované ako CSS vlastnosti. Tie sa nezapisujú pomlčkovou
notáciou, ale notáciou CamelCase (prvé slovo celé malými písmenami,
každé ďalšie má začiatočné písmeno veľké, nie sú tu žiadne
medzery). Takže napríklad:
document.body.style.backgroundColor = "red";
nastaví farbu pozadia elementu <body>
na červenú.
Vráťme sa k nášmu padajúcim lístia. Nastavme teda pozície. U nastavovaní hodnôt CSS je častá chyba zabudnutia jednotky:
listy[i].style.left = i * window.innerWidth / listy.length + "px"; listy[i].style.top = -listy[i].height + "px";
Posun
Teraz sa vrhneme na funkciu posun()
, ktorá posunie všetky
listy nadol. Funkcia cyklom prejde všetky listy a nastaví im novú pozíciu.
Tú získa na základe súčasnej pozície listu (ktorú musíme kvôli
odstráneniu CSS jednotky z hodnoty naparsovat) a následného pripočítaní
nejaké rozumné hodnoty, aby animácie nebola ani moc rýchla ani veľmi
pomalá. Hodnotu si môžete skúsiť upraviť (hodnota 2
v
kóde).
function posun() { for (let i = 0; i < listy.length; i++) { let novaPozice = parseInt(listy[i].style.top) + 2; listy[i].style.top = novaPozice + "px"; } }
Ešte je potrebné ošetriť prípad, keď list vyjde z okna. V takom prípade musíme pozíciu znovu nastaviť na mínus výšku obrázku. Dodajme podmienku medzi predchádzajúce 2 riadky, aby sme nemuseli CSS hodnotu nastavovať 2 ×.
if (novaPozice > window.innerHeight) { novaPozice = -listy[i].height; }
Nakoniec teda v obsluhe udalosti načítanie okná nastavme interval na nejakú rozumnú hodnotu (opäť vyskúšajte).
setInterval(posun, 20);
Pretože postup bol komplexnejší, uveďme si pre kontrolu kompletný zdrojový kód skriptu:
// Načítanie stránky window.onload = function () { listy = document.querySelectorAll("body > img[data-podzim]"); // nastavenia počiatočnej pozície for (let i = 0; i < listy.length; i++) { listy[i].style.left = i * window.innerWidth / listy.length + "px"; listy[i].style.top = -listy[i].height + "px"; } setInterval(posun, 20); } // Funkcie pre časovač function posun() { for (let i = 0; i < listy.length; i++) { let novaPozice = parseInt(listy[i].style.top) + 2; if (novaPozice > window.innerHeight) { novaPozice = -listy[i].height; } listy[i].style.top = novaPozice + "px"; } }
Aplikáciu spustite. Uvidíte, že lístie bude padať zhora nadol a po vytečeniu z obrazovky zase odznovu.
Gratulujem, vaše prvé JavaScriptová animácie je na svete. Môžete si ju samozrejme vylepšiť, aby bola ešte zaujímavejšie.
Animácie na plátne
V podobnom duchu sa nesú animácie na plátne, kde v určitom intervale
celej plátno vymastíme a znovu vykreslíme a tak stále dokola. Ako ukážku
si môžeme naprogramovať koleso šťastia. Pre jednoduchosť si ho načítame
zo statického obrázku. Vytvorme si teda stránku s plátnom a to si načíta v
JavaScripte. Do stránky si pridajme aj obrázok s id="kolo"
.
Stiahnite si obrázok nižšie a spolu s nasledujúcim HTML kódom ho vložte do nového projektu:
<img src="kolo.png" id="kolo" /> <canvas id="platno" width="500" height="500"></canvas>
V skripte si tieto objekty načíta a pridajme si rovno aj premennú, kde budeme mať uložený uhol otočenia. Obrázok nezabudneme zo stránky skryť.
let platno; let kontext; let otoceni = 0; let obrazek; window.onload = function () { platno = document.getElementById("platno"); kontext = platno.getContext("2d"); obrazek = document.getElementById("kolo"); obrazek.style.display = "none"; }
V metóde prekresli()
potom jednoducho vymastíme plátno a
znovu naň koleso vykreslíme. Najprv vhodne presunieme a otočíme kontext a
potom obrázok vykreslíme. Nakoniec pridáme k otočeniu jeden stupeň a to
rovno v jednotkách radiánov, nech sa vyhneme prepočítavanie. Vieme že 360
° = 2 * Pí, takže jeden stupeň je (2 * Pí) / 360.
function prekresli() { kontext.clearRect(0,0,500,500); kontext.save(); kontext.translate(250, 250); kontext.rotate(otoceni); kontext.drawImage(obrazek, -225, -225); kontext.restore(); otoceni += (2 * Math.PI) / 360; // otočenie o 1 stupeň, ale v radiánoch }
V udalosti načítanie stránky opäť nastavíme interval a vykreslíme koleso hneď na začiatku, aby sme nemuseli čakať na dovŕšenie prvého intervalu.
setInterval(prekresli, 20); prekresli();
výsledok:
Gratulujem, už by ste mali zvládať prácu s animáciami. Dokázať si to môžete na cvičenie.
Správne riešené animácie
Všetky naše riešenia animácií síce fungujú, ale pozrime sa na ne z hľadiska výkonu. Keď používateľ opustí našej záložku prehliadača, animácie stále beží a vyťažuje procesor. Horšie je to na mobilných zariadeniach, kde to ide aj poznať. Ako sa animácia dajú riešiť, aby za nás webový prehliadač vyriešil animáciu skutočne len keď je potreba, si povieme v budúcej lekcii, Riešené úlohy k 16. lekcii JavaScriptu .
V nasledujúcom cvičení, Riešené úlohy k 16. 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é 1354x (218.35 kB)
Aplikácia je vrátane zdrojových kódov v jazyku JavaScript