Multi-Touch-Webentwicklung

Boris Smus
Boris Smus

Einführung

Mobilgeräte wie Smartphones und Tablets haben in der Regel ein kapazitatives Touchscreen, um Interaktionen mit den Fingern des Nutzers zu erfassen. Da das mobile Web immer ausgefeiltere Anwendungen ermöglicht, benötigen Webentwickler eine Möglichkeit, diese Ereignisse zu verarbeiten. In fast jedem schnellen Spiel muss der Spieler beispielsweise mehrere Schaltflächen gleichzeitig drücken, was im Kontext eines Touchscreens Multitouch bedeutet.

Apple hat die Touch Events API in iOS 2.0 eingeführt. Android hat diesen De-facto-Standard inzwischen fast erreicht. Kürzlich hat sich eine W3C-Arbeitsgruppe zusammengefunden, um an dieser Spezifikation für Touch-Ereignisse zu arbeiten.

In diesem Artikel werde ich die Touch Events API von iOS- und Android-Geräten sowie Chrome für Computer auf Hardware mit Touchbedienung vorstellen. Außerdem erkläre ich, welche Arten von Apps Sie damit erstellen können, zeige Best Practices und nützliche Techniken, die die Entwicklung von Touch-fähigen Apps erleichtern.

Touch-Ereignisse

In der Spezifikation werden drei grundlegende Touch-Ereignisse beschrieben, die auf Mobilgeräten weithin implementiert sind:

  • touchstart: Ein Finger wird auf ein DOM-Element gelegt.
  • touchmove: Ein Finger wird über ein DOM-Element gezogen.
  • touchend: Ein Finger wird von einem DOM-Element entfernt.

Jedes Touch-Ereignis enthält drei Listen mit Touch-Ereignissen:

  • touches: Eine Liste aller Finger, die sich derzeit auf dem Display befinden.
  • targetTouches: Liste der Finger auf dem aktuellen DOM-Element.
  • changedTouches: eine Liste der Finger, die am aktuellen Ereignis beteiligt sind. Bei einem Touchend-Ereignis ist dies beispielsweise der Finger, der entfernt wurde.

Diese Listen bestehen aus Objekten, die Touch-Informationen enthalten:

  • identifier: Eine Zahl, die den aktuellen Finger in der Touch-Sitzung eindeutig identifiziert.
  • target: das DOM-Element, das das Ziel der Aktion war.
  • client/page/screen-Koordinaten: wo auf dem Bildschirm die Aktion stattgefunden hat
  • Radiuskoordinaten und Drehwinkel: Beschreiben die Ellipse, die die Fingerform annähernd beschreibt.

Apps mit Touchscreen

Die Ereignisse touchstart, touchmove und touchend bieten eine ausreichende Funktionsvielfalt, um praktisch jede Art von berührungsbasierter Interaktion zu unterstützen – einschließlich aller gängigen Multitouch-Gesten wie Zoomen durch Zusammenziehen und Auseinanderziehen oder Drehen.

Mit diesem Snippet können Sie ein DOM-Element per Touch-Geste mit nur einem Finger verschieben:

var obj = document.getElementById('id');
obj.addEventListener('touchmove', function(event) {
  // If there's exactly one finger inside this element
  if (event.targetTouches.length == 1) {
    var touch = event.targetTouches[0];
    // Place element where the finger is
    obj.style.left = touch.pageX + 'px';
    obj.style.top = touch.pageY + 'px';
  }
}, false);

Unten sehen Sie ein Beispiel, in dem alle aktuellen Berührungen auf dem Bildschirm angezeigt werden. Es ist hilfreich, sich ein Bild von der Reaktionsfähigkeit des Geräts zu machen.

Finger-Tracking
// Setup canvas and expose context via ctx variable
canvas.addEventListener('touchmove', function(event) {
  for (var i = 0; i < event.touches.length; i++) {
    var touch = event.touches[i];
    ctx.beginPath();
    ctx.arc(touch.pageX, touch.pageY, 20, 0, 2*Math.PI, true);
    ctx.fill();
    ctx.stroke();
  }
}, false);

Demos

Es gibt bereits eine Reihe interessanter Multitouch-Demos, z. B. diese Canvas-basierte Zeichendemo von Paul Irish und anderen.

Screenshot zeichnen

Und Browser Ninja, eine Tech-Demo, die ein Fruit Ninja-Klon ist und CSS3-Transformationen und ‑Übergänge sowie Canvas verwendet:

Browser-Ninja

Best Practices

Zoomen verhindern

Die Standardeinstellungen eignen sich nicht sehr gut für Multitouch, da Wischbewegungen und Touch-Gesten oft mit Browserverhalten wie Scrollen und Zoomen verknüpft sind.

Wenn Sie das Zoomen deaktivieren möchten, richten Sie den Viewport mit dem folgenden Meta-Tag so ein, dass er nicht vom Nutzer skaliert werden kann:

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

Weitere Informationen zum Festlegen des Darstellungsbereichs findest du in diesem Artikel zu mobiler HTML5-Werbung.

Scrollen verhindern

Einige Mobilgeräte haben Standardverhalten für Touchmove, z. B. den klassischen iOS-Overscroll-Effekt, bei dem die Ansicht zurückspringt, wenn beim Scrollen die Grenzen des Inhalts überschritten werden. Dies ist in vielen Multi-Touch-Anwendungen verwirrend und kann leicht deaktiviert werden:

document.body.addEventListener('touchmove', function(event) {
  event.preventDefault();
}, false); 

Mit Bedacht rendern

Wenn Sie eine Multitouch-Anwendung mit komplexen Gesten mit mehreren Fingern entwickeln, sollten Sie darauf achten, wie Sie auf Touch-Ereignisse reagieren, da Sie so viele gleichzeitig verarbeiten. Denken Sie an das Beispiel im vorherigen Abschnitt, bei dem alle Berührungen auf dem Bildschirm gezeichnet werden. Sie können zeichnen, sobald eine Touch-Eingabe erfolgt:

canvas.addEventListener('touchmove', function(event) {
  renderTouches(event.touches);
}, false);

Diese Technik lässt sich jedoch nicht mit der Anzahl der Finger auf dem Bildschirm skalieren. Stattdessen können Sie alle Finger verfolgen und in einer Schleife rendern, um eine deutlich bessere Leistung zu erzielen:

var touches = []
canvas.addEventListener('touchmove', function(event) {
  touches = event.touches;
}, false);

// Setup a 60fps timer
timer = setInterval(function() {
  renderTouches(touches);
}, 15);

targetTouches und changedTouches verwenden

Denken Sie daran, dass „event.touches“ ein Array ALLER Finger ist, die mit dem Bildschirm in Kontakt sind, nicht nur die Finger auf dem Ziel des DOM-Elements. Eventuell ist es viel nützlicher, stattdessen event.targetTouches oder event.changedTouches zu verwenden.

Da Sie für Mobilgeräte entwickeln, sollten Sie sich mit den allgemeinen Best Practices für Mobilgeräte vertraut machen. Diese werden im Artikel von Eric Bidelman sowie in diesem W3C-Dokument behandelt.

Geräteunterstützung

Leider variieren die Touch-Ereignisimplementierungen stark in Vollständigkeit und Qualität. Ich habe ein Diagnose-Script geschrieben, das einige grundlegende Informationen zur Touch API-Implementierung enthält, darunter, welche Ereignisse unterstützt werden und wie die Auslösung von Touchmove-Ereignissen erfolgt. Ich habe Android 2.3.3 auf Nexus One- und Nexus S-Hardware, Android 3.0.1 auf Xoom und iOS 4.2 auf iPad und iPhone getestet.

Kurz gesagt: Alle getesteten Browser unterstützen die Ereignisse touchstart, touchend und touchmove.

Die Spezifikation enthält drei weitere Touch-Ereignisse, die jedoch von keinem der getesteten Browser unterstützt werden:

  • touchenter: Ein bewegter Finger betritt ein DOM-Element.
  • touchleave: Ein bewegter Finger verlässt ein DOM-Element.
  • touchcancel: Eine Berührung wird unterbrochen (implementierungsspezifisch).

Innerhalb jeder Touch-Liste stellen die getesteten Browser auch die Touch-Listen touches, targetTouches und changedTouches bereit. Keiner der getesteten Browser unterstützt jedoch „radiusX“, „radiusY“ oder „rotationAngle“, mit denen die Form des Fingers angegeben wird, der den Bildschirm berührt.

Während eines Touchmove werden Ereignisse auf allen getesteten Geräten etwa 60-mal pro Sekunde ausgelöst.

Android 2.3.3 (Nexus)

Der Android-Gingerbread-Browser (getestet auf Nexus One und Nexus S) unterstützt keine Multitouch-Gesten. Dies ist ein bekanntes Problem.

Android 3.0.1 (Xoom)

Der Browser von Xoom unterstützt grundlegende Multitouch-Funktionen, aber nur für ein einzelnes DOM-Element. Der Browser reagiert nicht richtig auf zwei gleichzeitige Berührungen verschiedener DOM-Elemente. Mit anderen Worten: Die folgenden Aktionen reagieren auf zwei gleichzeitige Berührungen:

obj1.addEventListener('touchmove', function(event) {
  for (var i = 0; i < event.targetTouches; i++) {
    var touch = event.targetTouches[i];
    console.log('touched ' + touch.identifier);
  }
}, false);

Folgendes ist jedoch nicht möglich:

var objs = [obj1, obj2];
for (var i = 0; i < objs.length; i++) {
  var obj = objs[i];
  obj.addEventListener('touchmove', function(event) {
    if (event.targetTouches.length == 1) {
      console.log('touched ' + event.targetTouches[0].identifier);
    }
  }, false);
}

iOS 4.x (iPad, iPhone)

iOS-Geräte unterstützen Multitouch vollständig, können mehrere Finger gleichzeitig erkennen und bieten eine sehr reaktionsschnelle Touchbedienung im Browser.

Entwicklertools

Bei der Entwicklung mobiler Apps ist es oft einfacher, mit dem Prototyping auf dem Computer zu beginnen und sich dann den gerätespezifischen Teilen auf den Geräten zu widmen, die Sie unterstützen möchten. Multitouch ist eine der Funktionen, die sich auf dem PC nur schwer testen lassen, da die meisten PCs keine Touchbedienung haben.

Das Testen auf Mobilgeräten kann den Entwicklungszyklus in die Länge ziehen, da jede Änderung auf einen Server übertragen und dann auf das Gerät geladen werden muss. Sobald sie ausgeführt wird, müssen Sie wenig tun, um Ihre Anwendung zu debuggen, da Tablets und Smartphones keine Webentwicklertools bieten.

Eine Lösung für dieses Problem besteht darin, Touch-Ereignisse auf Ihrem Entwicklungscomputer zu simulieren. Bei einzelnen Berührungen können Touch-Ereignisse anhand von Mausereignissen simuliert werden. Multitouch-Ereignisse können simuliert werden, wenn Sie ein Gerät mit Touchbedienung haben, z. B. ein modernes Apple MacBook.

Ereignisse mit einmaligem Tippen

Wenn Sie Single-Touch-Ereignisse auf Ihrem Desktop simulieren möchten, können Sie in Chrome Touch-Ereignisse über die Entwicklertools emulieren. Öffne die Entwicklertools, wähle das Zahnradsymbol für die Einstellungen, dann „Überschreibungen“ oder „Emulation“ aus und aktiviere „Touch-Ereignisse emulieren“.

Für andere Browser können Sie Phantom Limb ausprobieren, das Touch-Ereignisse auf Seiten simuliert und außerdem eine riesige Hand anzeigt.

Es gibt auch das jQuery-Plug-in Touchable, mit dem Touch- und Mausereignisse plattformübergreifend vereinheitlicht werden.

Multi-Touch-Ereignisse

Damit Ihre Multitouch-Webanwendung in Ihrem Browser auf Ihrem Multitouch-Trackpad (z. B. Apple MacBook oder MagicPad) funktioniert, habe ich die MagicTouch.js-Polyfill erstellt. Sie erfasst Touch-Ereignisse auf Ihrem Touchpad und wandelt sie in standardkompatible Touch-Ereignisse um.

  1. Laden Sie das npTuioClient NPAPI-Plug-in herunter und installieren Sie es unter ~/Library/Internet Plug-Ins/.
  2. Laden Sie die TongSeng TUIO App für das MagicPad von Mac herunter und starten Sie den Server.
  3. Lade MagicTouch.js herunter, eine JavaScript-Bibliothek zum Simulieren von spezifikationskonformen Touch-Ereignissen basierend auf npTuioClient-Callbacks.
  4. Fügen Sie das Script „magictouch.js“ und das Plug-in „npTuioClient“ wie unten beschrieben in Ihre Anwendung ein:
<head>
  ...
  <script src="/path/to/magictouch.js"></script>
</head>

<body>
  ...
  <object id="tuio" type="application/x-tuio" style="width: 0px; height: 0px;">
    Touch input plugin failed to load!
  </object>
</body>

Möglicherweise müssen Sie das Plug-in aktivieren.

Eine Live-Demo mit magictouch.js ist unter paulirish.com/demo/multi verfügbar:

Ich habe diesen Ansatz nur mit Chrome 10 getestet, er sollte aber mit nur geringen Anpassungen auch in anderen modernen Browsern funktionieren.

Wenn Ihr Computer keinen Multitouch-Eingabemechanismus hat, können Sie Touch-Ereignisse mit anderen TUIO-Trackern wie dem reacTIVision simulieren. Weitere Informationen finden Sie auf der TUIO-Projektseite.

Ihre Touch-Gesten können mit den Multi-Touch-Gesten auf Betriebssystemebene identisch sein. Unter OS X kannst du systemweite Ereignisse konfigurieren, indem du in den Systemeinstellungen die Touchpad-Einstellungen aufrufst.

Da Multitouch-Funktionen in mobilen Browsern immer häufiger unterstützt werden, freue ich mich sehr, dass neue Webanwendungen diese umfangreiche API voll ausschöpfen können.