tez m Kurs Javascript - grafika na stronie
Strona początkowa

Images czyli grafika na stronie

Aby manipulować grafiką na stronie, musimy się do niej odwołać. Możemy to zrobić na kilka sposobów. Korzystając z metody getElementsByTagName, kolekcji document.images lub ze standardowego atrybutu id. Możemy tez wykorzystać metody DOM, aby dobrać się do naszych grafik:

	<img src="piesek.jpg" width="100" height="100" alt="piesek" />
	<img src="kotek.jpg" width="100" height="100" alt="kotek" />
	<img src="chomik.jpg" width="100" height="100" alt="chomik" />
	<img src="rybka.jpg" width="100" height="100" alt="rybka" id="rybcia" />
	<img src="chupacabra.jpg" width="100" height="100" alt="chupacabra" id="chupacabra" />

	var obrazki = document.images //stara metoda
	
	var obrazki = document.getElementsByTagName('img'); //nowa metoda
	
	var rybka = documen.getElementById('rybcia');

	var chupacabra = rybka.nextSibling();
	

Każdej grafice możemy ustawiać standardowe atrybuty html dla grafiki (border, name, height, width, hspace, vspace, lowsrc, src), lub też zmieniać jego style.

	var obr = document.getElementsByTagName('img')[2]; //3 grafika na stronie
	alert('Szerokosc: ' + obr.width + ', wysokosc: ' + obr.height + ', src:' + obr.src);
	

Efekt rollover

Do efektu rollover pownien być stosowany zwykły CSS. Jeżeli nie masz powodu by wykorzystywać do tego JS - nie rób tego. Koniec kropka.

Dzięki Javascript nie musimy się ograniczać tylko do sytuacji, gdy obraze wskazujemy kursorem. Podmiana obrazka może nastąpić podczas dowolnego zdarzenia, jakie obsługuje Javascript.

Aby podmienić grafikę na inną musimy zmienić atrybut src danej grafiki:

	var obr = document.getElementById('obrazek');
	obr.onmouseover = function() {
		this.src = 'obrazek_2.jpg';
	}
	obr.onmouseout = function() {
		this.src = 'obrazek_1.jpg';
	}
	

Efekt rollower z wcześniejszym załadowaniem obrazków

Niestety powyższa metoda ma poważny błąd. Nowa grafika zostaje ściągana dopiero, gdy wskażemy nasz obrazek kursorem. Przy wolnych łączach lub dużych grafikach spowoduje to brak płynności.
Aby temu zapobiec musimy wszystkie grafiki biorące udział w efekcie rollover załadować do cache przeglądarki (czyli je wcześniej pobrać). Wówczas, w chwili wskazania obrazka, skrypt szybko podmieni jeden obrazek na drugi.

Aby załadować grafiki do cache musimy skorzystać z obiektu typu Image, któremu ustawimy odpowiednią właściwość src. Podstawowa deklaracja tego typu obiektu ma postać:

	if (document.images) { //sprawdzamy czy przeglądarka obsługuje obiekty images
		var nowyImage = new Image(width,height) //tworzymy nowy obiekt Image - parametry width i height są opcjonalne
			nowyImage.src = "obrazek_on.jpg" //podajemy jego src
	}
	

Gdy utworzymy już stosowne obiekty, mozemy odwoływać się do ich właściwości src. Poniższy skrypt realizuje całe zadanie:

	<img src="obrazek_1.jpg" width="100" height="100" alt="Uhhh!..." id="obrazek" />

	<script type="text/javascript">
	if (document.images) {
		var Image_off = new Image();
		Image_off.src = 'obrazek_1.jpg';

		var Image_on = new Image();
		Image_on.src = 'obrazek_2.jpg';

		var obr = document.getElementById('obrazek');

		obr.onmouseover = function() {
			this.src = Image_on.src
		}
		obr.onmouseout = function() {
			this.src = Image_off.src
		}
	}
	</script>
	

Oczywiście nie tylko zdarzeniem mouseover człowiek żyje. Można przecież także i click wykorzystać:

Kliknij!

Zastrzel kartofla!

Efekt rollower dla większej ilosci obrazkow

Przypuśćmy, że na naszej stronie mamy więcej grafik z efektem rollover (np. zmieniające się menu). Deklarowanie dla każdej grafiki obu stanów w podany powyżej sposób mija się z celem. O wiele lepszym rozwiązaniem jest zastosowanie tablicy do przechowywania nazw obrazków, a następnie za pomocą pętli dynamiczne tworzenie obiektów Image:

	var nazwy = new Array('obrazek.jpg', 'kartofelek.jpg', 'piesek.jpg', 'kotek.jpg', czekolada.jpg')
	for (x=0; x<nazwy.length; x++) {
		var obr[x] = new Image();
		obr[x].src = nazwy[x];
	}
	

Jescze lepszym rozwiazaniem ulatwiajacym odwolywanie sie do naszych obiektów, bedzie stworzenie tablicy zagniezdzonej:

	var nazwy = new Array('obrazek', 'piesek', 'kotek', czekolada')
	for (x=0; x<nazwy.length; x++) {
		var obr[x] = new Array();
		obr[x]['on'] = new Image();
		obr[x]['on'].src = nazwy[x]+'_on.jpg';
		obr[x]['off'] = new Image();
		obr[x]['off'].src = nazwy[x]+'_off.jpg'
	}

	document.getElementById('obrazek').onmouseover = function() {
		this.src = obr[1]['on'];
	}
	document.getElementById('obrazek').onmouseout = function() {
		this.src = obr[1]['off'];
	}
	

W powyższym skrypcie założyłem, że każdy obrazek jest w 2 wariantach: z końcówką _on.jpg i z końcówką _off.jpg. Oczywiście takie założenia mogą być zupełnie inne i zależą tylko od naszej wyobraźni (i odpowiedniego stosowania metod stringsów takich jak np. indexOf).

Pasek loadingu

Obiekty takie jak image czy window posiadają zdarzenie onload, które wykrywa, czy dany obiekt został w pełni załadowany. Można wykorzystać to zdarznie do zrobienia paska postępu, który będzie pokazywał ile grafik zostało już załadowanych. Jednym z minusów takiego rozwiązania jest fakt, że nie jesteśmy w stanie wykryć ile procent danego obrazka zostało załadowane, dlatego aktualizacja paska będzie się odbywała dopiero po załadowaniu kolejnego obrazka. Tak więc pasek taki najlepiej sprawdza się w sytuacji ładowania dużej liczby grafiki.

Staraj się ładować na stronę jak najmniej oddzielnych grafik. Część albo i wszystkie grafiki możesz trzymać w jednym pliku i odpowiednio go ciąć za pomocą CSS (podobną metodę zastosowaliśmy przy tworzeniu zakładek). Dzięki temu zmniejszysz ilość requestów do swojej strony.

Za pomocą JS tworzymy diva - pasek postępu. Aby muc go skalować podając jego szerokość w %, umieszczamy go w dodatkowym divie.

loading

Nazwy obrazków do załadowania podajemy w formie tablicy. Następnie wykonujemy pętlę po tej tablicy, tworząc obiekty Image z odpowiednim src. Dla każdego obiektu definiujemy zdarzenie onload. Będzie ono wywoływało funkcję, która sprawdza ile obiektów zostało już załadowanych i odpowiednio ustawiało długość paska ładowania (w procentach). Aby móc spradzać ile obiektów zostało załadowanych, musimy posłużyć się dodatkową zmienną ile_zaladowano.

Jeżeli przejżymy internet w poszukiwaniu informacji na temat zdarznia onload dla obrazków okaże się że jest to jedno z najbardziej zabugowanych zdarzeń w JS. Część przeglądarek źle je obsługuje: niektóre mają problemy z wywoływaniem tego zdarzenia dla obrazków znajdujących się w cache przeglądarki, niektóre nie wywołują tego zdarzenia jeżeli załadowanemu obrazkowi zmienimy grafikę za pomocą SRC, a niektóre krzaczą się gdy wyślemy zły nagłówek dla grafiki... Ogólnie jest to dosyć ryzykowne zdarzenie, dlatego trzeba czasami trzeba szukać rozwiązania w necie.

Istnieje za to pewna zasada, której warto się trzymać. Zdarzenie onload definiujemy PRZED podaniem src obrazka. Czemu? Zwykła logika.
Obrazek może zostać wczytany zanim skrypt "dowie się" że cehcemy obsłużyć dla niego zdarzenie onload (przypadek, gdy obrazek jest w cache przeglądarki). Wtedy nasze zdarzenie nie zostanie wykonane.
Dodatkowo zasada ta nabiera znaczenia dla przeglądarek działających na silniku Webkit (np Chrome). W przeglądarkach tych pobranie rozmiarów obrazka jest możliwe dopiero po całkowitym jego wczytaniu (czyli dopiero w zdarzeniu onload).

	<style >
		div#loading {width:400px; height:10px; background:#333366; overflow:hidden}
		div#pasekPostepu {width:0%; height:100%; background:#3366CC; overflow:hidden}
	</style>

	<script type="text/javascript">
	//tablica z nazwami obrazków do załadowania
	var nazwyObrazkow = [
		'obrazek1.gif',
		'obrazek2.gif',
		'obrazek3.gif',
		'obrazek4.gif',
		'obrazek5.gif',
		'obrazek6.gif'
	];
	var ile_zaladowano = 0; //ile obiektów Images już załadowano do pamięci
	var szerokosc_przeskoku = (100/nazwyObrazkow.length); //szerokość oznaczająca % paska po załadowaniu 1 obrazka
	var obr = []; //tablica będzie zawierała obiekty Image
	var div = null; //zmienna pod którą utworzymy dynamicznie div zawierającego div-pasek postępu
	var pasek = null; //zmienna pod którą utworzymy dynamicznie div-pasek postępu
	var strona = 'index.php'; //strona na którą przeniesie po zakończonym ładowaniu


	//funkcja rozpoczynająca ładowanie obrazków
	function start_Loading() {
		div = document.createElement('div');
		div.id = 'loading';				//dzięki temu skorzystamy ze zdefiniowanych styli
		pasek = document.createElement('div');
		pasek.id = 'pasekPostepu';
		div.appendChild(pasek); 		//wstawiamy div-pasek postępu do diva
		document.getElementsByTagName('body')[0].appendChild(div);		//wstawiamy div na końcu body

		for(var x=0; x<nazwyObrazkow.length; x++) {		//pętla po nazwach obrazków...
			obr[x] = new Image();
			obr[x].onload = ustawPasek;			//dla każdego obiektu ustawiamy zdarznie onload
			obr[x].src = nazwyObrazkow[x];			
		}
	}


	//funkcja odpalana dla każdego obiektu Image, które wcześniej stworzyliśmy. Sprawdza ile obiektów zostało załoadowanych i ustawia odpowiednią szerokość paska
	function ustawPasek() {
		ile_zaladowano++;
		pasek.style.width = ile_zaladowano * szerokosc_przeskoku + "%"; //zmianiamy szerokość paska (podaną w %)
		
		if (ile_zaladowano >= nazwyObrazkow.length) {
			setTimeout("location.href='"+strona+"'", 2000) //po załadowaniu wszystkich grafik czekamy 2s i przenosimy na stronę
		}
	}

	window.onload = start_Loading; //odpalamy funkcję start_Loadingu
	</script>
	

Powyższy przykład możesz zobaczyć w działaniu tutaj.