NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 29 - Časovače a animace v JavaScriptu

V předešlém cvičení, Řešené úlohy k 25.-28. lekci JavaScriptu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V tomto tutoriálu základů JavaScriptu si ukážeme, jak našim kresbám nastavit časovače a docílit tím efektu animace na webové stránce.

Časovače a animace

Časovače můžeme v JavaScriptu obsluhovat pomocí dvou funkcí, které si nyní představíme.

Funkce setInterval()

Funkce slouží k opakovanému volání jiné funkce ve stanoveném intervalu. Jako parametry přijímá funkci, která se bude opakovaně volat, a časový interval, který určuje, jak často se volání bude opakovat. Funkci do parametru uvádíme bez závorek a čas udáváme v milisekundách, jedna sekunda odpovídá tisíci milisekund. Tuto funkci využijeme, když potřebujeme nastavit pravidelné opakování určité akce.

Funkce setTimeout()

Funkce setTimeout() slouží k odložení zavolání funkce o stanovený čas. Na rozdíl od funkce setInterval() se zavolá pouze jednou. Funkce setTimeout() přijímá stejné parametry – volanou funkci (bez závorek) a čas v milisekundách. Po zavolání funkce setTimeout() se čeká po dobu uvedenou v parametru, poté se zavolá předaná funkce.

Postupné vypsání textu

Ukažme si použití časovače nejprve na jednoduchém příkladu. Budeme v něm postupně vypisovat text Ahoj světe. Nejprve bude vidět písmeno A, o sekundu později přiskočí h a takto se budou přidávat další písmena. Jakmile bude vypsán celý text, smaže se a začne se vypisovat opět od začátku.

V těle HTML nebudeme mít žádný element, vše vytvoříme až z JavaScriptu:

<!DOCTYPE html>
<html lang="cs-cz">
    <head>
        <meta charset="UTF-8" />
        <title>Animace textu</title>
        <script src="animace_textu.js"></script>
    </head>
    <body>
    </body>
</html>

V projektu vytvoříme soubor animace_textu.js a vložíme do něj následující kód:

let text = "Ahoj světe";
let paragraph = document.createElement("p");

window.onload = function() {
    document.body.appendChild(paragraph);
}

Vytvořili jsme proměnnou text, kam jsme uložili náš výpis Ahoj světe. Poté jsme vytvořili element <p> a po načtení stránky jej přidali do těla dokumentu.

Funkce zmenText()

Pustíme se do tvorby funkce, která bude měnit text v našem elementu. Do našeho JavaScriptového souboru přidáme následující kód:

function zmenText() {
    if (paragraph.textContent == text) {
        paragraph.textContent = "";
    } else {
        // sem vzápětí doplníme další kód
    }
}

Jako první jsme vytvořili podmínku, která kontroluje, jestli je celý text už zobrazený. Pokud ano, obsah odstavce se smaže, aby bylo možné začít znovu. Tato kontrola je důležitá – kdybychom se pokusili zobrazit další znak za koncem textu, dostali bychom chybu, protože takový znak neexistuje.

Do větve else přidáme kód, který zajistí postupný výpis textu:

let pismenoKpridani = text[paragraph.textContent.length];
paragraph.textContent += pismenoKpridani;

Tento kód vybere další znak z proměnné text a přidá ho ke stávajícímu textu elementu paragraph. Pomocí vlastnosti length zjistíme délku textu aktuálně zobrazeného na obrazovce a tuto délku použijeme jako index pro výběr následujícího znaku, který se bude přidávat. Operátor += pak tento znak připojí na konec textu v elementu paragraph.

Je důležité si uvědomit, že:

  • Délka řetězce (length) začíná na hodnotě 1 (např. text s jedním znakem má délku 1).
  • Indexy znaků začínají na 0 (první znak má index 0, druhý 1 atd.).

Proto aktuální délka textu vypsaného na obrazovce odpovídá indexu dalšího znaku k vypsání v proměnné text.

Nakonec přidáme podmínku, která zjistí, jestli nevypisujeme mezeru. Pokud ano, ihned zobrazíme další znak, aby program působil plynule. Celý blok else bude vypadat takto:

else {
    let pismenoKpridani = text[paragraph.textContent.length];
    paragraph.textContent += pismenoKpridani;

    if (pismenoKpridani == " ") {
        zmenText();
    }
}

Pokud je přidaný znak mezera, zavoláme funkci zmenText(), která zajistí okamžité přidání dalšího znaku. Tím využíváme princip rekurze, což znamená, že funkce volá sama sebe, dokud není splněna podmínka pro ukončení. Rekurze zde zajišťuje, že mezera nebude zpomalovat plynulost programu.

Nastavení časovače

Nyní zbývá spustit interval. Obsluhu události onload upravíme tak, aby vypadala následovně:

window.onload = function() {
    document.body.appendChild(paragraph);
    zmenText();
    setInterval(zmenText, 1000);
}

Jako první jsme zavolali funkci zmenText(), aby se první písmeno vypsalo okamžitě po spuštění programu. Pokud bychom tuto funkci nezavolali, výpis textu by začal až po uplynutí první sekundy, což by mohlo působit dojmem, že aplikace nereaguje.

Dále voláme funkci setInterval(), která jako první parametr přijímá funkci zmenText() (bez závorek) a jako druhý číslo 1000, čímž jsme nastavili interval změny textu na jednu sekundu.

Celý kód vypadá takto:

let text = "Ahoj světe";
let paragraph = document.createElement("p");

window.onload = function() {
    document.body.appendChild(paragraph);
    zmenText();
    setInterval(zmenText, 1000);
}

function zmenText() {
    if (paragraph.textContent == text) {
        paragraph.textContent = "";
    } else {
        let pismenoKpridani = text[paragraph.textContent.length];
        paragraph.textContent += pismenoKpridani;

        if (pismenoKpridani == " ") {
            zmenText();
        }
    }
}

Výsledek v prohlížeči:

Animace textu
localhost

Složitější animace

Bylo by hezké mít na webu i nějakou složitější animaci. Jednoduché animace lze vyřešit v CSS, ale u těch složitějších již musíme použít JavaScript. Celá pointa animací spočívá v tom, ž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ů. Každý obrázek bude mít atribut data-podzim. Cíleně budeme vybírat pouze tyto obrázky, protože na webu mohou být (a bývají) i jiné obrázky a ty nechceme ovlivňovat.

Stáhneme si obrázek listu níže a vložíme jej do nového projektu:

List - Základní konstrukce jazyka JavaScript

V HTML souboru doplníme opět pouze hlavičku a tělo necháme prázdné:

<!DOCTYPE html>
<html lang="cs-cz">
    <head>
        <meta charset="UTF-8" />
        <title>Podzimní výzdoba</title>
        <script src="listy.js"></script>
        <link href="styl.css" rel="stylesheet" />
    </head>
    <body>
    </body>
</html>

Do projektu si přidáme CSS soubor s názvem styl.css a vložíme do něj následující kód:

body > img[data-podzim] {
    position: absolute;
}

body {
    overflow: hidden;
}

Obrázkům jsme v souboru nastavili absolutní pozici a <body> nastylovali tak, aby nezobrazovalo scrollbary.

Vytvoříme v projektu soubor listy.js a do něj umístíme následující kód:

document.addEventListener("DOMContentLoaded", function() {
    for (let i = 0; i < 5; i++) {
        let list = document.createElement("img");
        list.src = "list.jpg";
        list.setAttribute("data-podzim", "");
        list.alt = "List";
        document.body.appendChild(list);
    }

    // Zde vzápětí nastavíme počáteční pozici listů

});

V události DOMContentLoaded jsme nejprve pomocí cyklu vytvořili elementy obrázků listů s atributem data-podzim a vložili je do těla HTML.

Zjištění velikosti okna

Listům nyní budeme chtít nastavit výchozí pozici, kterou vypočítáme zleva jako pětinu šířky okna pro každý list. Horní pozici vypočítáme jako výšku okna mínus výška listu, aby při načtení stránky začaly sjíždět z horní hrany. Protože potřebujeme pracovat s velikostí okna, ukážeme si několik vlastností, které s tím souvisejí:

  • Velikost obrazovky - zjišťuje se pomocí vlastností screen.width a screen.height. Velikost obrazovky bez systémových panelů, jako je například taskbar, zjistíme pomocí screen.availWidth a screen.availHeight.
  • Velikost okna webové stránky – reprezentuje plochu dostupnou pro obsah webu. Šířku a výšku zjistíme pomocí window.innerWidth a window.innerHeight.

Nastavení CSS vlastností z JavaScriptu

Ukažme si ještě, jak nastavovat CSS vlastnosti elementům pomocí JavaScriptu. Každý DOM element má vlastnost style, která obsahuje CSS vlastnosti přepsané do camelCase notace místo pomlčkové. Například pro změnu barvy pozadí elementu <body> na červenou bychom mohli použít tento zápis:

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

Nastavení počáteční pozice listů

Vraťme se k našemu padajícímu listí a nastavme mu počáteční pozice. Nezapomeneme na doplnění jednotky px. Namísto komentáře v kódu výše doplníme:

let listy = document.querySelectorAll("body > img[data-podzim]");

for (let i = 0; i < listy.length; i++) {
    listy[i].style.top = -listy[i].height + "px";
    listy[i].style.left = i * window.innerWidth / listy.length + "px";
}

// Sem později doplníme funkci setInterval()

V tomto kódu nejprve získáme jednotlivé listy. V cyklu poté nastavíme postupně každému listu pomocí CSS stejnou horní pozici style.top. Levý okraj jednotlivých obrázků style.left posouváme násobkem aktuálního indexu cyklu, který se postupně inkrementuje.

Funkce posun()

Nyní vytvoříme funkci posun(), která bude posouvat všechny listy dolů:

function posun(listy) {
    for (let list of listy) {
        let novaPozice = parseInt(list.style.top) + 2;
        if (novaPozice > window.innerHeight) {
            novaPozice = -list.height;
        }
        list.style.top = novaPozice + "px";
    }
}

Funkce cyklem projde všechny listy a nastaví jim novou pozici. Aktuální pozici získá z jejich vlastnosti v CSS, kterou je potřeba naparsovat (převést na číslo). K této pozici se přičte vhodná hodnota, aby animace byla plynulá.

Pomocí podmínky funkce kontroluje, zda list nevyjel z okna. Pokud ano, nastaví jeho pozici na zápornou hodnotu výšky obrázku. Tím zajistí, že list začne znovu na horním okraji obrazovky.

Nyní zbývá pouze doplnit v obsluze události načtení okna nastavení časovače, přidáme tedy poslední řádek:

setInterval(function() {
    posun(listy);
}, 20);

Protože jsme potřebovali předat funkci posun() parametr, museli jsme místo klasického volání setInterval() použít anonymní funkci. Anonymní funkce zde slouží jako obal, který volá funkci posun a předává jí parametr listy. Bez tohoto obalu by kód nefungoval, protože setInterval() očekává pouze odkaz na funkci bez parametrů.

Aplikaci spustíme a uvidíme, že listí padá shora dolů a po opuštění obrazovky se znovu objeví nahoře:

Podzimní výzdoba
localhost

Nyní bychom měli již zvládat základy práce s animacemi. Jak zajistit, aby za nás webový prohlížeč spouštěl animaci jen když je potřeba, si řekneme jindy :)

V následujícím cvičení, Řešené úlohy k 29. lekci JavaScriptu, si procvičíme nabyté zkušenosti z předchozích lekcí.


 

Měl 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 1626x (13.02 kB)
Aplikace je včetně zdrojových kódů v jazyce JavaScript

 

Předchozí článek
Řešené úlohy k 25.-28. lekci JavaScriptu
Všechny články v sekci
Základní konstrukce jazyka JavaScript
Přeskočit článek
(nedoporučujeme)
Řešené úlohy k 29. lekci JavaScriptu
Článek pro vás napsal Michal Žůrek - misaz
Avatar
Uživatelské hodnocení:
1020 hlasů
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