Mit Chrome entwickeln

LEGO®-Steine für das Web auf verschiedenen Geräten

Hans Eklund
Hans Eklund

Build with Chrome, ein unterhaltsamer Test für Chrome-Nutzer auf dem Computer, der ursprünglich in Australien eingeführt wurde, wurde 2014 wieder veröffentlicht. Er ist jetzt weltweit verfügbar, bietet Verknüpfungen mit THE LEGO® MOVIE™ und unterstützt jetzt auch Mobilgeräte. In diesem Artikel teilen wir einige Erkenntnisse aus dem Projekt, insbesondere in Bezug auf die Umstellung von einer Desktop-Anwendung zu einer Lösung mit mehreren Bildschirmen, die sowohl die Maus- als auch die Touchbedienung unterstützt.

Die Geschichte von Build with Chrome

Die erste Version von Build with Chrome wurde 2012 in Australien eingeführt. Wir wollten die Leistungsfähigkeit des Webs auf ganz neue Weise demonstrieren und Chrome einer ganz neuen Zielgruppe präsentieren.

Die Website bestand aus zwei Hauptteilen: dem „Build“-Modus, in dem Nutzer mit LEGO-Steinen Kreationen bauen können, und dem „Explore“-Modus, in dem sie sich die Kreationen in einer LEGO-Version von Google Maps ansehen können.

Interaktive 3D-Modelle waren unerlässlich, um Nutzern das bestmögliche LEGO-Bauerlebnis zu bieten. 2012 war WebGL nur in Desktop-Browsern öffentlich verfügbar. Daher war Build nur für Desktop-Computer gedacht. Bei der Funktion „Entdecken“ wurden die Kreationen mit Google Maps dargestellt. Wenn Sie jedoch nah genug heranzoomten, wurde zu einer WebGL-Implementierung der Karte gewechselt, auf der die Kreationen in 3D zu sehen waren. Dabei wurde weiterhin Google Maps als Basistextur verwendet. Wir wollten eine Umgebung schaffen, in der LEGO-Fans jeden Alters ihre Kreativität einfach und intuitiv ausdrücken und die Kreationen anderer entdecken können.

2013 haben wir beschlossen, Build with Chrome auf neue Webtechnologien auszuweiten. Zu diesen Technologien gehörte WebGL in Chrome für Android, mit dem sich Build with Chrome natürlich auch auf Mobilgeräten nutzen lässt. Zuerst haben wir Touch-Prototypen entwickelt, bevor wir die Hardware für das „Builder Tool“ getestet haben, um das Gestenverhalten und die taktile Reaktion zu verstehen, die wir in einem Browser im Vergleich zu einer mobilen App sehen könnten.

Responsives Frontend

Wir mussten Geräte mit Touch- und Mauseingabe unterstützen. Die Verwendung derselben Benutzeroberfläche auf kleinen Touchscreens erwies sich jedoch aufgrund von Platzeinschränkungen als suboptimale Lösung.

Im Bereich „Bauen“ gibt es viele interaktive Elemente: Sie können heranzoomen und herauszoomen, die Farben der Steine ändern und natürlich Steine auswählen, drehen und platzieren. Da Nutzer viel Zeit mit diesem Tool verbringen, ist es wichtig, dass sie schnell auf alles zugreifen können, was sie häufig verwenden, und dass sie sich beim Interagieren damit wohlfühlen.

Wenn Sie eine stark interaktive Touch-Anwendung entwerfen, werden Sie feststellen, dass der Bildschirm schnell klein wirkt und die Finger der Nutzer beim Interagieren einen Großteil des Bildschirms bedecken. Das wurde uns bei der Arbeit mit dem Builder klar. Beim Design müssen Sie die physische Bildschirmgröße und nicht die Pixel in den Grafiken berücksichtigen. Es ist wichtig, die Anzahl der Schaltflächen und Steuerelemente zu minimieren, damit möglichst viel Bildschirmfläche für die eigentlichen Inhalte zur Verfügung steht.

Unser Ziel war es, Build auf Touch-Geräten natürlich zu gestalten. Dazu haben wir nicht nur die Touchbedienung in die ursprüngliche Desktopversion aufgenommen, sondern die Oberfläche so gestaltet, dass sie wirklich für Touchbedienung gedacht ist. Wir haben zwei Versionen der Benutzeroberfläche entwickelt: eine für Computer und Tablets mit großen Bildschirmen und eine für Mobilgeräte mit kleineren Bildschirmen. Verwenden Sie nach Möglichkeit eine einzige Implementierung und sorgen Sie für einen reibungslosen Übergang zwischen den Modi. In unserem Fall haben wir festgestellt, dass der Unterschied zwischen diesen beiden Modi so groß war, dass wir uns für einen bestimmten Wendepunkt entschieden haben. Die beiden Versionen haben viele gemeinsame Funktionen und wir haben versucht, die meisten Dinge mit nur einer Codeimplementierung zu erledigen. Einige Aspekte der Benutzeroberfläche funktionieren jedoch unterschiedlich.

Wir verwenden User-Agent-Daten, um Mobilgeräte zu erkennen, und prüfen dann die Größe des Darstellungsbereichs, um zu entscheiden, ob die mobile Benutzeroberfläche für kleine Bildschirme verwendet werden soll. Es ist etwas schwierig, einen Grenzwert für einen „großen Bildschirm“ festzulegen, da es schwierig ist, einen zuverlässigen Wert für die physische Bildschirmgröße zu erhalten. Glücklicherweise spielt es in unserem Fall keine Rolle, ob wir die Benutzeroberfläche für kleine Bildschirme auf einem Touchgerät mit großem Bildschirm anzeigen, da das Tool trotzdem einwandfrei funktioniert. Einige Schaltflächen wirken jedoch möglicherweise etwas zu groß. Wir haben den Wendepunkt schließlich auf 1.000 Pixel festgelegt. Wenn Sie die Website über ein Fenster laden, das breiter als 1.000 Pixel ist (im Querformat), wird die Version für große Bildschirme angezeigt.

Sehen wir uns die beiden Bildschirmgrößen und -oberflächen genauer an:

Großer Bildschirm mit Unterstützung für Maus und Touch

Die Version für große Bildschirme wird auf allen Desktop-Computern mit Mausunterstützung und auf Touch-Geräten mit großen Bildschirmen (z. B. Google Nexus 10) ausgeliefert. Diese Version ähnelt der ursprünglichen Desktoplösung in Bezug auf die verfügbaren Navigationssteuerungen. Wir haben jedoch Touchbedienung und einige Touch-Gesten hinzugefügt. Wir passen die Benutzeroberfläche an die Fenstergröße an. Wenn ein Nutzer die Größe des Fensters ändert, wird möglicherweise ein Teil der Benutzeroberfläche entfernt oder die Größe geändert. Dazu verwenden wir CSS-Medienabfragen.

Beispiel: Wenn die verfügbare Höhe weniger als 730 Pixel beträgt, ist der Zoom-Schieberegler im Explore-Modus ausgeblendet:

@media only screen and (max-height: 730px) {
    .zoom-slider {
        display: none;
    }
}

Kleiner Bildschirm, nur Touchbedienung

Diese Version wird auf Mobilgeräten und kleinen Tablets ausgeliefert (Zielgeräte: Nexus 4 und Nexus 7). Für diese Version ist Multitouch-Unterstützung erforderlich.

Auf Geräten mit kleinem Bildschirm müssen wir den Inhalten möglichst viel Platz bieten. Deshalb haben wir einige Anpassungen vorgenommen, um den Platz zu maximieren. Meistens haben wir selten verwendete Elemente aus dem Blickfeld verschoben:

  • Die Auswahl der Bausteine wird beim Bauen zu einer Farbauswahl minimiert.
  • Die Zoom- und Ausrichtungssteuerung wurde durch Multi-Touch-Gesten ersetzt.
  • Die Chrome-Vollbildfunktion ist auch hilfreich, um mehr Platz auf dem Bildschirm zu erhalten.
Anzeigen auf einem großen Bildschirm erstellen
Auf einem großen Bildschirm entwickeln. Die Auswahl der Bausteine ist immer sichtbar und rechts befinden sich einige Steuerelemente.
Auf einem kleinen Bildschirm entwickeln
Auf einem kleinen Bildschirm entwickeln. Die Auswahl der Steine ist minimiert und einige Schaltflächen wurden entfernt.

WebGL-Leistung und -Unterstützung

Moderne Touch-Geräte haben zwar recht leistungsstarke GPUs, aber sie sind noch weit von ihren Desktop-Pendants entfernt. Daher wussten wir, dass es einige Herausforderungen bei der Leistung geben würde, insbesondere im 3D-Explore-Modus, in dem viele Kreationen gleichzeitig gerendert werden müssen.

Kreativ gesehen wollten wir einige neue Arten von Steinen mit komplexen Formen und sogar Transparenz hinzufügen – Funktionen, die in der Regel sehr viel GPU-Leistung erfordern. Da wir jedoch abwärtskompatibel sein und weiterhin Kreationen aus der ersten Version unterstützen mussten, konnten wir keine neuen Einschränkungen festlegen, z. B. die Gesamtzahl der Steine in den Kreationen deutlich reduzieren.

In der ersten Version von Build gab es eine maximale Anzahl von Bausteinen, die in einer Kreation verwendet werden konnten. Es gab einen „Ziegelzähler“, der angab, wie viele Ziegel noch übrig waren. Bei der neuen Implementierung haben einige der neuen Blöcke einen größeren Einfluss auf den Brick-Meter als die Standardblöcke, wodurch die maximale Gesamtzahl der Blöcke leicht reduziert wurde. So konnten wir neue Blöcke einbinden und gleichzeitig eine gute Leistung erzielen.

Im Explore 3D-Modus passiert gleichzeitig viel: Texturierung der Basisplatte, Laden von Kreationen, Animieren und Rendern von Kreationen usw. Das erfordert viel von der GPU und der CPU. Deshalb haben wir in den Chrome-Entwicklertools viel Frame-Profiling durchgeführt, um diese Teile so weit wie möglich zu optimieren. Auf Mobilgeräten haben wir uns entschieden, die Creatives etwas näher heranzuzoomen, damit nicht so viele Creatives gleichzeitig gerendert werden müssen.

Bei einigen Geräten mussten wir einige der WebGL-Shader überarbeiten und vereinfachen, aber wir haben immer eine Lösung gefunden und sind weitergekommen.

Unterstützung für Geräte ohne WebGL

Wir wollten, dass die Website auch dann einigermaßen nutzbar ist, wenn das Gerät des Besuchers WebGL nicht unterstützt. Manchmal gibt es Möglichkeiten, 3D-Objekte mithilfe einer Canvas-Lösung oder CSS3D-Funktionen vereinfacht darzustellen. Leider konnten wir keine zufriedenstellende Lösung finden, um die 3D-Funktionen von „Entwerfen und erkunden“ ohne WebGL zu replizieren.

Der visuelle Stil der Kreationen muss für alle Plattformen einheitlich sein. Wir hätten auch eine 2,5D-Lösung ausprobieren können, aber das hätte die Kreationen in gewisser Weise anders aussehen lassen. Außerdem mussten wir dafür sorgen, dass mit der ersten Version von „Build with Chrome“ erstellte Kreationen in der neuen Version der Website genauso aussehen und reibungslos funktionieren wie in der ersten Version.

Der Explore-2D-Modus ist weiterhin für Geräte ohne WebGL verfügbar, auch wenn Sie keine neuen Kreationen erstellen oder in 3D erkunden können. So können sich Nutzer trotzdem ein Bild davon machen, wie umfangreich das Projekt ist und was sie mit diesem Tool erstellen könnten, wenn sie ein WebGL-kompatibles Gerät verwenden würden. Die Website ist für Nutzer ohne WebGL-Unterstützung möglicherweise nicht so wertvoll, sollte aber zumindest als Teaser dienen und sie dazu anregen, es auszuprobieren.

Manchmal ist es einfach nicht möglich, Fallback-Versionen für WebGL-Lösungen beizubehalten. Es gibt viele mögliche Gründe, z. B. Leistung, visueller Stil, Entwicklungs- und Wartungskosten. Wenn Sie sich jedoch gegen die Implementierung eines Fallbacks entscheiden, sollten Sie zumindest für Besucher mit nicht WebGL-fähigen Browsern sorgen, erklären, warum sie nicht vollständig auf die Website zugreifen können, und eine Anleitung dazu geben, wie sie das Problem mit einem WebGL-fähigen Browser beheben können.

Vermögensverwaltung

2013 führte Google eine neue Version von Google Maps ein, die die größten Änderungen an der Benutzeroberfläche seit der Einführung des Dienstes mit sich brachte. Deshalb haben wir beschlossen, Build with Chrome so zu überarbeiten, dass es zur neuen Google Maps-Benutzeroberfläche passt. Dabei haben wir auch andere Faktoren berücksichtigt. Das neue Design ist relativ flach mit klaren, einfarbigen Farben und einfachen Formen. So konnten wir für viele UI-Elemente reines CSS verwenden und die Verwendung von Bildern minimieren.

In der Explore-Ansicht müssen viele Bilder geladen werden: Miniaturansichten für die Kreationen, Kartentexturen für die Baseplates und schließlich die eigentlichen 3D-Kreationen. Wir achten besonders darauf, dass es beim Laden neuer Bilder nicht zu Speicherlecks kommt.

Die 3D-Kreationen werden in einem benutzerdefinierten Dateiformat gespeichert, das als PNG-Bild verpackt ist. Da die Daten der 3D-Kreationen als Bild gespeichert wurden, konnten wir sie quasi direkt an die Shader weitergeben, die die Kreationen rendern.

Für alle von Nutzern erstellten Bilder konnten wir dank des Designs dieselben Bildgrößen für alle Plattformen verwenden und so die Speicher- und Bandbreitennutzung minimieren.

Bildschirmausrichtung verwalten

Es ist leicht zu vergessen, wie sehr sich das Seitenverhältnis des Displays ändert, wenn Sie vom Hoch- ins Querformat wechseln oder umgekehrt. Das müssen Sie von Anfang an bei der Anpassung für Mobilgeräte berücksichtigen.

Auf einer herkömmlichen Website mit aktiviertem Scrollen können Sie CSS-Regeln anwenden, um eine responsive Website zu erhalten, auf der Inhalte und Menüs neu angeordnet werden. Solange Sie die Scrollfunktion verwenden können, ist das ziemlich einfach.

Wir haben diese Methode auch bei Build verwendet, waren aber bei der Gestaltung des Layouts etwas eingeschränkt, da die Inhalte jederzeit sichtbar sein und wir gleichzeitig schnell auf eine Reihe von Steuerelementen und Schaltflächen zugreifen mussten. Für reine Inhaltswebsites wie Nachrichtenwebsites ist ein responsives Layout sehr sinnvoll, aber für eine Spiele-App wie unsere war es eine Herausforderung. Es war eine Herausforderung, ein Layout zu finden, das sowohl im Quer- als auch im Hochformat funktioniert, gleichzeitig aber einen guten Überblick über die Inhalte bietet und eine bequeme Interaktion ermöglicht. Letztendlich haben wir uns entschieden, Build nur im Querformat zu behalten und den Nutzer aufzufordern, sein Gerät zu drehen.

Explore war in beiden Ausrichtungen viel einfacher zu lösen. Wir mussten nur die Zoomstufe des 3D-Modells je nach Ausrichtung anpassen, um eine einheitliche Darstellung zu erhalten.

Das Layout der Inhalte wird größtenteils über CSS gesteuert, aber einige orientierungsbezogene Elemente mussten in JavaScript implementiert werden. Wir haben festgestellt, dass es keine gute geräteübergreifende Lösung gibt, um die Ausrichtung mit window.orientation zu ermitteln. Daher haben wir letztendlich nur window.innerWidth und window.innerHeight verglichen, um die Ausrichtung des Geräts zu ermitteln.

if( window.innerWidth > window.innerHeight ){
  //landscape
} else {
  //portrait
}

Touch-Unterstützung hinzufügen

Das Hinzufügen von Touch-Unterstützung für Webinhalte ist relativ einfach. Grundlegende Interaktivität wie das Klickereignis funktioniert auf Computern und Touch-fähigen Geräten gleich. Bei erweiterten Interaktionen müssen Sie jedoch auch die Touch-Ereignisse „touchstart“, „touchmove“ und „touchend“ verarbeiten. In diesem Artikel erfahren Sie die Grundlagen zur Verwendung dieser Ereignisse. Internet Explorer unterstützt keine Touch-Ereignisse, sondern verwendet stattdessen Maus-Ereignisse (z. B. „pointerdown“, „pointermove“ und „pointerup“). Pointer-Ereignisse wurden zur Standardisierung an das W3C gesendet, sind aber derzeit nur im Internet Explorer implementiert.

Für den Explore 3D-Modus wollten wir dieselbe Navigation wie in der Standardimplementierung von Google Maps verwenden: Mit einem Finger die Karte schwenken und mit zwei Fingern heranzoomen. Da die Kreationen in 3D sind, haben wir auch die Drehgeste mit zwei Fingern hinzugefügt. Dazu sind in der Regel Touch-Ereignisse erforderlich.

Es empfiehlt sich, aufwendige Berechnungen zu vermeiden, z. B. das Aktualisieren oder Rendern von 3D-Objekten in den Ereignishandlern. Speichern Sie die Touch-Eingabe stattdessen in einer Variablen und reagieren Sie im requestAnimationFrame-Render-Loop auf die Eingabe. Dies erleichtert auch die gleichzeitige Implementierung einer Maus, da Sie die entsprechenden Mauswerte einfach in denselben Variablen speichern.

Initialisieren Sie zuerst ein Objekt, in dem die Eingabe gespeichert werden soll, und fügen Sie den Touchstart-Ereignis-Listener hinzu. In jedem Ereignishandler wird event.preventDefault() aufgerufen. Dadurch wird verhindert, dass der Browser das Touch-Ereignis weiter verarbeitet, was zu unerwartetem Verhalten wie dem Scrollen oder Skalieren der gesamten Seite führen kann.

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);
  }
}

Die Eingabe wird nicht in den Ereignis-Handlern, sondern in separaten Handlern gespeichert: handleDragStart, handleDragging und handleDragStop. Das liegt daran, dass wir sie auch über die Mausereignis-Handler aufrufen können möchten. Denken Sie daran, dass Nutzer zwar selten, aber doch manchmal Touchbedienung und Maus gleichzeitig verwenden. Anstatt diesen Fall direkt zu bearbeiten, sorgen wir nur dafür, dass nichts passiert.

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;
  }
}

Bei Touchmove-basierten Animationen ist es oft nützlich, auch die Delta-Bewegung seit dem letzten Ereignis zu speichern. Wir haben diesen Wert beispielsweise als Parameter für die Geschwindigkeit der Kamera verwendet, wenn sie sich in Explore über alle Wandhalterungen bewegt, da Sie nicht die Wandhalterungen ziehen, sondern die Kamera bewegen.

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;
}

Eingebettetes Beispiel:Ziehen eines Objekts mithilfe von Touch-Ereignissen. Ähnliche Implementierung wie beim Ziehen der 3D-Explore-Karte in Build with Chrome: http://cdpn.io/qDxvo

Multi-Touch-Gesten

Es gibt mehrere Frameworks oder Bibliotheken wie Hammer oder QuoJS, die die Verwaltung von Multitouch-Gesten vereinfachen können. Wenn Sie jedoch mehrere Touch-Gesten kombinieren und die volle Kontrolle haben möchten, ist es manchmal am besten, sie von Grund auf neu zu erstellen.

Um die Touch-Gesten „Zusammenziehen“ und „Drehen“ zu verwalten, speichern wir den Abstand und den Winkel zwischen zwei Fingern, wenn der zweite Finger auf das Display gelegt wird:

//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;
}

Im Touchmove-Ereignis messen wir dann kontinuierlich den Abstand und den Winkel zwischen diesen beiden Fingern. Die Differenz zwischen dem Startabstand und dem aktuellen Abstand wird dann verwendet, um den Maßstab festzulegen, und die Differenz zwischen dem Startwinkel und dem aktuellen Winkel wird verwendet, um den Winkel festzulegen.

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;
  }
}

Sie könnten die Entfernungsänderung zwischen den einzelnen Touchmove-Ereignissen ähnlich wie im Beispiel mit dem Ziehen verwenden. Dieser Ansatz ist jedoch oft nützlicher, wenn Sie eine kontinuierliche Bewegung wünschen.

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;
}

Sie können auch das Ziehen des Objekts aktivieren, während Sie die Touch-Gesten zum Zusammen- und Auseinanderziehen und Drehen verwenden. In diesem Fall verwenden Sie den Mittelpunkt zwischen den beiden Fingern als Eingabe für den Drag-Handler.

Eingebettetes Beispiel:Ein Objekt in 2D drehen und skalieren Ähnlich wie die Karte in „Entdecken“: http://cdpn.io/izloq

Unterstützung von Maus und Touchbedienung auf derselben Hardware

Heutzutage gibt es mehrere Laptops, z. B. das Chromebook Pixel, die sowohl die Maus- als auch die Touchbedienung unterstützen. Andernfalls kann es zu unerwartetem Verhalten kommen.

Wichtig ist, dass Sie nicht nur die Touchbedienung erkennen und dann die Mauseingabe ignorieren, sondern beide gleichzeitig unterstützen.

Wenn Sie event.preventDefault() nicht in Ihren Touch-Ereignishandlern verwenden, werden auch einige emulierte Mausereignisse ausgelöst, damit die meisten nicht für Touchbedienung optimierten Websites weiterhin funktionieren. Bei einem einzelnen Tippen auf das Display werden diese Ereignisse beispielsweise in schneller Folge und in dieser Reihenfolge ausgelöst:

  1. touchstart
  2. touchmove
  3. touchend
  4. Mouseover
  5. mousemove
  6. mousedown
  7. mouseup
  8. Klick

Bei etwas komplexeren Interaktionen können diese Mausereignisse zu unerwartetem Verhalten führen und Ihre Implementierung beeinträchtigen. Es ist oft am besten, event.preventDefault() in den Touch-Ereignishandlern zu verwenden und die Mauseingabe in separaten Ereignishandlern zu verwalten. Wenn Sie event.preventDefault() in Touch-Ereignishandlern verwenden, wird auch das Standardverhalten verhindert, z. B. das Scrollen und das Klickereignis.

„Bei Build with Chrome sollte nicht herangezoomt werden, wenn jemand doppelt auf die Website tippt, obwohl das in den meisten Browsern Standard ist. Deshalb verwenden wir das Meta-Tag „viewport“, um dem Browser zu sagen, dass er nicht zoomen soll, wenn ein Nutzer doppelt tippt. Außerdem wird die Klickverzögerung von 300 Millisekunden aufgehoben, wodurch die Reaktionsfähigkeit der Website verbessert wird. Die Klickverzögerung dient dazu, zwischen einem einzelnen Tippen und einem doppelten Tippen zu unterscheiden, wenn das Zoomen durch Doppeltippen aktiviert ist.

<meta name="viewport" content="width=device-width,user-scalable=no">

Wenn Sie diese Funktion verwenden, müssen Sie dafür sorgen, dass die Website auf allen Bildschirmgrößen gut lesbar ist, da Nutzer nicht heranzoomen können.

Maus-, Touch- und Tastatureingabe

Im 3D-Modus „Erkunden“ sollten drei Möglichkeiten zur Navigation auf der Karte verfügbar sein: Maus (Ziehen), Touchbedienung (Ziehen, Zusammenziehen zum Zoomen und Drehen) und Tastatur (mit den Pfeiltasten). Alle diese Navigationsmethoden funktionieren etwas anders, aber wir haben bei allen denselben Ansatz verwendet: Variablen in Ereignis-Handlern festlegen und in der requestAnimationFrame-Schleife darauf reagieren. Die requestAnimationFrame-Schleife muss nicht wissen, welche Methode für die Navigation verwendet wird.

So könnten wir beispielsweise die Bewegung der Karte (dragDX und dragDY) mit allen drei Eingabemethoden festlegen. Hier ist die Tastaturimplementierung:

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;
}

Eingebettetes Beispiel:Mit Maus, Touchbedienung und Tastatur navigieren: http://cdpn.io/catlf

Zusammenfassung

Die Anpassung von Build with Chrome zur Unterstützung von Touch-Geräten mit vielen verschiedenen Bildschirmgrößen war eine Lernerfahrung. Das Team hatte nicht viel Erfahrung mit dieser Art von Interaktivität auf Touch-Geräten und wir haben dabei viel gelernt.

Die größte Herausforderung bestand darin, die Nutzerfreundlichkeit und das Design zu optimieren. Die technischen Herausforderungen bestanden darin, viele Bildschirmgrößen, Touch-Ereignisse und Leistungsprobleme zu verwalten.

Obwohl es einige Herausforderungen mit den WebGL-Shadern auf Touch-Geräten gab, funktionierte das fast besser als erwartet. Geräte werden immer leistungsfähiger und WebGL-Implementierungen werden schnell besser. Wir sind der Meinung, dass WebGL in naher Zukunft auf Geräten viel häufiger verwendet wird.

Erstellen Sie jetzt etwas Tolles!