Klocki LEGO® na stronach internetowych na wiele urządzeń
Build with Chrome to zabawny eksperyment dla użytkowników Chrome na komputerach stacjonarnych, który został pierwotnie wprowadzony w Australii. W 2014 r. został on ponownie wydany na całym świecie, w ramach współpracy z filmem THE LEGO® MOVIE™, a także z dodatkowym wsparciem dla urządzeń mobilnych. W tym artykule omówimy wnioski z tego projektu, zwłaszcza dotyczące przejścia z rozwiązania przeznaczonego tylko do komputerów na rozwiązanie wieloekranowe, które obsługuje zarówno mysz, jak i wejście dotykowe.
Historia kompilacji w Chrome
Pierwsza wersja programu Build with Chrome została wprowadzona w Australii w 2012 r. Chcieliśmy pokazać potęgę internetu w zupełnie nowy sposób i zaprezentować Chrome zupełnie nowej grupie odbiorców.
Strona składała się z 2 głównych części: trybu „Budowanie”, w którym użytkownicy mogą budować konstrukcje z klocków LEGO, oraz trybu „Odkrywanie”, w którym mogą przeglądać konstrukcje w wersji LEGO Map Google.
Interaktywne modele 3D były niezbędne, aby zapewnić użytkownikom najlepsze wrażenia podczas budowania z klocków LEGO. W 2012 r. WebGL był publicznie dostępny tylko w przeglądarkach na komputery, więc Build był przeznaczony tylko na komputery. W przypadku funkcji Explore do wyświetlania kreacji używane są Mapy Google, ale po zbliżeniu mapy do wystarczającego poziomu włącza się implementacja mapy w technologii WebGL, która pokazuje kreacje w 3D, ale nadal wykorzystuje mapy Google jako teksturę podstawową. Chcieliśmy stworzyć środowisko, w którym pasjonaci LEGO w każdym wieku mogliby łatwo i intuicyjnie wyrażać swoją kreatywność oraz poznawać projekty innych użytkowników.
W 2013 roku postanowiliśmy rozszerzyć Build with Chrome o nowe technologie internetowe. Jedną z nich był WebGL w Chrome na Androida, który pozwalał na ewolucję funkcji Tworzenie w Chrome w wersję mobilną. Na początek opracowaliśmy prototypy dotykowe, a potem przetestowaliśmy sprzęt w „Narzędziu konstruktora”, aby poznać zachowanie gestów i reakcje dotykowe, z którymi możemy się spotkać w przeglądarce w porównaniu z aplikacją mobilną.
Elastyczny interfejs
Musieliśmy zapewnić obsługę urządzeń z klawiaturą dotykowego i myszką. Jednak używanie tego samego interfejsu na małych ekranach dotykowych okazało się nieoptymalnym rozwiązaniem ze względu na ograniczoną ilość miejsca.
W budowaniu jest wiele interakcji: powiększanie i pomniejszanie, zmiana kolorów klocków i oczywiście wybieranie, obracanie i umieszczanie klocków. Jest to narzędzie, z którego użytkownicy często korzystają, dlatego ważne jest, aby mieli szybki dostęp do wszystkich często używanych funkcji i by mogli wygodnie z nich korzystać.
Podczas projektowania bardzo interaktywnej aplikacji dotykowej szybko zauważysz, że ekran wydaje się mały, a palce użytkownika zajmują sporą jego część. Stało się to dla nas oczywiste, gdy pracowaliśmy z Kreatorem. Podczas projektowania należy wziąć pod uwagę fizyczny rozmiar ekranu, a nie piksele w grafice. Ważne jest, aby zminimalizować liczbę przycisków i elementów sterujących, aby jak najwięcej miejsca na ekranie przeznaczyć na rzeczywiste treści.
Naszym celem było uczynienie Build naturalnym na urządzeniach dotykowych. Nie tylko dodaliśmy obsługę dotykiem do pierwotnej implementacji na komputery, ale sprawiliśmy, że wygląda ona tak, jakby była przeznaczona do urządzeń dotykowych. W efekcie powstały 2 wariacje interfejsu: jedna dla komputerów i tabletów z dużymi ekranami oraz druga dla urządzeń mobilnych z mniejszymi ekranami. Jeśli to możliwe, najlepiej użyć jednej implementacji i płynnie przechodzić między trybami. W naszym przypadku stwierdziliśmy, że różnica w doświadczeniu między tymi dwoma trybami była tak znacząca, że zdecydowaliśmy się polegać na określonym punkcie przełamania. Obie wersje mają wiele wspólnych funkcji i staraliśmy się, aby większość z nich działała na podstawie jednego kodu, ale niektóre aspekty interfejsu różnią się w zależności od wersji.
Dane użytkownika służą do wykrywania urządzeń mobilnych, a następnie sprawdzamy rozmiar widoku, aby zdecydować, czy należy użyć interfejsu na małym ekranie. Trudno jest wybrać punkt przełamania dla „dużego ekranu”, ponieważ trudno jest uzyskać wiarygodną wartość fizycznego rozmiaru ekranu. Na szczęście w naszym przypadku nie ma większego znaczenia, czy wyświetlamy interfejs na małym ekranie czy na urządzeniu dotykowym z dużym ekranem, ponieważ narzędzie będzie działać prawidłowo, choć niektóre przyciski mogą być nieco za duże. Ostatecznie ustawiliśmy punkt przecięcia na 1000 pikseli. Jeśli wczytasz witrynę z poziomu okna szerszego niż 1000 pikseli (w układzie poziomym), zobaczysz wersję na duży ekran.
Porozmawiajmy teraz o 2 rozmiarach ekranu i doświadczeniach:
duży ekran z obsługą myszy i dotyku;
Wersja na duży ekran jest wyświetlana na wszystkich komputerach z myszką i na urządzeniach dotykowych z dużymi ekranami (np. Google Nexus 10). Ta wersja jest zbliżona do oryginalnego rozwiązania na komputery pod względem dostępnych elementów sterujących, ale dodaliśmy obsługę dotykiem i niektóre gesty. Dostosowujemy interfejs użytkownika w zależności od rozmiaru okna, więc gdy użytkownik zmieni rozmiar okna, może to spowodować usunięcie lub zmianę rozmiaru części interfejsu. Wykorzystujemy do tego zapytania o multimedia w CSS.
Przykład: gdy dostępna wysokość jest mniejsza niż 730 pikseli, suwak powiększenia w trybie Eksplorowanie jest ukryty:
@media only screen and (max-height: 730px) {
.zoom-slider {
display: none;
}
}
Mały ekran, obsługa tylko dotykiem
Ta wersja jest wyświetlana na urządzeniach mobilnych i małych tabletach (urządzenia docelowe: Nexus 4 i Nexus 7). Ta wersja wymaga obsługi wielodotykowej.
Na urządzeniach z małym ekranem musimy zapewnić treściom jak najwięcej miejsca na ekranie, więc wprowadziliśmy kilka zmian, aby zmaksymalizować przestrzeń, głównie poprzez ukrycie elementów, których użytkownicy rzadko używają:
- Podczas budowania selektor klocków w budowaniu minimalizuje się do selektora kolorów.
- Zastąpiliśmy sterowanie powiększeniem i orientacją gestami wielodotykowymi.
- Funkcja pełnego ekranu w Chrome również pomaga w wykorzystaniu dodatkowej przestrzeni na ekranie.


Wydajność i obsługa WebGL
Nowoczesne urządzenia dotykowe mają dość wydajne procesory graficzne, ale wciąż nie są tak mocne jak ich odpowiedniki na komputerach. Wiedzieliśmy więc, że będziemy mieć pewne problemy z wydajnością, zwłaszcza w trybie Odkrywaj w 3D, w którym musimy renderować wiele kreacji jednocześnie.
Chcieliśmy też dodać kilka nowych rodzajów klocków o skomplikowanych kształtach i przezroczystości – funkcje, które zwykle bardzo obciążają procesor graficzny. Musieliśmy jednak zachować zgodność wsteczną i nadal obsługiwać kreacje z pierwszej wersji, więc nie mogliśmy nałożyć żadnych nowych ograniczeń, takich jak znaczne zmniejszenie łącznej liczby klocków w kreacji.
W pierwszej wersji aplikacji Build istniał limit liczby klocków, które można było użyć w jednym projekcie. Było tam „pełne” oznaczenie, ile cegieł zostało. W ramach nowej implementacji niektóre nowe cegły miały wpływać na licznik cegieł bardziej niż cegły standardowe, co spowodowało nieznaczne zmniejszenie łącznej maksymalnej liczby cegieł. Był to jeden ze sposobów na dodanie nowych elementów przy zachowaniu przyzwoitej wydajności.
W trybie eksploracji 3D wiele rzeczy dzieje się jednocześnie: wczytywanie tekstur podstawy, wczytywanie kreacji, animowanie i renderowanie kreacji itd. Wymaga to dużej mocy zarówno procesora graficznego, jak i procesora. Dlatego w Chrome DevTools przeprowadziliśmy wiele profilowania klatek, aby zoptymalizować te elementy w jak największym stopniu. Na urządzeniach mobilnych postanowiliśmy nieco przybliżyć kreacje, aby nie trzeba było renderować tak wielu z nich jednocześnie.
W przypadku niektórych urządzeń musieliśmy ponownie przejrzeć i uprościć niektóre shadery WebGL, ale zawsze znajdowaliśmy sposób na rozwiązanie problemu i dalsze działanie.
Obsługa urządzeń bez obsługi WebGL
Chcieliśmy, aby witryna była w jakimś stopniu użyteczna nawet wtedy, gdy urządzenie użytkownika nie obsługuje WebGL. Czasami można uprościć wyświetlanie obiektów 3D, korzystając z rozwiązania canvas lub funkcji CSS3D. Niestety nie znaleźliśmy wystarczająco dobrego rozwiązania, które pozwoliłoby odtworzyć funkcje tworzenia i eksplorowania modeli 3D bez użycia WebGL.
Ze względu na spójność styl wizualny kreacji musi być taki sam na wszystkich platformach. Mogliśmy spróbować użyć rozwiązania 2,5D, ale wtedy kreacje wyglądałyby nieco inaczej. Musieliśmy też zastanowić się, jak zapewnić, aby projekty utworzone za pomocą pierwszej wersji Build with Chrome wyglądały tak samo i działały tak samo płynnie w nowej wersji witryny jak w pierwszej.
Tryb 2D jest nadal dostępny na urządzeniach, które nie obsługują WebGL, ale nie można tworzyć nowych kreacji ani eksplorować w trybie 3D. Użytkownicy mogą jednak zobaczyć, jak rozbudowany jest projekt i co mogą stworzyć za pomocą tego narzędzia, gdyby mieli urządzenie z obsługą WebGL. Witryna może nie być tak wartościowa dla użytkowników bez obsługi WebGL, ale powinna przynajmniej pełnić funkcję teasera i zachęcać do wypróbowania.
Przechowywanie wersji zastępczych dla rozwiązań WebGL jest czasami po prostu niemożliwe. Jest wiele możliwych powodów: wydajność, styl wizualny, koszty rozwoju i utrzymania itp. Jeśli jednak zdecydujesz się nie stosować rozwiązania zastępczego, musisz przynajmniej zadbać o użytkowników, którzy nie mają obsługi WebGL. Wyjaśnij im, dlaczego nie mogą w pełni korzystać z witryny, i podaj instrukcje, jak rozwiązać ten problem za pomocą przeglądarki obsługującej WebGL.
Zarządzanie komponentami
W 2013 r. wprowadziliśmy nową wersję Map Google, w której wprowadzono najważniejsze zmiany w interfejsie od czasu ich premiery. Dlatego postanowiliśmy zmienić wygląd aplikacji Build with Chrome, aby pasował do nowego interfejsu Map Google. Podczas projektowania wzięliśmy pod uwagę inne czynniki. Nowy design jest stosunkowo płaski, z czystymi, jednolitymi kolorami i prostymi kształtami. Dzięki temu mogliśmy użyć czystego CSS-u w wielu elementach interfejsu, minimalizując użycie obrazów.
W sekcji Odkrywaj musimy wczytać wiele obrazów: miniatury kreacji, tekstury map dla podstaw i wreszcie same kreacje 3D. Dokładamy wszelkich starań, aby nie dochodziło do wycieku pamięci podczas ciągłego wczytywania nowych obrazów.
Elementy 3D są przechowywane w niestandardowym formacie pliku zapakowanym jako obraz PNG. Przechowywanie danych dotyczących kreacji 3D w postaci obrazu umożliwiło nam przekazywanie tych danych bezpośrednio do shaderów renderujących kreacje.
Dzięki temu, że wszystkie zdjęcia użytkowników są w tym samym formacie, mogliśmy użyć tych samych rozmiarów na wszystkich platformach, co pozwoliło nam zminimalizować wykorzystanie miejsca na dane i przepustowości.
Zarządzanie orientacją ekranu
Łatwo zapomnieć, jak bardzo zmienia się format obrazu podczas przełączania się z orientacji pionowej na poziomą i odwrotnie. Należy wziąć to pod uwagę już na etapie dostosowywania aplikacji do urządzeń mobilnych.
W tradycyjnej witrynie z włączonym przewijaniem możesz zastosować reguły CSS, aby uzyskać responsywną witrynę, która ponownie układa treści i menu. Jeśli możesz korzystać z funkcji przewijania, nie powinno to stanowić problemu.
Używaliśmy tej metody również w przypadku Build, ale mieliśmy pewne ograniczenia w sposobie rozwiązywania problemów z układem, ponieważ treści musiały być widoczne przez cały czas, a jednocześnie chcieliśmy zachować szybki dostęp do wielu elementów sterujących i przycisków. W przypadku stron z treściami, np. witryn z wiadomościami, płynny układ ma sens, ale w przypadku aplikacji z grami, takiej jak nasza, było to trudne. Wyzwaniem było znalezienie układu, który działałby zarówno w orientacji poziomej, jak i pionowej, a jednocześnie zapewniał dobry przegląd treści i wygodne interakcje. Ostatecznie zdecydowaliśmy się zachować tryb poziomy tylko w przypadku tworzenia, a użytkownikowi prosimy o obrócenie urządzenia.
Zadanie Explore było znacznie łatwiejsze do rozwiązania w obu orientacjach. Aby uzyskać spójne wrażenia, musieliśmy dostosować poziom powiększenia obrazu 3D w zależności od orientacji.
Większość układu treści jest kontrolowana przez CSS, ale niektóre elementy związane z orientacją trzeba było zaimplementować w JavaScript. Okazało się, że nie ma dobrego rozwiązania umożliwiającego identyfikację orientacji na różnych urządzeniach za pomocą window.orientation, więc ostatecznie po prostu porównywaliśmy window.innerWidth i window.innerHeight, aby określić orientację urządzenia.
if( window.innerWidth > window.innerHeight ){
//landscape
} else {
//portrait
}
Dodawanie obsługi dotyku
Dodanie obsługi dotykowej do treści internetowych jest dość proste. Podstawowa interaktywność, np. zdarzenie kliknięcia, działa tak samo na komputerach i urządzeniach z ekranem dotykowym, ale w przypadku bardziej zaawansowanych interakcji musisz też obsługiwać zdarzenia dotykowe: touchstart, touchmove i touchend. Z tego artykułu dowiesz się, jak korzystać z tych zdarzeń. Internet Explorer nie obsługuje zdarzeń dotyku, ale zamiast tego używa zdarzeń wskaźnika (pointerdown, pointermove, pointerup). Zdarzenia wskaźnika zostały przesłane do W3C w celu ustandaryzowania, ale na razie są stosowane tylko w Internet Explorerze.
W trybie eksploracji w 3D chcieliśmy zachować tę samą nawigację co w standardowej wersji Map Google: przesuwanie po mapie jednym palcem i powiększanie za pomocą 2 palców. Ponieważ kreacje są w 3D, dodaliśmy też gest obracania dwoma palcami. Zazwyczaj wymaga to użycia zdarzeń dotykowych.
Dobrą praktyką jest unikanie intensywnych obliczeń, takich jak aktualizowanie lub renderowanie modelu 3D w obsługach zdarzeń. Zamiast tego przechowuj dane dotykowe w zmiennej i reaguj na nie w pętli renderowania requestAnimationFrame. Dzięki temu łatwiej jest też zaimplementować mysz, ponieważ odpowiednie wartości myszy są przechowywane w tych samych zmiennych.
Zacznij od zainicjowania obiektu do przechowywania danych wejściowych i dodaj detektor zdarzenia dotknięcie. W każdym obiekcie event handler wywołujemy funkcję event.preventDefault(). Ma to zapobiec dalszemu przetwarzaniu zdarzenia dotykowego przez przeglądarkę, co mogłoby spowodować nieoczekiwane działanie, takie jak przewijanie lub skalowanie całej strony.
var input = {dragStartX:0, dragStartY:0, dragX:0, dragY:0, dragDX:0, dragDY:0, dragging:false};
plateContainer.addEventListener('touchstart', onTouchStart);
function onTouchStart(event) {
event.preventDefault();
if( event.touches.length === 1){
handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
//start listening to all needed touchevents to implement the dragging
document.addEventListener('touchmove', onTouchMove);
document.addEventListener('touchend', onTouchEnd);
document.addEventListener('touchcancel', onTouchEnd);
}
}
function onTouchMove(event) {
event.preventDefault();
if( event.touches.length === 1){
handleDragging(event.touches[0].clientX, event.touches[0].clientY);
}
}
function onTouchEnd(event) {
event.preventDefault();
if( event.touches.length === 0){
handleDragStop();
//remove all eventlisteners but touchstart to minimize number of eventlisteners
document.removeEventListener('touchmove', onTouchMove);
document.removeEventListener('touchend', onTouchEnd);
//also listen to touchcancel event to avoid unexpected behavior when switching tabs and some other situations
document.removeEventListener('touchcancel', onTouchEnd);
}
}
Rzeczywiste przechowywanie danych wejściowych nie odbywa się w obsługach zdarzeń, lecz w osobnych obsługach: handleDragStart, handleDragging i handleDragStop. Chcemy, aby można było wywoływać te metody również z modułów obsługi zdarzeń myszy. Pamiętaj, że chociaż jest to mało prawdopodobne, użytkownik może jednocześnie używać ekranu dotykowego i myszy. Zamiast zajmować się bezpośrednio tym zgłoszeniem, sprawdzamy, czy nic się nie dzieje.
function handleDragStart(x ,y ){
input.dragging = true;
input.dragStartX = input.dragX = x;
input.dragStartY = input.dragY = y;
}
function handleDragging(x ,y ){
if(input.dragging) {
input.dragDX = x - input.dragX;
input.dragDY = y - input.dragY;
input.dragX = x;
input.dragY = y;
}
}
function handleDragStop(){
if(input.dragging) {
input.dragging = false;
input.dragDX = 0;
input.dragDY = 0;
}
}
Podczas tworzenia animacji opartych na zdarzeniu touchmove często warto przechowywać także wartość delta od ostatniego zdarzenia. Użyliśmy go na przykład jako parametru prędkości kamery podczas przemieszczania się po wszystkich płytach bazowych w sekcji Odkrywaj, ponieważ nie przeciągasz płyt, tylko poruszasz kamerą.
function onAnimationFrame() {
requestAnimationFrame( onAnimationFrame );
//execute animation based on input.dragDX, input.dragDY, input.dragX or input.dragY
/*
/
*/
//because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
input.dragDX=0;
input.dragDY=0;
}
Przykład w ramach wbudowanego przykładu: przeciąganie obiektu za pomocą zdarzeń dotykowych. Implementacja podobna do przeciągania mapy 3D w Build with Chrome: http://cdpn.io/qDxvo
Gesty wielodotykowe
Istnieje kilka frameworków i bibliotek, takich jak Hammer czy QuoJS, które mogą uprościć zarządzanie gestami wielodotykowymi, ale jeśli chcesz połączyć kilka gestów i uzyskać pełną kontrolę, czasami lepiej jest zacząć od zera.
Aby zarządzać gestami ściskania i obracania, przechowujemy odległość i kąt między 2 palcami, gdy drugi palec dotyka ekranu:
//variables representing the actual scale/rotation of the object we are affecting
var currentScale = 1;
var currentRotation = 0;
function onTouchStart(event) {
event.preventDefault();
if( event.touches.length === 1){
handleDragStart(event.touches[0].clientX , event.touches[0].clientY);
}else if( event.touches.length === 2 ){
handleGestureStart(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
}
}
function handleGestureStart(x1, y1, x2, y2){
input.isGesture = true;
//calculate distance and angle between fingers
var dx = x2 - x1;
var dy = y2 - y1;
input.touchStartDistance=Math.sqrt(dx*dx+dy*dy);
input.touchStartAngle=Math.atan2(dy,dx);
//we also store the current scale and rotation of the actual object we are affecting. This is needed to support incremental rotation/scaling. We can't assume that an object is always the same scale when gesture starts.
input.startScale=currentScale;
input.startAngle=currentRotation;
}
W wydarzeniu dotkniecia i przesuwania stale mierzymy odległość i kąt między tymi dwoma palcami. Różnica między początkową a bieżącą odległością jest następnie używana do ustawienia skali, a różnica między początkowym a bieżącym kątem służy do ustawienia kąta.
function onTouchMove(event) {
event.preventDefault();
if( event.touches.length === 1){
handleDragging(event.touches[0].clientX, event.touches[0].clientY);
}else if( event.touches.length === 2 ){
handleGesture(event.touches[0].clientX, event.touches[0].clientY, event.touches[1].clientX, event.touches[1].clientY );
}
}
function handleGesture(x1, y1, x2, y2){
if(input.isGesture){
//calculate distance and angle between fingers
var dx = x2 - x1;
var dy = y2 - y1;
var touchDistance = Math.sqrt(dx*dx+dy*dy);
var touchAngle = Math.atan2(dy,dx);
//calculate the difference between current touch values and the start values
var scalePixelChange = touchDistance - input.touchStartDistance;
var angleChange = touchAngle - input.touchStartAngle;
//calculate how much this should affect the actual object
currentScale = input.startScale + scalePixelChange*0.01;
currentRotation = input.startAngle+(angleChange*180/Math.PI);
//upper and lower limit of scaling
if(currentScale<0.5) currentScale = 0.5;
if(currentScale>3) currentScale = 3;
}
}
Zmiana odległości między każdym zdarzeniem touchmove może być używana podobnie jak w przypadku przykładu z przeciąganiem, ale to podejście jest często przydatniejsze, gdy chcesz uzyskać ciągły ruch.
function onAnimationFrame() {
requestAnimationFrame( onAnimationFrame );
//execute transform based on currentScale and currentRotation
/*
/
*/
//because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
input.dragDX=0;
input.dragDY=0;
}
Jeśli chcesz, możesz też umożliwić przeciąganie obiektu podczas wykonywania gestów ściskania i obracania. W takim przypadku jako punkt wejścia do uchwytu przeciągania należy użyć punktu środkowego między 2 palcami.
Przykład: obracanie i zmienianie skali obiektu w 2D. Podobnie jak mapa w sekcji Odkrywaj: http://cdpn.io/izloq
Obsługa myszy i dotyku na tym samym sprzęcie
Obecnie dostępnych jest kilka laptopów, takich jak Chromebook Pixel, które obsługują zarówno mysz, jak i sterowanie dotykowe. Jeśli nie będziesz uważać, może to spowodować nieoczekiwane działanie.
Pamiętaj, że nie wystarczy wykryć obsługę dotykowego sterowania i ignorować dane z myszy. Musisz obsługiwać oba te elementy jednocześnie.
Jeśli w obsługach zdarzeń dotykowych nie używasz event.preventDefault()
, będą też wywoływane niektóre emulowane zdarzenia myszy, aby umożliwić działanie większości witryn nieoptymalizowanych pod kątem urządzeń dotykowych. Na przykład w przypadku pojedynczego kliknięcia na ekranie te zdarzenia mogą być wywoływane w szybkiej kolejności w tej kolejności:
- touchstart
- touchmove
- touchend
- ruch kursora myszy|najechanie kursorem myszy (na obiekt)
- mousemove
- mousedown
- mouseup
- click
Jeśli masz nieco bardziej złożone interakcje, te zdarzenia myszy mogą powodować nieoczekiwane działanie i zakłócać implementację. Często najlepiej jest używać event.preventDefault()
w obsługach zdarzeń dotykowych, a zarządzać danymi wprowadzanymi przez mysz w osobnych obsługach zdarzeń. Pamiętaj, że użycie event.preventDefault()
w obsługach zdarzeń dotykowych uniemożliwi też niektóre działania domyślne, takie jak przewijanie i zdarzenie kliknięcia.
„W Build with Chrome nie chcieliśmy, aby po dwukrotnym dotknięciu strony nastąpiło powiększenie, mimo że jest to standardowa funkcja w większości przeglądarek. Dlatego używamy metatagu viewport, aby powiedzieć przeglądarce, że nie ma powiększać obrazu, gdy użytkownik dwukrotnie kliknie. Pozwala to też wyeliminować opóźnienie kliknięcia o 300 ms, co poprawia szybkość działania witryny. (opóźnienie kliknięcia służy do rozróżnienia pojedynczego kliknięcia od kliknięcia dwukrotnego, gdy włączone jest powiększanie po kliknięciu dwukrotnym).
<meta name="viewport" content="width=device-width,user-scalable=no">
Pamiętaj, że korzystając z tej funkcji, musisz zadbać o czytelność witryny na wszystkich rozmiarach ekranu, ponieważ użytkownik nie będzie mógł powiększyć widoku.
Mysz, ekran dotykowy i klawiatura
W trybie eksploracji w 3D chcieliśmy zapewnić 3 sposoby nawigacji po mapie: za pomocą myszy (przeciąganie), dotykiem (przeciąganie, zbliżanie i obracanie za pomocą gestów) oraz za pomocą klawiatury (nawigacja za pomocą klawiszy strzałek). Wszystkie te metody nawigacji działają nieco inaczej, ale w przypadku każdej z nich zastosowaliśmy to samo podejście: zmienne ustawiamy w obsługach zdarzeń i działamy na nich w pętli requestAnimationFrame. Pętla requestAnimationFrame nie musi wiedzieć, która metoda jest używana do nawigacji.
Na przykład możemy ustawić ruch mapy (dragDX i dragDY) za pomocą wszystkich 3 metod wprowadzania danych. Oto implementacja klawiatury:
document.addEventListener('keydown', onKeyDown );
document.addEventListener('keyup', onKeyUp );
function onKeyDown( event ) {
input.keyCodes[ "k" + event.keyCode ] = true;
input.shiftKey = event.shiftKey;
}
function onKeyUp( event ) {
input.keyCodes[ "k" + event.keyCode ] = false;
input.shiftKey = event.shiftKey;
}
//this needs to be called every frame before animation is executed
function handleKeyInput(){
if(input.keyCodes.k37){
input.dragDX = -5; //37 arrow left
} else if(input.keyCodes.k39){
input.dragDX = 5; //39 arrow right
}
if(input.keyCodes.k38){
input.dragDY = -5; //38 arrow up
} else if(input.keyCodes.k40){
input.dragDY = 5; //40 arrow down
}
}
function onAnimationFrame() {
requestAnimationFrame( onAnimationFrame );
//because keydown events are not fired every frame we need to process the keyboard state first
handleKeyInput();
//implement animations based on what is stored in input
/*
/
*/
//because touchmove is only fired when finger is actually moving we need to reset the delta values each frame
input.dragDX = 0;
input.dragDY = 0;
}
Przykład w ramach aplikacji: Przeglądanie za pomocą myszy, ekranu dotykowego i klawiatury: http://cdpn.io/catlf
Podsumowanie
Dostosowanie Build with Chrome do obsługi urządzeń dotykowych o różnych rozmiarach ekranu było dla nas cennym doświadczeniem. Nasz zespół nie miał zbyt dużego doświadczenia w korzystaniu z tego poziomu interakcji na urządzeniach dotykowych, ale dużo się nauczyliśmy.
Największym wyzwaniem okazało się znalezienie odpowiedniego rozwiązania w zakresie wrażeń użytkownika i projektu. Wyzwania techniczne dotyczyły zarządzania wieloma rozmiarami ekranu, zdarzeniami dotykowymi i problemami z wydajnością.
Chociaż shadery WebGL na urządzeniach dotykowych sprawiały pewne problemy, w ogóle działały lepiej niż się spodziewaliśmy. Urządzenia stają się coraz potężniejsze, a implementacje WebGL poprawiają się błyskawicznie. Uważamy, że w najbliższej przyszłości będziemy częściej korzystać z WebGL na urządzeniach.
Jeśli jeszcze tego nie zrobisz, utwórz coś niesamowitego.