Images czyli grafika na stronie

Aby manipulować grafiką na stronie, musimy się do niej odwołać korzystając zmetod pobierających obiekty.


<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 images = document.images //korzystając z kolekcji
var images = document.querySelectorAll('img'); //nowa metoda
var fish = document.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.querySelectorAll('img')[2]; //3 grafika na stronie
console.log('Szerokosc: ' + img.width + ', wysokosc: ' + img.height + ', src:' + img.src);

Efekt rollover

Do efektu rollover powinien 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 obrazek 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');

img.addEventListener('mouseover', function() {
    this.src = 'obrazek_2.jpg';
});

img.addEventListener('mouseout', function() {
    this.src = 'obrazek_1.jpg';
});

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

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, możemy odwoływać się do ich właściwości src. Poniższy skrypt realizuje całe zadanie:


if (document.images) {
    var imageOff = new Image();
    imageOff.src = '/images/obrazek1.jpg';

    var imageOn = new Image();
    imageOn.src = '/images/obrazek2.jpg';

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

    img.addEventListener('mouseover', function() {
        this.src = imageOn.src;
    });
    img.addEventListener('mouseout', function() {
        this.src = imageOff.src;
    });
}

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

Kliknij!
Zastrzel kartofla!

Powyższy efekt kliknięcia także można uzyskać z użyciem tylko CSS. Wystarczy wykorzystać do tego selektor :checked i selektor rodzeństwa ~. Poniżej zamieszczam skrócony wzór:


    <label class="cnt">
        <input type="checkbox">
        <div class="off"></div>
        <div class="on"></div>
    </label>

    .cnt {display:block; overflow:hidden;}
    .cnt input {left:-99999px; position:absolute;}
    .cnt .off {display:block;}
    .cnt .on {display:none;}
    .cnt input:checked ~ .off {display:none;}
    .cnt input:checked ~ .on {display:block;}

Efekt rollower dla większej ilości obrazków

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 names = [
    'obrazek.jpg',
    'kartofelek.jpg',
    'piesek.jpg',
    'kotek.jpg',
    'czekolada.jpg'
];

for (x=0; x<names.length; x++) {
    var img[x] = new Image();
    img[x].src = names[x];
}

Pasek wczytywania

Obiekty takie jak image czy window posiadają zdarzenie onload, które wykrywa, czy dany obiekt został w pełni załadowany.


window.addEventListener('load', function() {
    console.log('Cały dokument z grafiką został załadowany');
});

img.addEventListener('load', function() {
    console.log('Dana grafika została załadowana');
});

Można wykorzystać to zdarzenie 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. Dzięki temu zmniejszysz ilość requestów do swojej strony.

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 sprawdzać ile obiektów zostało załadowanych, musimy posłużyć się dodatkową zmienną ile_zaladowano.


<style>
    .loading-bg {
        margin:30px 0;
        width:600px;
        height:40px;
        background:#eee;
        border:1px solid #ddd;
        overflow:hidden;
    }
    .loading-bg .progress {
        width:0;
        height:100%;
        background:#EC185D;
        overflow:hidden
    }
</style>
<div id="progressCnt"></div>

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

    //funkcja odpalana dla każdego obiektu Image, które wcześniej stworzyliśmy.
    //Sprawdza ile obiektów zostało załadowanych i ustawia odpowiednią szerokość paska.
    function setLoadingBar() {
        howLoaded++;
        loadingBar.style.width = howLoaded * loadingStep + "%"; //zmianiamy szerokość paska (podaną w %)

        if (howLoaded >= imgNames.length) {
            setTimeout(function() {
                location.href = pageToRedirect; //po załadowaniu wszystkich grafik czekamy 2s i przenosimy na stronę
            }, 2000)
        }
    }

    //funkcja rozpoczynająca ładowanie obrazków
    function startLoading() {
        var div = document.querySelector('#progressCnt');

        loadingBarBg = document.createElement('div');
        loadingBarBg.className = 'loading-bg';    //dzięki temu skorzystamy ze zdefiniowanych styli

        loadingBar = document.createElement('div');
        loadingBar.className = 'progress';

        loadingBarBg.appendChild(loadingBar);

        div.appendChild(loadingBarBg);

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

    document.addEventListener("DOMContentLoaded", function(event) {
        startLoading();
    });
});

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


Trening czyni mistrza

Poniżej zamieszczam kilka zadań, które w ramach ćwiczenia możesz wykonać:

  1. Na środku powyżej stworzonego postępu ładowania dodaj tekst, który będzie pokazywał liczbę wczytywanych obrazków w formacie "Wczytano 5 / 10"