Przybliżanie zdjęć: zoom / lupa do produktów

Jeśli zastanawiałeś się kiedyś jak stworzyć komponent który jest w stanie przybliżać fragment zdjęcia po najechaniu myszką, Twoje poszukiwania dobiegają końca!

Ostatnia aktualizacja: 
JavaScript
17m 40s
5.900+ wyświetleń
144+ pozytywnych reakcji

Prosty zoom w vanilla JS

Po co komu frameworki, gdy przy odrobinie czystego JavaScript jesteśmy w stanie osiągnąć efekt znany z wielu sklepów e-commerce!

Transkrypt wideo

Cześć, w tym wideo pokażę wam jak zrobić lupę do zdjęć
Zaczynajmy
[ intro kodu.je ]
Zapewne na wielu sklepach internetowych spotkaliście się z sytuacją,
gdzie po najechaniu na zdjęcie, otwiera się wam jego przybliżony podgląd
W tym materiale pokażę wam jak w prosty sposób zaimplementować taką funkcjonalność
Zaczniemy od stworzenia diva o klasie "photo"
Reprezentować on będzie nasze zdjęcie,
które będziemy mogli przybliżyć
Wewnątrz niego dynamicznie przy pomocy JSa,
będziemy tworzyli diva
o klasie "magnifier",
który będzie symbolizował nam właśnie lupę,
no i obok samego diva o klasie "photo",
utworzymy sobie nasze przybliżone
zdjęcie
Więc tak będzie wyglądał markup,
część jego będziemy tworzyli dynamicznie, więc nadajmy podstawowe stylowanie
temu naszemu markupowi
Nasz divo klasie "photo" będzie miał
szerokość 400px
oraz wysokość 400px
Ustawimy mu background-image na taki,
jaki chcielibyśmy aby nasze zdjęcie posiadało
'photo.jpg'
oraz ustawimy background-size na 400px
Wypozycjonujemy go relatywnie,
bo to się nam przyda do naszej lupy
i ostylujmy naszego "magnifier"
czyli tak naprawdę tą naszą lupę
Ustawimy żeby miała ona połowę wysokości rodzica,
ustawimy to już w pikselach - niech będzie
Border ustawimy na 1px o kolorze srebrnym,
wypozycjonujemy to absolutnie względem rodzica,
ustawimy początkową pozycję na lewy górny róg,
box-sizing ustawimy na border-box,
tak aby ten border był wliczony w tą szerokość 200px i wysokość
Możemy nadać analogiczny kolor #c9c9c9 jako tło
i zmniejszymy mu trochę opacity, powiedzmy na połowę
Ten element będzie nam się przesuwał w momencie kiedy będziemy przesuwali myszkę
i tak naprawdę kiedy wyjedziemy myszką poza obszar tego zdjęcia,
to on nie będzie widoczny
Ostylujmy jeszcze nasze przybliżone zdjęcie
Również ustawimy mu szerokość na taką samą jak naszemu głównemu zdjęciu czyli 400px,
background-image równiez taki sam,
natomiast background-size ustawimy na 800px
i cała mechanika tego przykładu będzie polegała na tym,
że będziemy przesuwać background-position w momencie,
gdy będziemy ruszali myszką na naszym głównym elemencie "photo"
Ustawimy jeszcze sobie background-repeat na no-repeat
i możemy przejść do pisania logiki naszego programu
Więc na początku pobierzemy sobie to nasze "photo" document.querySelector (.'photo')
Następnie potrzebowalibyśmy zmiennych, w których przechowamy nasze elementy magnifire
Możemy je ustawić domyślnie na null,
no i nasze przybliżone zdjęcie, czyli zoom - również na null
Jak już powiedzieliśmy - chcielibyśmy aby ten magnifire był tworzony w momencie,
kiedy wjedziemy myszką na nasze zdjęcie, więc stwórzmy sobie funkcję createMagnifire
i wewnątrz niej będziemy tworzyli sobie magEl z document.createElement ('div')
Nadamy mu klasę .magnifire
i ustawimy, że nasza globalna zmienna mag,
będzie równa temu magEl
Dodamy sobie jeszcze do naszego 'photo' ten element
Analogicznie powinniśmy stworzyć sobie zmienną usuwającą ten element,
czyli removeMagnifier
i będziemy usuwali z naszego 'photo' removeChild, - ten nasz magElement
Możemy jeszcze sobie to uwarunkować, że jeżeli mag,
to usuńmy oczywiście mag, nie magElement,
ponieważ to była zmienna lokalna, dostępna jedynie w createMagnifier
Więc mając te dwie zmienne możemy przypisać sobie już zdarzenia do naszego  photo.adEventListener
i chcielibyśmy, że w momencie kiedy wjedziemy myszką na nasze 'photo',
to chcielibyśmy aby wywołała się funkcja createMagnifier
Analogicznie na 'mouseleave' wywoła nam się removeMagnifier
'mouseenter' i 'mouseleave' zostanie wywołane tylko 1 raz w momencie wjechania na obszar zdjęcia,
bądź jego opuszczenia
Usuńmy sobie tego diva i zobaczmy czy nasz przykład działa - no działa
Jak widzimy dopóki myszka nie znajduje się na obszarze 'photo',
to tego elementu magnifier nie ma,
natomiast po najechaniu myszką on się tutaj pojawia
Poprawmy tylko tutaj wcięcia w naszym markupie
i przejdźmy do dalszej części przykładu
Chcielibyśmy aby po najechaniu myszką,
w momencie kiedy ruszamy myszką po naszym zdjęciu,
to żeby ten magnifier podążał za tą myszką
Więc stwórzmy sobie zmienną onMouseMove,
to będzie funkcja i przypiszmy ją do zdarzenia 'photo' onMouseMove
Oczywiście te funkcje też możemy sobie przenieść do analogicznych funkcji o nazwach onMouseEnter
oraz onMouseLeave, removeMagnifier i wpisujemy onMouseEnter, onMouseLeave
Dzięki temu gdybyśmy chcieli aby więcej zdarzeń,
czy więcej funkcji wywoływało się w  momencie tego konkretnego zdarzenia,
to będziemy mogli po prostu dopisać je do odpowiednich funkcji onMouseLeave czy onMouseEnter
Więc jak chcemy tak naprawdę przesuwać tego naszego diva magnifier?
Będziemy robili to na podobnej zasadzie co w naszym materiale Sticky Notes -
adnotacja powinna wam wyskoczyć w prawym górnym rogu ekranu,
więc jeśli chcielibyście wiedzieć dokładnie i szczegółowo jak działa fragment kodu,
który za chwile napiszemy - możecie obejrzeć tamto wideo
Na początku pobierzemy sobie bounding naszego zdjęcia,
to będzie po prostu za pomocą thisa getBoundingClientRect
Następnie dodamy sobie tutaj obiekt zdarzenia jako parametr
i zdefiniujemy zmienne X i Y, gdzie X będzie równe ev.clientX odjąć właśnie photoBounding.left,
czyli tak naprawdę pozycję od lewej strony naszego zdjęcia
Obliczamy w tym momencie relatywną pozycję myszki względem naszego 'photo'
Analogicznie utworzymy sobie zmienną Y ev.clientY minus photoBounding.top,
Zapiszemy sobie również photoSize,
wykorzystamy do tego window.getComputedStyle
i podamy jako parametr właśnie nasze 'photo',
moglibyśmy tutaj też wykorzystać naszą zmienną 'photo',
odwołamy się do parametru height
i to nam zwróci sumaryczną wartość faktyczną w przeglądarce tego elementu,
jaką on ma wysokość, natomiast będzie to wartość w pikselach,
dlatego wykorzystamy sobie do tego parseInt aby przekonwertować sobie to na inta,
na liczbę całkowitą
Analogicznie pobierzemy sobie magSize,
mag - tak naprawdę moglibyśmy tutaj dać warunek,
aby sprawdzać czy ten mag na pewno istnieje,
natomiast zdarzenie mouseEnter wywoła się pierwsze niż mouseMove,
więc w sumie moglibyśmy to pominąć
Sam element magnifier będziemy przesuwali za pomocą translate'ów,
więc tworzymy sobie transformCSSValues
i chcielibyśmy aby w osi Y nasz div został przesunięty w momencie ruszania myszką o wartość X -
oczywiście będziemy musieli jeszcze parę rzeczy tutaj ustawić,
no i aby w osi Y przesunęło się o wartość Y pikseli
To będziemy przypisywali do naszego mag,
ustawiali transform na właśnie transformCSSValues
No i jak widzimy, nasz magnifier ma swoją pozycję startową w tamtym miejscu,
gdzie mamy kursor
My docelowo chcielibyśmy aby ten kursor znajdował się możliwie jak najbardziej na środku tej lupy,
więc musimy zrobić troszkę obliczeń
Jako, że znamy szerokość i wysokość naszego obiektu magnifier
(zakładamy oczywiście, że one są równe)
możemy tę naszą wartość X, Y pomniejszyć o połowę wielkości tego elementu,
dzięki temu pozycja naszego obiektu (w momencie przesuwania myszką) będzie na środku
No oczywiście w momencie kiedy zbliżymy się za bardzo do krawędzi,
to niestety ten nasz obiekt magnifier - on nam wychodzi poza to nasze zdjęcie,
więc chcielibyśmy zrobić, że jeżeli zbliżamy się już do krawędzi,
to myszka może się ruszać dalej w kierunku krawędzi,
natomiast sam obiekt magnifier zostanie w tej samej pozycji
Tutaj musimy zrobić kilka warunków,
czyli sprawdźmy sobie najpierw czy X wyszedł poza zakres
Dodamy sobie całą szerokość obiektu magnifier
i sprawdzimy czy jest większa od całego photoSize -
jeśli tak, to chcielibyśmy aby X równało się photoSize minus magSize,
czyli było najbardziej jak to możliwe przesunięte w tej osi do krawędzi
Zobaczmy efekt - jak widzimy, gdy zbliżamy się do prawej krawędzi,
to już poza nią nie wyjdziemy
No i oczywiście w momencie, gdy opuścimy nasze 'photo',
to ten element nam zniknie,
więc tak naprawdę musimy jeszcze zrobić tylko analogiczne warunki dla pozostałych krawędzi
i poruszanie naszą lupą będzie zakończone
To photoSize i magSize możemy sobie zamknąć w zmiennej, bo to się nam przyda
Nazwijmy to sobie MAX_POSITION np.
No i chcielibyśmy aby X równa się MAX_POSITION,
jeśli Y plus magSize jest większy niż photoSize,
to Y równa się MAX_POSITION,
no i jeśli X jest mniejsze od zera,
czyli tak naprawdę z lewej strony wychodzi nam poza zakres,
to chcielibyśmy je po prostu wyzerować analogicznie wyzerujemy też wartość Y
Zobaczmy efekt - no jak widzimy, przy poruszaniu naszą myszką po tym obszarze,
nie możemy już wysunąć tego obiektu poza nasze 'photo'
No oczywiście nasza lupę możemy już poruszać, natomiast zdjęcie po prawej,
które jest tym przybliżonym zdjęciem, ono się nam nie przesuwa analogicznie do tego,
gdzie wskazujemy naszym kursorem
Więc zanim dopiszemy tutaj sobie odpowiedni fragment kodu,
aby to zrealizować, to może sprawmy aby ten podgląd przybliżony był widoczny tylko w momencie,
kiedy najechaliśmy na nasze zdjęcie,
więc usuniemy sobie z naszego markupu naszego diva o klasie "zoom"
i stworzymy sobie funkcję createZoomedPhoto np.
Ustawimy, że wyżej zdefiniowany zoom to będzie nowy div o klasie zoom
i dodamy go sobie od razu do naszego body
Analogicznie stworzymy sobie var removeZoomedPhoto,
to będzie funkcja i sprawdzamy - jeśli zoom,
to document.body.removeChild(zoom),
no i wyzerujmy sobie tego zoom do nulla
Tutaj też oczywiście musimy sobie nasze mag wyzerować do nulla
Tak naprawdę te createZoomedPhoto i removeZoomedPhoto,
możemy dodać oczywiście do naszych funkcji mouseEnter i mouseLeave -
createZoomedPhoto oraz removeZoomedPhoto
No i zapisujemy, zobaczmy co się stanie,
kiedy poruszamy się po naszym zdjęciu, to jego przybliżony ekwiwalent też jest już widoczny,
więc pozostało nam tylko zmieniać background position na naszym przybliżonym zdjęciu,
w zależności od tego gdzie znajdujemy się myszką na naszym głównym divie 'photo'
Więc w naszym onMouseMove damy sobie taką linijkę,
że zoom.style.backgroundPosition
i tutaj podamy sobie X pomnożonego razy 2,
jako że nasz backgroundSize jest większy na tym elemencie dwukrotnie,
czyli tak naprawdę mamy skalę 2 w stosunku do naszego oryginalnego 'photo'
No i oczywiście dopisujemy pikseli oraz Y razy 2px
No oczywiście musimy sobie tu wstawić spację,
ponieważ tutaj załóżmy, że byłoby 100px aby wskazać pozycję Y,
to musimy podać spację i dopiero kolejne  - załóżmy 100px
Zapisujemy, sprawdzamy, no i jak widzimy - to nie do końca działa tak jakbyśmy się tego spodziewali,
ponieważ background position ma w pewnym sensie odwróconą oś,
można powiedzieć - musimy po prostu wstawić sobie tutaj minusiki
i jak widzimy, nasze zdjęcie przybliża się tam, gdzie poruszamy naszą myszką
Możemy jeszcze szybciutko dodać na naszym 'photo' jakiś margin-right,
załóżmy 20px i jak widzimy, możemy sobie przybliżać nasze zdjęcia
To jest zdjęcie Damiana z tegorocznych Warszawskich Dni Informatyki,
dajcie znać czy byliście na tym wydarzeniu i jak widzimy -
stworzenie takiego przykładu jest koncepcyjnie bardzo proste,
nie wymaga też wiele wysiłku, jeśli chodzi o implementację,
oczywiście ten przykład moglibyśmy dalej rozszerzać, np. dodając możliwość podglądania innych zdjęć,
czy tak naprawdę sprawianie, aby ten kod był bardziej uniwersalny
Jeżeli będziecie zainteresowani takim zagadnieniem, koniecznie dajcie nam znać w komentarzu
Jeszcze jedna ważna informacja
Niedawno ruszyliśmy ze sklepem internetowym, gdzie możecie zakupić przeprowadzone przez nas Webinary
Możecie odwiedzić go klikając w odnośnik widoczny po lewej stronie ekranu
Trzymajcie się i do zobaczenia wkrótce
[ blooper ]

Kliknij by pominąć tę sekcję

Wsparcie Element API według CanIUSE

No cóż... można powiedzieć, że było to od zawsze :) 

Data on support for the mdn-api__Element feature across the major browsers

Zobacz kod źródłowy

Nie mam nic do ukrycia! Eksperymentuj z moimi przykładami :) 

16 kwietnia 2022

Komentarz od autora

Myślę, że dalej jest to solidny materiał - pomimo tego, że unikałem wtedy ES6 (aby nie wdrażać "nowości" i skupić się na przykładzie), jednak umówmy się - jest już 2022 i ES6+ to w dzisiejszych czasach - po prostu JavaScript, wspierany we wszystkich istotnych przeglądarkach.

Gdybym robił ten materiał dzisiaj, zdecydowanie korzystałbym z dobrodziejstw nowej składni języka - template strings, let / const, arrow functions... Czy chociażby deklarowanie zmiennych na osobnych liniach - bez wymieniania ich po przecinku.

Poznaj Wojtka

Cześć! Nazywam się Wojciech Połowniak i jestem programistą Fullstack z zacięciem do tworzenia jakościowych materiałów szkoleniowych.

Uwielbiam automatyzację, VR oraz interaktywne sposoby przekazywania wiedzy. Tematy takie jak UX, dostępność czy devops również nie są mi obce.

Jestem też organizatorem meet.js oraz Techspeakerem pod banderą Mozilli... A to jeszcze nie wszystko.

Chcesz więcej?

Nie ma sprawy! Koduje to długie godziny darmowej treści dostępnej na wyciągnięcie ręki.

Newsletter

Jeśli chcesz być na bieżąco z najnowszymi inicjatywami od twórców koduje? Zapisz się na newsletter - nie spamujemy!

Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

W przyszłości, możemy udostępnić Ci informacje o dodatkowych kursach naszego autorstwa.

Najczęściej zadawane pytania

Jaka tematyka jest poruszana na Koduje?
expand_more
Mówimy o HTML, CSS i JavaScript - zarówno na backendzie, jak i frontendzie. Tematyka taka jak Devops, architektura i infrastruktura oprogramowania również pojawią się na kanale!
Czy mogę zaproponować temat kolejnych wideo?
expand_more
Oczywiście, że tak! Najlepiej sugerować materiały w sekcji komentarzy na YouTube 
Jak to możliwe, że Koduje jest darmowe? 
expand_more
Moją pasją jest dzielenie się wiedzą w sposób zrozumiały i klarowny, jednocześnie interaktwny i angażujący. Tworząc materiały, utrwalam też własną wiedzę. Wierzę, że za to widzowie nie powinni płacić
W sieci można znaleźć strony przypominające do koduje.pl, o co chodzi?
expand_more
Niestety, na przełomie lat wiele osób próbowało podszyć się pod Koduje i wykorzystać nasze materiały do promocji własnych kanałów dystrybucyjnych.  Jeśli masz wątpliwości, czy dana strona współpracuje z Koduje - daj nam o tym znać. Nie pochwalamy piractwa, plagiatu ani szarej strefy prawa autorskiego.
Czy prowadzicie szkolenia indywidualne?
expand_more
W chwili obecnej, niestety nie. Na przełomie lat prowadziłem kursantów przez ich przygodę z programowaniem, z czego każdy otrzymał pracę jako programista. Jeśli jesteś zainteresowany lekcjami indywidualnymi, zapraszam do kontaktu mailowego.
Czy oferujecie płatne kursy?
expand_more
W przyszłości nie wykluczamy możliwości tworzenia dedykowanych kursów o danych zagadnieniach. Zapisz się na nasz newsletter, aby być na bieżąco z naszymi najnowszymi płatnymi materiałami.
Jak mogę się z wami skontaktować?
expand_more
Czytamy komentarze na YouTube! Śmiało możesz zadać pytanie na dowolny temat pod którymkolwiek z naszych wideo. Poza tym możesz skontaktować się z nami mailowo bądź poprzez fanpage na Facebooku
Obecnym właścicielem marki jest Wojciech Połowniak. Zobacz zakładkę o nas!