14. díl - Časovače a animace v JavaScriptu

JavaScript Základní konstrukce Časovače a animace v JavaScriptu

Vítám vás u dalšího dílu našeho seriálu. Minule jsme se věnovali 2D kontextu plátna. V tomto díle se podíváme jak můžeme různé věci časovat a na to navážeme efektem animace. Když budeme používat obrázky, stáhněte si je z přiloženého souboru.

Časovače

Časovače můžeme v JavaScriptu obsluhovat pomocí dvou metod.

setInterval() a setTimeout()

Metody setInterval() a setTimeout() přijímají dva parametry. Funkci, která se bude volat a čas (jak často nebo za jak dlouho se bude funkce volat). Časy se udávají v milisekundách (1 sekunda = 1000 milisekund). Rozdíl mezi těmito dvěma metodami je vcelku zásadní. Zatímco setInterval() bude metodu volat každých X milisekud, 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 v JavaScriptu (je jen na nás, jak to implementujeme, 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. Protože i body ještě nemusí být načtené (pokud importujeme script v hlavičce), element přidáme do elementu body až po načtení stránky.

var text = "Ahoj světe";
var 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ž neopsali všechna písmena. Pokud bychom totiž získali další písmeno v pořadí (když jsme na konci, již žádné další písmeno neexistuje), dostali bychom chybu. Jestli se zadání (proměnná text) neshodují s proměnnou uvnitř elementu, změníme hodnotu elementu na prázdný textový řetězec. Tím však musíme průběh funkce ukončit.

if (element.textContent == text) {
        element.textContent = "";
        return;
}

Dále si vezmeme písmeno (znak), které přidáme k textu elementu. Již víme, že length vrátí 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 tomu +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 -1 vynuluje, takže vezmeme znak na indexu aktuální délky textu vypsaného na obrazovce.

var 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 ještě spustíme jednou metodu ZmenText() ručně:

ZmenText();

Aplikaci si ještě můžete vylepšit, protože u mezery se aplikace bude jevit jako že se zasekla.

Postupný výpis textu v JavaScriptu

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 script, 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.

<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 styl, ve kterém nastavíme obrázkům absolutní pozici (opět budeme nastavovat jen našim podzimním) a body nastavme tak, aby nezobrazovalo scrollbar.

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.

var listy;
window.onload = function () {
        listy = document.querySelectorAll("body > img[data-podzim]");
}

Cyklem listy projdeme.

for (var i = 0; i < listy.length; i++)

a nastavíme jim 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 jejich výška (tak aby při načtení stránky začali sjíždět z horní hrany).

Velikost okna

Občas (jako třeba teď) je potřeba pracovat s velikostí okna. Existuje několik způsobů a několik vlastností, které vracejí velikost, ale ne všechny velikost okna.

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ě rozlišení mínus velikost systémových panelů. Vlastnosti najdeme opět na objektu screen pod 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 vlastnosti innerHeight a inneWidth.

Nastavování vlastnosti CSS

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, akorát se nezapisují pomlčkovou notací, ale notací camelCase (první slovo celé malým, každé další má počáteční písmeno velké, žádné mezery). Takže například:

document.body.style.backgroundColor = "red";

nastaví barvu pozadí elementu body na červenou.

Vraťme se k 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 níže. Funkce cyklem projde všechny listy a všem nastaví novou pozici. Tu získá z hodnoty předchozí (kterou musíme kvůli odstranění 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 vyzkoušejte doplnit sami (místo písmen X).

var novaPozice = parseInt(listy[i].style.top) + XXXXXXXXXXXX;
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. Podmínku dejme 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 (opět vyzkoušejte) rozumnou hodnotu.

setInterval(posun, XXXXXXXXXXXXXXXXXXX);

Aplikaci spusťte. Uvidíte, že listí bude padat shora dolů a po vytečení z obrazovky zase odznovu.

Animace v JavaScriptu

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 pořád dokola. Jako ukázku si můžeme udělat kolo štěstí. Pro jednoduchost si ho 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.

<img src="kolo.png" id="kolo" />
<canvas id="platno" width="500" height="500"></canvas>

V scriptu si tyto objekty načtěme a přidejme si rovnou i proměnou, kde budeme mít uloženou hodnotu otočení. Obrázek nezapomeňte ze stránky skrýt.

var canvas
var ctx
var otoceni = 0;
var img;

window.onload = function () {
        canvas = document.getElementById("platno");
        ctx = canvas.getContext("2d");
        img = document.getElementById("kolo")
        img.style.display = "none";
}

V metodě prekresli() pak jednoduše vymažeme plátno a znovu jej překreslíme. To provedeme tím způsobem, že si nejprve vhodně přesuneme a otočíme kontext a poté obrázek vykreslíme. Nakonec přidejme k otočení jeden stupeň a to rovnou v jednotkách radiánů, ať to nemusíme přepočítat. Víme že 360°= 2*PI, tak jeden stupeň = (2*PI) / 360.

function prekresli() {
        ctx.clearRect(0,0,500,500);
        ctx.save();
        ctx.translate(250, 250);
        ctx.rotate(otoceni);
        ctx.drawImage(kolo, -225, -225);
        ctx.restore();
        otoceni += (2 * Math.PI) / 360 // otočení o 1 stupeň, ale v radiánech
}

V události načtení stránky opět zapneme interval a vykreslíme ji hned poprvé, abychom vizuálně snížili latenci stránky.

setInterval(prekresli, 20);
prekresli();
Animované kolo štěstí v JavaScriptu

Správně řešené animace

Všechna řešení animací, která jsme doposud prováděli, jsou v podstatě špatně. To, že sice fungují, je pěkné, ale podívejme se na ně z hlediska výkonu. Když uživatel opustí naší záložku, animace stále běží a vytěžuje procesor. Horší je to na mobilních zařízeních, kde to jde 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 můžete přečíst v článku JS requestAnimati­onFrame - za lepší vykreslování.

Gratuluji, již byste měli zvládat práci s animacemi. Dokázat si to můžete ve cvičení.


 

Stáhnout

Staženo 204x (218.71 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

  Aktivity (1)

Článek pro vás napsal Michal Žůrek (misaz)
Avatar
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.

Jak se ti líbí článek?
Celkem (4 hlasů) :
55555


 


Miniatura
Všechny články v sekci
Základní konstrukce jazyka JavaScript
Miniatura
Následující článek
Cvičení k 14. lekci JavaScriptu

 

 

Komentáře

Avatar
00
Člen
Avatar
00:
setIntervat()

?

 
Odpovědět 15.5.2015 15:06
Avatar
Odpovídá na 00
Michal Žůrek (misaz):

má tam být setInterval. Díky, opraveno.

Odpovědět 16.5.2015 11:22
Nesnáším {}, proto se jim vyhýbám.
Avatar
Jurajs
Člen
Avatar
Odpovídá na Michal Žůrek (misaz)
Jurajs:

Ahoj, kde jsi sebral v té podmínce textContent ?? Díky předem za vysvětlení :)

if (element.textContent == text) {
        element.textContent = "";
        return;
}
 
Odpovědět 24.11.2015 14:27
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 3 zpráv z 3.