W tym odcinku kursu Ajaksa zajmiemy się interakcją Ajax – PHP. Zapytania HTTP wysyłane w tle przez obiekt XMLHttpRequest będą odwoływały się do skryptów PHP. Jako przykład przygotowałem galerię fotografii. Miniaturowe zdjęcia zawarte w galerii możemy podglądać wskazując je myszką. Wyskakujące okienka pop-up zawierają powiększoną fotografię oraz dodatkowe dane. Skrypt PHP będzie odpowiadał za przekazanie do Ajaksa danych EXIF konkretnej fotografii.
Okienka pop-up z podglądem fotografii
Galeria fotografii widoczna na rys. 1 prezentuje zestawienie miniaturowych fotografii. Wskazanie dowolnej fotografii wskaźnikiem myszy
powoduje pojawienie się małego okienka (tzw. pop-up) zawierającego powiększoną fotografię. Okienko oprócz powiększonego zdjęcia zawiera dodatkowe informacje: nazwę aparatu, jakim wykonano zdjęcie, wartości przysłony,
czasu oraz ogniskowej.
Okno pop-up zawiera zawsze dane bieżące o wskazanej fotograf ii, co widać na rys. 3. Oczywiście liczba wierszy i kolumn tabeli miniatur, jak również wymiary zdjęcia wyświetlanego w oknie pop-up mogą być dowolne (rys. 4). Dodatkowo,
ok na pop-up wędrują za wskaźnikiem myszki, jego przesunięcie powoduje przesunięcie ok na pop-up.
Rozwiązanie takie znajdziemy m.in. w serwisach
Template Monster, iStockphoto
oraz WebHandel.
Rozwiązanie – opis krok po kroku
W omawianej galerii:
- men u strony (tj. tabelkę miniatur) generujemy w PHP na podstawie zawartości folderu mini/ (funkcja {stala}glob(){/stala}),
- każda miniaturka obsługuje zdarzenia: {stala}onmouseover{/stala}, {stala}onmousemove{/stala} oraz {stala}onmouseout{/stala},
- po wystąpieniu zdarzenia {stala}onmouseover{/stala} pojawia się wyskakujące okienko pop-up,
- po wystąpieniu zdarzenia {stala}onmousemove{/stala} okienko pop-up jest przesuwane do nowego położenia,
- zdarzenie {stala}onmouseout{/stala} ukrywa okienko pop-up,
- w okienku pop-up zostaje umieszczone powiększone zdjęcie. Pobranie powiększonej fotografii jest wykonywane asynchronicznie w tle przez przeglądarkę – nie jest do tego wykorzystany obiekt {stala}XMLHttpRequest{/stala},
- poniżej powiększonej fotografii w oknie pop-up zostają umieszczone dane EXIF wybranego zdjęcia – dane EXIF są pobierane przez obiekt {stala}XMLHttpRequest{/stala}.
Krok 1: dane
Fotografie zawarte w galerii należy przygotować
w dwóch formatach: większym i mniejszym.
Miniaturki umieszczamy w folderze mini/,
zaś fotografie duże w folderze duze/. Duże
i małe zdjęcia muszą być zapisane w plikach
o identycznych nazwach, np.:
mini/foto-03.jpg
duze/foto-03.jpg
Krok 2: tabela miniatur
Za wydrukowanie tabeli miniatur odpowiadają
dwa proste skrypty PHP. Na początku skryptu
{stala}index.php{/stala} w tablicy {stala}$plks{/stala} ustalamy nazwy
wszystkich plików graficznych o rozszerzeniu
.jpg z folderu mini/. Tablicę {stala}$plks{/stala} przekształcamy
na tablicę dwuwymiarową o zadanej liczbie
kolumn. Odpowiada za to funkcja {stala}array_1dim_to_2dim(){/stala} z pliku {stala}array.inc.php{/stala}:
Tabela XHTML jest drukowana w podwójnej
pętli for sterowanej liczbą wierszy i kolumn
tabeli:
for ($i = 0; $i < $ile_wierszy; $i++) {
echo \'\';
for ($j = 0; $j < $ile_kolumn; $j++) {
if (isset($plks[$i][$j]) && ($plks[$i][$j] != \'\')) {
echo \' \';
} else {
echo \' \' . \"\n\";
}
}
echo \' \';
}
Drukowane komórki td zawierają obrazy
ze zdefiniowaną obsługą zdarzeń:
Parametr this zawiera wskaźnik do klikniętego
obrazu, zaś event umożliwia odczyt
współrzędnych wskaźnika myszy.
Krok 7: asynchroniczne pobieranie dużego zdjęcia i danych EXIF
Proces ładowania dużego zdjęcia i danych EXIF
jest realizowany wewnątrz funkcji {stala}powiekszenie_exif(){/stala}. Jej parametrem jest nazwa pliku
graficznego, np. foto-003.jpg.
Pobraniem dużej fotografii zajmie się
przeglądarka. Wymieniamy wartość atrybutu
src; nie zachodzi konieczność użycia obiektu
{stala}XMLHttpRequest{/stala}. Po zmianie wartości src
elementu img przeglądarka sama w tle wysyła
zapytania HTTP, pobiera potrzebny obraz
i umieszcza go na stronie WWW. To taki
Ajax bez obiektu {stala}XMLHttpRequest{/stala}. Wyświetlenie
dużego zdjęcia wymaga zatem wyłączenia
trzech linijek kodu:
var el;
el = document.getElementById(\'duze\');
el.src = \'duze/\' + filename;
Kod ten możemy również zapisać w postaci jednej linijki:
document.getElementById(\'duze\').src = \'duze/\' + filename;
Dane EXIF natomiast odbieramy od skryptu
server.php.
Pełny kod funkcji {stala}powiekszenie_exif(){/stala} jest
następujący:
function powiekszenie_exif(filename) {
r = getXMLHttpRequest();
var el;
el = document.getElementById(\'duze\');
el.src = \'duze/\' + filename;
r.open(\'GET\', \'server.php?id=\' + filename, true);
r.onreadystatechange = handleAjaxResponse;
r.send(null);
}
Tutaj właśnie pojawia się interakcja: Ajax
– PHP. Sprowadza się ona do użycia adresu
URL odnoszącego się do skryptu PHP:
sever.ph?id=foto-023.jpg
Komunikacja w kierunku: od Ajaksa do
PHP odbywa się za pośrednictwem zmiennych
URL.
Krok 8: wysyłanie danych z PHP do Ajaksa
Skrypt PHP ma za zadanie odczytać dane EXIF
i przesłać je – w postaci tabeli XHTML – do
Ajaksa. Nazwa pliku graficznego jest przekazywana
z Ajaksa do PHP jako zmienna URL
o nazwie id. Najpierw ustalamy nazwę pliku,
następnie funkcją {stala}exif_read_data(){/stala} odczytujemy
dane EXIF, po czym instrukcją echo wysyłamy
odpowiednią tabelę XHTML:
Aparat:
{$exif[\'Make\']}
Model:
{$exif[\'Model\']}
...
\";
}
?>
Walidacja zmiennej URL polega na dopasowaniu
otrzymanego łańcucha do wyrażenia
regularnego {stala}^foto-[0-9]+\\.jpg${/stala}. W przypadku
zmiany nazw plików w galerii, ten fragment
należy poddać modyfikacji.
Krok 9: odbieranie danych
Za odbiór danych ze skryptu PHP odpowiada
funkcja {stala}handleAjaxResponse(){/stala}. Jeśli transmisja
zakończy się sukcesem, to odebrany tekst
jest wpisywany do elementu div o identyfikatorze {stala}#exif{/stala}:
function handleAjaxResponse() {
if ((r.readyState == 4) && (r.status == 200)) {
e = document.getElementById(\'exif\');
e.innerHTML = r.responseText;
}
}
Krok 3: okienko pop-up
Okienko pop-up jest elementem {stala}div#popup{/stala}
umieszczonym po znaczniku {html}
...
Ten początkowo niewidoczny element jest
pozycjonowany bezwzględnie i przesunięty na
wierzch:
#popup {
display: none;
position: absolute;
z-index: 50;
...
}
Wyskakiwanie okienka pop-up polega na:
- zmianie widoczności (właściwość CSS display),
- ustaleniu położenia (właściwości CSS top i left).
Okno pop-up pojawia się po wystąpieniu
zdarzenia {stala}onmouseover{/stala}. W obsłudze zdarzenia
wykorzystane są dwa parametry: wskaźnik
do klikniętego obrazu (parametr element)
oraz zdarzenie (parametr event):
function show_popup(element, event) {
if (!event) {
var event = window.event;
}
move_popup(event);
filename = element.src;
re = \'/mini\/(foto-[0-9]+\.jpg)$/\';
if (match = filename.match(re)) {
powiekszenie_exif(match[1]);
}
}
Pop-up jest wyświetlany przez funkcję
{stala}move_popup(){/stala}, która odpowiada także za
przesuwanie okna pop-up, tak by podążało
za kursorem.
Krok 4: przesuwanie okna pop-up
Okno pop jest przesuwane funkcją {stala}move_popup(){/stala}.
Odpowiadają za to trzy instrukcje przypisania
zmieniające właściwości: display, left
oraz top:
function move_popup(event) {
if (!event) {
var event = window.event;
}
el = document.getElementById(\'popup\');
el.style.display = \'block\';
el.style.left = event.clientX + document.documentElement.scrollLeft + 10 + \'px\';
el.style.top = event.clientY + document.documentElement.scrollTop + 10 + \'px\';
}
Metoda wyznaczania współrzędnych okna
pop-up pochodzi z artykułu Petera-Paula Kocha
pt. \”Mission Impossible – mouse position\”,
dostępnego w serwisie evolt.org.
Krok 5: ukrywanie okna pop-up
Ukrycie okna pop-up sprowadza się do zmiany
właściwości CSS display. Jest to wykonywane
w funkcji {stala}hide_popup(){/stala}:
function hide_popup() {
e = document.getElementById(\'popup\');
e.style.display = \'none\';
}
Krok 6: wyświetlanie powiększonego obrazu i danych EXIF
W celu wyświetlenia powiększonego obrazu
należy najpierw ustalić nazwę pliku graficznego.
Nazwa dużego zdjęcia jest identyczna
jak nazwa miniaturki (z dokładnością do folderu).
Nazwa pliku miniaturki jest dostępna jako
wartość atrybutu src obiektu, który wygenerował
zdarzenie. Obiekt ten jest przekazywany
jako pierwszy parametr element funkcji show_
popup(element, event). A więc nazwę miniaturki
odczytujemy z element.src:
filename = element.src;
Pobraną nazwę filemane dopasowujemy do
wyrażenia regularnego /mini\\/(foto-[0-9]+\\jpg)$/. Dzięki temu w zmiennej {stala}match[1]{/stala} uzyskamy
{stala}fragment foto-XXX.jpg{/stala} (przechwytywanie w wyrażeniach regularnych). Jeśli to się
powiedzie, wywołujemy funkcję {stala}powiekszenie_exif(){/stala}, przekazując do niej nazwę obrazu
(bez nazwy folderu):
filename = element.src;
re = /mini\/(foto-[0-9]+\.jpg)$/;
if (match = filename.match(re)) {
powiekszenie_exif(match[1]);
}
...