Lekce 17 - Časovače a animace v JavaScriptu
V předešlém cvičení, Řešené úlohy k 15. a 16. lekci JavaScriptu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
Vítám vás u další lekce našeho on-line kurzu JavaScriptu. V tomto JavaScript tutoriálu se podíváme jak můžeme různé věci časovat a na to navážeme efektem animace.
Časovače
Časovače můžeme v JavaScriptu obsluhovat pomocí dvou funkcí.
setInterval()
a setTimeout()
Funkce setInterval()
a setTimeout()
přijímají
dva parametry. Funkci, která se bude volat, a časový interval (jak často
nebo za jak dlouho se bude volat). Časové intervaly se udávají
v milisekundách (1 sekunda = 1000 milisekund). Rozdíl mezi těmito dvěma
funkcemi je vcelku zásadní. Zatímco setInterval()
bude metodu
volat každých X milisekund, setTimeout()
ji zavolá pouze jednou
jedinkrát a to za X milisekund.
Příklad
Cílem bude vytvořit text, který se bude postupně vypisovat. Nejprve bude
vidět písmeno "A"
, o sekundu později přiskočí
"h"
a budou pokračovat třeba písmena "o"
,
"j"
, "s"
, "v"
, "ě"
,
"t"
, "e"
. Jakmile budou vypsána všechna písmena,
text se vymaže a začne to celé znovu.
Nyní nebudeme mít již v HTML žádný element, vytvoříme jej až
v JavaScriptu (implementace je jen na nás, ale pro zopakování DOMu necháme
<body>
prázdné ).
Do proměnné text
uložíme text, který se bude vypisovat, a
vytvoříme element <p>
. Protože i <body>
ještě nemusí být načtené (pokud importujeme skript
v <head>
), element <p>
přidáme do
elementu <body>
až po načtení stránky.
let text = "Ahoj světe"; let element = document.createElement("p"); window.onload = function() { document.body.appendChild(element); }
Nyní přejdeme k samotné funkci, která bude měnit text v našem elementu.
function zmenText() { }
V této funkci si nejprve ověříme, zdali jsme již nevypsali všechna
písmena. Pokud bychom totiž získali další písmeno v pořadí (když jsme
na konci a žádné další písmeno neexistuje), dostali bychom chybu. Pokud se
zadání (proměnná text
) již shoduje s obsahem elementu,
změníme hodnotu elementu na prázdný textový řetězec, aby se mohl text
začít vypisovat znovu. Připravíme si i další větev, kam budeme psát
další kód.
if (element.textContent == text) { element.textContent = ""; } else { }
Dále si vezmeme písmeno (znak), které přidáme k textu elementu. Již
víme, že length
obsahuje délku řetězce. Vezmeme tedy další
znak v pořadí tak, že změříme délku řetězce, který je vypsaný na
obrazovku, a přičteme k ní 1. Jenže to má háček. Zatímco délka
řetězce se počítá od 1 (1 znak = délka 1
), tak znak na
určité pozici (index) se počítá od nuly (1. znak = index 0
).
Proto musíme ještě jedničku odečíst, nakonec se +1 a -1 vynuluje, takže
vezmeme znak na indexu aktuální délky textu vypsaného na obrazovce.
let pismenoKpridani = text[element.textContent.length];
A písmeno přidáme k textu zobrazeném v elementu.
element.textContent += pismenoKpridani;
Nyní již nezbývá než jen spustit interval. Do obsluhy události
onload
přidejme volání metody setInterval()
, které
jako první parametr předáme název metody zmenText
(bez
závorek) a jako druhý číslo 1000
, aby byl interval změny textu
přesně 1 sekundu.
setInterval(zmenText, 1000);
Interval se spustí až po jedné sekundě. Do té doby se bude aplikace
jevit jako že 1 sekundu nereaguje, proto předtím ještě spustíme jednou
metodu zmenText()
ručně:
zmenText(); setInterval(zmenText, 1000);
Aplikaci si ještě můžete vylepšit, protože u mezery se aplikace bude jevit jako že se zasekla.
Složitější animace
Jistojistě by bylo hezké mít na webu nějakou složitější animaci. Ty jednoduché lze vyřešit v CSS, ale ty složitější již musíme řešit JavaScriptem. Celá pointa animací je, že v nějakém intervalu ovlivňujeme vlastnosti animovaného objektu.
Vezmeme si například podzimní výzdobu webu. Naprogramujeme skript, který
nechá padat listí odshora dolů. Obrázky listí budeme mít v kořenovém
elementu <body>
a každý obrázek bude mít data-atribut
data-podzim
. Cíleně budeme vybírat pouze tyto obrázky, protože
ne webu mohou (a bývají) i jiné obrázky a ty nechceme ovlivňovat.
Stáhněte si obrázek listu níže a vložte jej do nového projektu s následujícím HTML obsahem:

<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 přidejme CSS styl, ve kterém nastavíme obrázkům
absolutní pozici (opět budeme nastavovat jen našim podzimním) a
<body>
nastylujme tak, aby nezobrazovalo scrollbary.
body > img[data-podzim] { position:absolute; } body { overflow:hidden; }
Nadefinujme si proměnou listy
, kam si po načtení stránky
uložíme obrázky listů s data atributem data-podzim
.
let listy; window.onload = function () { listy = document.querySelectorAll("body > img[data-podzim]"); }
Listy projdeme cyklem:
for (let i = 0; i < listy.length; i++)
Budeme jim chtít nastavit výchozí pozici, která bude zleva pětina šířky okna pro každý (viz dále, tak aby se přesně rozprostřely) a shora mínus jejich výška (tak aby při načtení stránky začali sjíždět z horní hrany).
Velikost okna
Občas (jako např. teď) je potřebujeme pracovat s velikostí okna. Existuje několik způsobů a vlastností, které s touto velikostí souvisejí.
Skutečná velikost obrazovky
Úplně tu nejskutečnější velikost obrazovky vám řeknou vlastnosti
width
a height
na objektu screen.
Oblast obrazovky vyhrazena aplikacím
Jedná se o velikost, kterou mohou použít aplikace. Jinými slovy
v podstatě o velikost obrazovky výše mínus velikost systémových panelů
(např. taskbaru). Vlastnosti najdeme opět na objektu screen
jako
availWidth
a availHeight
.
Velikost okna webové stránky
Nakonec si necháme tu nejdůležitější. Velikost plochy, kterou může
zabírat naše aplikace. Vlastnosti najdeme tentokrát na objektu
window
a to jako innerWidth
a
innerHeight
.
Nastavování CSS vlastností
Zatím nám ještě chybí jedna podstatná informace a to jak se nastavují vlastnosti CSS elementům DOMu.
Všechny elementy DOMu mají vlastnost style
, která obsahuje
vlastnosti pojmenované jako CSS vlastnosti. Ty se nezapisují pomlčkovou
notací, ale notací camelCase (první slovo celé malými písmeny, každé
další má počáteční písmeno velké, nejsou zde žádné mezery). Takže
například:
document.body.style.backgroundColor = "red";
nastaví barvu pozadí elementu <body>
na červenou.
Vraťme se k našemu padajícímu listí. Nastavme tedy pozice. U nastavování hodnot CSS je častá chyba zapomenutí jednotky:
listy[i].style.left = i * window.innerWidth / listy.length + "px"; listy[i].style.top = -listy[i].height + "px";
Posun
Nyní se vrhneme na funkci posun()
, která posune všechny listy
dolů. Funkce cyklem projde všechny listy a nastaví jim novou pozici. Tu
získá na základě současné pozice listu (kterou musíme kvůli odstranění
CSS jednotky z hodnoty naparsovat) a následného přičtení nějaké rozumné
hodnoty, aby animace nebyla ani moc rychlá ani moc pomalá. Hodnotu si můžete
zkusit upravit (hodnota 2
v kódu).
function posun() { for (let i = 0; i < listy.length; i++) { let novaPozice = parseInt(listy[i].style.top) + 2; listy[i].style.top = novaPozice + "px"; } }
Ještě je třeba ošetřit případ, kdy list vyjede z okna. V takovém případě musíme pozici znovu nastavit na mínus výšku obrázku. Dodejme podmínku mezi předchozí 2 řádky, abychom nemuseli CSS hodnotu nastavovat 2×.
if (novaPozice > window.innerHeight) { novaPozice = -listy[i].height; }
Nakonec tedy v obsluze události načtení okna nastavme interval na nějakou rozumnou hodnotu (opět vyzkoušejte).
setInterval(posun, 20);
Protože postup byl komplexnější, uveďme si pro kontrolu kompletní zdrojový kód skriptu:
// Načtení stránky window.onload = function () { listy = document.querySelectorAll("body > img[data-podzim]"); // nastavení počáteční pozice 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); } // Funkce pro č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"; } }
Aplikaci spusťte. Uvidíte, že listí bude padat shora dolů a po vytečení z obrazovky zase odznovu.
Gratuluji, vaše první javascriptová animace je na světě. Můžete si ji samozřejmě vylepšit, aby byla ještě zajímavější.
Animace na plátně
V podobném duchu se nesou animace na plátně, kde v určitém intervalu
celé plátno vymažeme a znovu vykreslíme a tak stále dokola. Jako ukázku si
můžeme naprogramovat kolo štěstí. Pro jednoduchost si jej načteme ze
statického obrázku. Vytvořme si tedy stránku s plátnem a to si načtěme
v JavaScriptu. Do stránky si přidejme i obrázek
s id="kolo"
.
Stáhněte si obrázek níže a spolu s následujícím HTML kódem jej vložte do nového projektu:

<img src="kolo.png" id="kolo" /> <canvas id="platno" width="500" height="500"></canvas>
V skriptu si tyto objekty načtěme a přidejme si rovnou i proměnnou, kde budeme mít uložený úhel otočení. Obrázek nezapomeneme ze stránky skrýt.
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 metodě prekresli()
poté jednoduše vymažeme plátno a
znovu na něj kolo vykreslíme. Nejprve vhodně přesuneme a otočíme kontext a
poté obrázek vykreslíme. Nakonec přidáme k otočení jeden stupeň a to
rovnou v jednotkách radiánů, ať se vyhneme přepočítávání. Víme ž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čení o 1 stupeň, ale v radiánech }
V události načtení stránky opět nastavíme interval a vykreslíme kolo hned na začátku, abychom nemuseli čekat na dovršení prvního intervalu.
setInterval(prekresli, 20); prekresli();
Výsledek:
Gratuluji, již byste měli zvládat práci s animacemi. Dokázat si to můžete na cvičení.
Správně řešené animace
Všechna naše řešení animací sice fungují, ale podívejme se na ně
z hlediska výkonu. Když uživatel opustí naší záložku prohlížeče,
animace stále běží a vytěžuje procesor. Horší je to na mobilních
zařízeních, kde to jde i poznat. Jak se animace dají řešit, aby za nás
webový prohlížeč vyřešil animaci skutečně jen když je potřeba, si
řekneme jindy
V následujícím cvičení, Řešené úlohy k 17. lekci JavaScriptu, si procvičíme nabyté zkušenosti z předchozích lekcí.
Měla 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 629x (218.69 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript
Komentáře


Zobrazeno 10 zpráv z 11. Zobrazit vše