Grafika na stronie
Możesz też skorzystać z licznych czyścicieli. Wystarczy w internecie poszukać frazy "exif remove".
Przypuśćmy, że mamy obrazek img na stronie:
<img src="./wietnam.jpg" class="img" alt="Kartofel w wietnamie" width="353" height="367">
Żeby móc na nim pracować, pobierzmy go i zbadajmy w konsoli (zrób to teraz):
const img = document.querySelector(".img");
console.dir(img);
Podobnie jak inne elementy i nasza grafika udostępnia nam masę metod i właściwości, które będą nam pomocne.
Wśród nich jednymi z najczęściej używanymi są:
width | szerokość grafiki, |
---|---|
height | wysokość grafiki, |
alt | alternatywny opis grafiki (widoczny gdy się nie wczyta), |
title | tekst, który pojawi się po najechaniu kursorem na element, |
src | adres do grafiki |
const obr = document.querySelector(".img");
console.log(`Szerokość: ${img.width}, wysokość: ${img.height}, src: ${img.src}`);
Konstruktor Image()
W Javascript obrazki możemy tworzyć na kilka sposobów. Można tutaj wykorzystać np. document.createElement("img")
, ale też możemy skorzystać z konstruktora Image()
. Przyjmuje on dwa opcjonalne parametry określające szerokość i wysokość.
const img = new Image();
img.src = "test.jpg";
//lub
const img = document.createElement("img");
img.src = "test.jpg";
Stworzona w ten sposób grafika jest ściągana na urządzenie użytkownika, co bardzo przydaje się w momencie, gdy chcemy zawczasu wczytać daną grafikę.
Zdarzenie load
Obiekty wczytywane (np. window, image, iframe itp.) posiadają zdarzenie load, które wykrywa, czy dany obiekt został w pełni załadowany.
Dla obiektu window zdarzenie to oznacza wczytanie całego dokument dom oraz wszystkich grafik (w przeciwieństwie do DOMContentLoaded, które odpalane jest po wczytaniu drzewa DOM, ale przed wczytaniem grafik).
Dla grafiki oznacza to wczytanie danej grafiki:
img.addEventListener("load", e => {
console.log("Dana grafika została załadowana");
});
img.src = "lorem.jpg"; //wpierw ustawiamy zdarzenie, potem ustawiamy src
Jeżeli w powyższym skrypcie zdarzenie load ustawilibyśmy po ustawieniu src, skrypt mógł by zadziałać nieprawidłowo. Może zdarzyć się sytuacja, że obrazek wczyta się natychmiastowo po ustawieniu src (np. siedzi już w cache przeglądarki). Oznacza to, że obrazek wczyta się przed odpaleniem nasłuchiwania zdarzenia load.
Są jednak sytuacje (szczególnie przy bardziej skomplikowanych systemach), że nie jesteśmy w stanie zagwarantować takiej kolejności. Przykładowo system pobiera sobie src grafik, a podpięcie zdarzeń następuje dopiero później. W takim przypadku warto sprawdzić właściwość complete każdej grafiki, która wskazuje czy dany obrazek jest wczytany czy nie. Jeżeli tak się stanie odpalimy dla niej zdarzenie load.
img.src = "lorem.jpg";
img.addEventListener("load", e => {
console.log("Dana grafika została załadowana");
});
if (img.complete) {
const loadEvent = new Event("load");
img.dispatchEvent(loadEvent);
}
Postęp wczytywania grafik na stronie
Wyobraź sobie, że naszym zadaniem będzie zrobienie paska ładowania grafik użytych na stronie.
Aby to zrealizować, zacznijmy od przygotowania elementu z paskiem postępu:
.loading-bar {
margin: 30px 0;
height: 10px;
border-radius: 10px;
background: #eee;
display: flex;
overflow:hidden;
}
.loading-bar__progress {
background: tomato;
}
<div id="loading-bar">
<div class="loading-bar__progress"></div>
</div>
Sam skrypt będzie raczej prosty. Tworzymy tablicę ze ścieżkami do grafik oraz pustą tablicę, do której będziemy wrzucać obiekty typu Images, które będą miały ustawione src takie jak poszczególne elementy w tablicy.
//tablica z nazwami obrazków do załadowania
const imgNames = [
"obrazek1.gif",
"obrazek2.gif",
"obrazek3.gif",
"obrazek4.gif",
"obrazek5.gif",
"obrazek6.gif"
];
const loadingStep = (100 / imgNames.length); //szerokość oznaczająca % paska po załadowaniu 1 obrazka
const images = []; //tablica będzie zawierała obiekty Image
const loading = document.querySelector(".loading");
const loadingBar = loading.querySelector(".loading-progress");
//funkcja rozpoczynająca ładowanie obrazków
function startLoading(cb) {
imgNames.forEach(name => {
const img = new Image();
//po wczytaniu grafiki wrzucam nowe Image() do tablicy images
//sprawdzam ile elementów ma ta tablica i na tej podstawie ustawiam szerokość paska postępu
img.addEventListener("load", e => {
images.push(img);
loadingBar.style.width = `${images.length * loadingStep}%`; //zmieniamy szerokość paska w %
if (images.length >= imgNames.length) {
cb(); //odpalam jakąś funkcję po zakończeniu wczytywania
}
});
img.src = name;
if (img.complete) {
img.dispatchEvent(new Event("load"));
}
});
}
startLoading(function() {
alert("Zakończono wczytywanie")
});
Powyższy przykład możesz zobaczyć w działaniu tutaj.
Jak zauważysz, takie wczytywanie działa "skokowo" ponieważ zmianę paska dokonujemy dopiero po wczytaniu danej grafiki. Przy dużej liczbie małych grafik nie powinno to być problemem, ale co jeżeli wczytujemy bardzo duże grafiki? W tym repozytorium znajdziesz moją małą próbę rozwiązania tego problemu. Polecam przetestować przy ograniczeniu szybkości łącza w zakładce Network debuggera.
Lazy loading
Lazy loading to metoda wczytywania obrazków polegająca na tym, że dany obrazek wczytywany jest dopiero w momencie gdy pojawi się na ekranie.
W nowych przeglądarkach wczytywanie takie możemy uzyskać za pomocą dodatkowego atrybutu lazy dla elementów img:
<img src="image.png" loading="lazy" alt="...">
<iframe src="https://example.com" loading="lazy"></iframe>
Atrybut ten może przyjąć jedną z wartości:
auto | domyślna wartość dla leniwego wczytywania. Równa temu, jakbyśmy w ogóle tego atrybutu nie używali. |
---|---|
lazy | opóźnione wczytywanie grafiki gdy osiągnie ona wskazany dystans od ekranu (zależy od typu zasobów, szybkości łącza itp.) |
eager | zdjęcie ma być wczytywane natychmiast po wejściu na stronę |
W przypadku, gdy dana przeglądarka nie obsługuje powyższego atrybutu, możemy skorzystać z kilku metod naprawy tego stanu.
Pierwszą z nich jest użycie tak zwane IntersectObserver, który nasłuchuje, czy dane elementy znalazły się w zadanym obszarze.
Drugą jest użycie jednego z zdarzeń resize, scroll i ewentualnie orientationchange.
Nie będę tutaj duplikował czyjegoś kodu i zwyczajnie odeślę was pod ten adres, gdzie został pokazany stosowny kod.