Kapka CSS - CSS2 Tipy & triky [VII]

1. 1. 2003

Sdílet

V předchozích dílech jsme se více než kdy dříve zaměřili na příklady sokamžitým vizuálním efektem, tedy takové, u nichž je na první pohled patrná jejich činnost, a dle reakcí č...
V předchozích dílech jsme se více než kdy dříve zaměřili na příklady s
okamžitým vizuálním efektem, tedy takové, u nichž je na první pohled patrná
jejich činnost, a dle reakcí čtenářů pak nemohu jinak než ve stejném stylu
pokračovat i nadále. Znamená to upustit od "plané" teorie, jíž už je nabita
spousta jiných moudrých knih, a věnovat se skutečně funkčním příkladům, z nichž
lze vycházet v praxi, která, jak už bylo mnohokrát zmíněno, se nemusí vždy
shodovat s teorií, zvláště v dnešní době, kdy stále ještě vládne nejednota na
poli webových prohlížečů. Snažím se proto, aby právě v tomto byl náš seriál
výjimečný. Jako již obvykle, dodávám, že i dnes najdete ukázky zde uváděné na
CD PC WORLDu.

Myslím že se sluší, abych dnešní díl, který budete číst možná právě o svátcích
vánočních, kapánek protáhnul. Nebudu ale takový technokrat, abych vám o
Vánocích předkládal nezáživné technické příklady a zkusíme si proto vytvořit
ukázku padání sněhových vloček, které ne každý má bohužel i za oknem. Ukážeme
si příklad, kterak vytvořit sněžení, a koneckonců, až budeme s programem
hotovi, třeba už bude sněžit i za našimi okny ;). Použít jej potom jednoduše
můžeme na kterékoliv svoji stránce. Pro ty, kdo se nechtějí zabývat detaily,
jsem text s rozšiřujícími informacemi napsal tučným písmem. Dodám jen, že
příklad jako obvykle funguje v prohlížečích s podporou DOM (Document Object
Model Objektový model dokumentu), z těch známějších jsou to např. IE5+,
Opera4+, NS6+.

První úkol je nakreslení sněhových vloček tři druhy by pro naši ukázku mohly
postačit. Nazveme je "vlocka1.gif", "vlocka2.gif" a "vlocka3.gif". Volíme
formát GIF (popř. PNG), neboť může obsahovat pozadí transparentní (průsvitné)
chceme přece, aby obzor překrývala pouze vločka, nikoliv celá čtvercová plocha
s naším obrázkem! Nyní máme připravené podklady a můžeme začít s tvorbou
příkladu pomocí DHTML. Zapisovat budeme příkazy samozřejmě jako skript, proto
tedy do části našeho HTML, označené tagy SCRIPT. Nejprve si ujasníme, na jaké
ploše se sněžení bude rozprostírat. Tu definujeme souřadnicemi (v pixelech)
zapsanými v proměnných max_x (maximální šířka) a max_y (maximální výška). Mohli
bychom rovnou uvést např. 800 a 600, ve skutečnosti ale nevíme, jakou velikost
pracovní plochy má na svém počítači ten, kdo bude ukázku sledovat. Jde tedy o
to, aby mu tak vločky nepadaly třeba jen do půli obrazovky, či naopak daleko za
její hranice. Pokusíme se proto o univerzální řešení. Ke zjištění velikosti
pracovní plochy obzoru ;) se vztahuje několik prostředků, které nám mohou být
nápomocny.

Jsou to vlastnosti, které jsou součástí DOM u IE5+, NS6+ a Opera6+, přestože se
v oficiálním doporučení konsorcia W3C o DOM nevyskytují. Jejich názvy jsou
offsetWidth (obsahuje šířku elementu) a offsetHeight (obsahuje výšku elementu).
Leckdo se pak možná dovtípí, že potřebné informace nám vlastnosti poskytnou u
elementu BODY, tedy např. document.body.offsetWidth. Nyní bychom mohli vesele
pokračovat, kdyby... kdyby interpretace této vlastnosti nebyla u některých
prohlížečů poněkud odlišná než u těch ostatních, což nám situaci poněkud
komplikuje. Opera a Netscape totiž u vlastnosti, která poskytuje výšku
dokumentu, nevrací jeho celou výši (např. 600 pixelů), ale jen její aktuálně
používanou část (je-li např. na obrazovce vypsán jen jeden řádek textu, pak
vlastnost obsahuje např. 37), čímž se pro náš příklad stává de facto
nepoužitelnou.

Použijeme proto poněkud méně univerzální vlastnosti, konkrétně jsou jimi
clientWidth (obsahuje šířku elementu) a clientHeight (obsahuje výšku elementu),
které jsou použitelné u elementu BODY pouze v IE (např.
document.body.clientWidth), a innerWidth (šířka) a innerHeight (výška), které
zná zase Netscape a Opera u elementu WINDOW (tj. hlavního objektu v DOM, proto
by nebylo nutné uvádět zdlouhavý zápis window.innerHeight a postačil by samotný
název vlastnosti tedy v prohlížeči, který ji podporuje. Ostatní by to mohli
považovat za název proměnné, která neexistuje, a hlásili by chybu, proto se
zkráceného zápisu tentokrát vyvarujeme). Nyní už můžeme jednoduše do proměnných
max_x a max_y zapsat potřebné souřadnice. Můžeme to udělat podmínkami
(vlastnost je podporována, pokud obsahuje nenulovou hodnotu) a bohužel musíme
počítat i s tím, že některý prohlížeč nemusí dokonce podporovat žádnou z výše
uvedených vlastností. Začít bychom tedy mohli například takto:

if (document.body.clientWidth>0) max_x= document.body.clientWidth; else ...

což můžeme ale zkrátit na:

if (document.body.clientWidth) max_x= document.body.clientWidth; else ...

a konečně na:

if (max_x=document.body.clientWidth);else if (max_x=window.innerWidth); else
max_x=800;

...což je podmínkami ošetřený zápis, jehož výsledkem je získaná aktuální šířka
plochy dokumentu, eventuálně hodnota 800 (pixelů), pokud není prohlížečem
podporována ani jedna zmíněná vlastnost. Pracovní plochu máme zjištěnu.
Posledním detailem je odečtení výšky největšího obrázku (v našem případě 16
pixelů) od zjištěné výšky plochy a šířky (rovněž 16 pixelů) od zjištěné šířky
plochy (zápis a-=b odpovídá zdlouhavějšímu a=a-b), aby nedocházelo k vykreslení
obrázků za její hranice a tím pádem rušivému automatickému zobrazování
scroll-baru prohlížečem. Následuje možná trochu technokraticky nazvaný proces,
inicializace vloček ;). Máme tím na mysli nastavení všech potřebných parametrů,
před samotným zahájením sněžení.

Při deklaraci (vytváření) proměnných uvádíme před jejich název klíčové slovo
var, což sice není nezbytné, ale jde o dobrý zvyk. Zápis "var a=5" má tedy
stejný význam jako "a=5".

Do proměnných nyní zapíšeme stanovené hodnoty, jimiž jsou:

- Počet vloček, jež mají najednou na obrazovce padat (vlocek=20).
- Počet dalších druhů vloček (pridat_vlocek=2).
- Rychlost obnovování padajících vloček (rychl=10).
- Maximální rychlost padání vloček (max_pridat_plyn=3).
- Šířka dráhy padající vločky (amp=4).
- Rychlost kmitání padající vločky do stran (frekv=11).

Obrázek naznačuje dráhu padající vločky. Jak je patrno, jde vlastně o průběh
matematické funkce sinus, převrácený na výšku. Zeleně značená dráha má větší
šířku (amplitudu) a menší kmitání (frekvenci).

Základní data jsou určena a nyní je zpracujeme. Informace o každé z vloček si
uložíme do nové proměnné, a protože jich bude hodně, půjde o celé pole.
Příkazem new Array() si tedy vytvoříme pole proměnných s názvem vlocky. Do něj
pak v následujícím cyklu for uložíme informace o každé jedné vločce. Blok
příkazů mezi složenými závorkami "{" a "}" se bude opakovat tolikrát, kolik je
vloček. Při každém jednom provedením nabývá proměnná "i" vyšší hodnoty, tedy od
1 až po celkový počet vloček. Nejprve se pokaždé příkazem document.write zapíše
do našeho HTML tag IMG s jedním obrázkem vločky. Každému pomocí kaskádových
stylů a vlastnosti "POSITION" určíme absolutní umístění na obrazovce a atribut
"ID" (sloužící k identifikaci), který je pro každý obrázek jedinečný (např.
"vlocka14"). Na začátku jsme si pro větší pestrost nakreslili tři druhy vloček
(rozlišené čísly 1-3 v jejich názvu), hodláme je tedy všechny vyžít. U každé
vločky totiž náhodně vybereme, který ze tří obrázků se pro ni vybere. Docílíme
toho pomocí metody Math.random, jež generuje náhodné číslo od 0 do 1 včetně
desetinných míst. My však požadujeme číslo v rozsahu 1-3. Jednoduchou
matematikou tedy rozsah náhodně vygenerovaných čísel jejich vynásobením
zvětšíme až na potřebnou hodnotu (např. na hodnotu 2, jíž obsahuje proměnná
pridat_vlocek). Získanou desetinnou hodnotu metodou Math.round zaokrouhlíme na
celé číslo a vyskytnutí nuly zamezíme přičtením hodnoty 1 k němu (čímž konečně
získáváme potřebné hodnoty 1-3). Pokračujeme dalším krokem. Najednou však
zjišťujeme, že námi dříve vytvořené pole, obsahující tolik proměnných, kolik je
vloček, asi nebude stačit. Každá totiž nese více než jednu informaci, bude tak
třeba vytvořit ke každé položce pole (ta zastupuje vždy jednu vločku) ještě
další pod-položky. Vytvoříme proto tzv. vícerozměrné pole, tzn. že každý jeho
prvek bude zastupovat nové pole proměnných. Opět nám k tomu poslouží příkaz new
Array(), který tak provedeme u každého prvku pole. Nové proměnné jsou osa_x,
která bude obsahovat x-ovou (horizontální) souřadnici osy padající vločky, dále
sour_y, která obsahuje vždy aktuální y-ovou (vertikální) souřadnici, a položka
plyn, která zaznamenává rychlost, s jakou bude padat. Všechny zmíněné informace
jak je patrno jsou generovány opět náhodně, ale v závislosti na limitách
definovaných na začátku našeho skriptu ve výše uvedených proměnných (max_x,
max_y...). Toliko z cyklovaného bloku. Nyní už může následovat spuštění
sněžení. Metoda setInterval se postará o to, aby se v pravidelném intervalu
spouštěla zadaná funkce. Jaká to má být, se uvádí v prvním parametru
("Snezit()"), a po jakých časových intervalech to bude (určíme proměnnou
rychl), zase v parametru druhém, který je vyjádřen v milisekundách
(1000ms=1sec). Jelikož lze spouštět v různých časových intervalech souběžně
více funkcí, je nutné každý takový proces označit. Až budeme totiž v budoucnu
chtít spouštění funkce zarazit, je proto pak vyžadována právě její
identifikace. Tu jsme si tedy uložili do proměnné s názvem s_id. Nyní si
popíšeme naší funkci Snezit. Ta se celá skládá z cyklu for, který zpracovává
padání každé vločky a provádí následující: Nejprve se k proměnné sour_y v poli
vlocky přičte hodnota proměnné plyn, a právě o tolik pixelů se tedy vločka
posune směrem dolů (zápis a+=b je ekvivalentní k zdlouhavějšímu a=a+b). Na
dalším řádku pak zkontrolujeme, zdali se již nesnesla příliš nízko a nepřesáhla
hranice okna prohlížeče (není-li sour_y, obsahující aktuální souřadnici, větší
než max_y se souřadnicí hraniční). Pokud tomu tak je, provede se blok,
zajišťující nastavení y-ové souřadnice opět na počáteční, tedy na nulu a x-ové,
osové souřadnice na novou, náhodně zvolenou, aby vločka nepadala znovu po
stejné dráze. V předchozí větě jsme sice již x-ovou souřadnici nastavili, ale
pouze osu a proto vždy jen na začátku procesu padání, neboť se pak po celé své
dráze nemění. Vločka ale jak již z výše uvedeného obrázku vyplývá nebude padat
pouze svisle dolů. Přiblížení se ke skutečnému pohybu při sněžení zajistíme
tak, že se bude obrázek vločky během padání neustále vychylovat z osy, jak je
znázorněno na náčrtu výše. Hodnoty pro vychýlení získáme z metody Math.sin,
která vrací průběh funkce sinus ze zadaného parametru (y-ové dráhy vločky). Ten
můžeme libovolně upravovat k obrazu svému jeho vynásobením (činíme tak
proměnnou amp) či vydělením jeho parametru (proměnnou frekv) viz popis u
obrázku. K vychylovacím hodnotám konečně přičteme hodnoty osy a získanou
hodnotu zapíšeme do proměnné sour_x v poli vlocky. Následuje metoda
getElementById, jejímž vstupním parametrem je hodnota atributu "ID"
(identifikátoru) u elementu IMG našeho obrázku. Metoda vrací odkaz na objekt
tohoto elementu v DOM, jeho potomkem je zase objekt style, který obsahuje
použitý styl elementu, a "TOP" je již zmiňovaná vlastnost stylu, určující
vertikální pozici obrázku, a "LEFT" určuje zase pozici horizontální. Těmto
vlastnostem pak přiřazujeme hodnoty aktuálních souřadnic naší vločky. Zbývá už
jen volba, umožňující ustátí sněžení. To zajistí funkce Vypnout, která se
vyvolá, pokud myší klikneme na odkaz "Vypnout sněžení" v našem HTML. Funkce
sněžení zruší metodou clearInterval (rovněž z DOM objektu window), která ukončí
pravidelné provádění naší funkce Snezit. Aby pak vločky nezůstaly na obloze
"viset", zhasneme je jednu po druhé pomocí stylů, konkrétně přiřazením hodnoty
"HIDDEN" pro vlastnost s názvem "VISIBILITY".




Vypnout sněžení



A to je již opravdu vše. Musím ještě upozornit, že opravdová "chumelenice" by
si vzhledem k náročnosti JavaScriptu na výkon počítače vyžádala i poněkud více
jeho výkonu. Abychom proto neodradili uživatele s pomalejšími stroji, kde by
tak pohyb velkého množství vloček ani nemusel být hezky plynulý, měli bychom si
vystačit s cca 20-30 vločkami. Tímto tedy končím dnešní "vánoční" díl seriálu.
Pište e-maily s dotazy (j.kysela@web-brana.cz), třeba příště zodpovím právě ten
váš. Prozatím se mějte hezky a přeji vám všem krásné Vánoce!