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“.









var frekv=11,amp=4,vlocek=20,pri­dat_vlocek=2,max_pridat_plyn=3,

rychl=10,max_x,max_y;

function Vypnout(){

clearInterval(s_id);

for(var i=1;i<=vlocek;i++)

document.getElementById(„vloc­ka“+i).style.visibility=„hid­den“;

}

function Snezit(){

for(var i=1;i<=vlocek;i++)

{

vlocky[i][„sour_y“]+=vlocky[i][„plyn“];

if (vlocky[i][„sour_y“]>max_y) {

vlocky[i][„sour_y“]=0;

vlocky[i][„osa_x“]=Math.rou­nd(Math.random()*max_x);

}

vlocky[i][„sour_x“]=Math.rou­nd(vlocky[i][„osa_x“]+amp*Mat­h.sin

(vlocky[i][„sour_y“]/frekv));

document.getElementById(„vloc­ka“+i).style.top=vlocky[i]

[„sour_y“] ;

document.getElementById(„vloc­ka“+i).style.left=vlocky[i]

[„sour_x“ ];

} }

if (max_x=window.innerWidth); else if (max_x=document.

body.clientWidth); else max_x=800;

if (max_y=window.innerHeight);else if (max_y=document.

body.clientHeight); else max_y=600;

max_y-=16;

max_x-=16;

var vlocky=new Array();

for(var i=1;i<=vlocek;i++)

{

document.write(„
+“.gif\ style=\position:absolute\ id=\vlocka"+i+„\>“);

vlocky[i]=new Array();

vlocky[i][„osa_x“]=Math.rou­nd(Math.random()*max_x);

vlocky[i][„sour_y“]=Math.rou­nd(Math.random()*max_y);

vlocky[i][„plyn“]=1+Math.rou­nd(Math.random()*max_pridat_plyn);

}

var s_id=setInterval(„Snezit()“,rychl);



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!