Jump to Table of Contents

Touch Events and Abstractions

The event-touch module extends the whitelist of DOM events to include the native touch and gesture events and adds relevant information to event facades.

The event-move module adds a set of abstract events that adapt to the client environment to handle either touch or mouse input.

The event-flick module adds a "flick" event on top of the gesture abstraction layer to capture a user flicking an element with mouse or finger.

The event-gestures module is a rollup of these three, but will potentially roll in more gesture based events in the future.

Using Touch Events

YUI DOM event support also extends to touch events. To use touch events in your application, you will need to include the event-touch module in your use statement.

The set of common low-level touch events, which exist on most touch-enabled OSes are supported:

  • touchstart
  • touchmove
  • touchend
  • touchcancel

Additionally, the iOS specific touch events, gesturestart, gesturechange and gestureend, are also supported. YUI doesn't replicate support for these events on other touch OSes currently, due to their lack of DOM level multi-touch support. At the point at which they do expose multi-touch information in the lower level touch events, we can build in cross-platform support for multi-touch gestures.

node.on("touchstart", function () {
    this.addClass("detached");
});

The Touch Event Facade

The event facade passed to touch events has the common set of touch specific array properties available:

  • touches
  • changedTouches
  • touchTargets

These event objects in these arrays are also normalized, just the same as the event object pass to any other DOM listener.

The event object for the iOS gesture events have scale and rotation properties, the same as the native event object.

Cross-Device Gesture Support

The event-move module provides the following events that roughly relate to the associated touch or mouse event, depending on the client device:

Abstract event Mouse event Touch event
gesturemovestart mousedown touchstart
gesturemove mousemove touchmove
gesturemoveend mouseup touchend

I say "roughly" because the gesture events aim to encapsulate common interactions rather than just serving as a relay to other events. Where this comes out is in the additional configuration that can be included in the subscription as a third argument.

// Notify me when the user puts a finger down, or mouses down on
// the car node
car.on("gesturemovestart", alignForMove, {

    // fire the event only after 300ms of continuous contact...
    minTime: 300,

    // ...or if the finger/mouse moves more than 3px
    minDistance: 3
});

// Move the car node when the user moves the finger or mouse.
// Note the `this` override parameter is shifted to account for
// the configuration param
car.on("gesturemove", car.move, null, car);


// Notify me when the user lifts their finger, or lets go of
// the mouse button (only if a gesturemovestart was received
// on the node).
car.on("gesturemoveend", screechingHalt);

The complete set of configuration parameters for the gesture events is in the API docs.

The three gesture events are related to each other. They are notifications for the start, progress, and end of the same gesture. gesturemove and gesturemoveend subscriptions won't execute unless a gesturemovestart happens.

If you need them to fire separately, such as when attaching and detaching subscribers dynamically, the gesturemove and gesturemoveend events can be subscribed to individually by configuring standAlone: true

// Doesn't require an associated `gesturemovestart` subscription
Y.one("doc").on("gesturemove", function(e) {...}, {
    standAlone:true
});

Under the hood, the DOM listeners which monitor mousemove/touchmove and mouseup/touchend are bound to the document by default. The node only provides the shared context to relate the three events.

Flick Gesture Event

The flick gesture event is fired whenever the user initiates a flick gesture (with a finger or the mouse) on the node where the listener is attached.

myNode.on("flick", function(e) {

  // Some of the flick specific data on the event facade

  var flick = e.flick,
      velocity = flick.velocity,
      distance = flick.distance,
      axis = flick.axis,
      startX = flick.start.pageX,
      startY = flick.start.pageY,

  // The event object itself is the event object for
  // the event which concludes the flick (the mouseup or touchend)

      endX = e.pageX,
      endY = e.pageY,
      endTarget = e.target;

});

Like with the supporting gesture events, when subscribing to flick, you can also pass additional configuration to control when and how the flick subscriber is notified.

// Custom config, with no context or extra args
myNode.on("flick", flickHandler, {

    // only notify me if the flick covered
    // more than 20px and was faster than 0.8 px/ms
    minDistance: 20,
    minVelocity: 0.8,

    // prevent the default behavior for the
    // underlying mouse/touch events
    preventDefault: true
});

// Another option to avoid confusion when specifying the `this`
// override or bound arguments for events with custom signatures
// is to use Y.bind
myNode.on("flick", Y.bind(o.flickHandler, o, arg1), {
    minDistance: 20,
    minVelocity: 0.8,
    preventDefault: true
});

// Alternately, make sure to account for the additional subscription
// parameter by passing null if there is no configuration.
myNode.on("flick", o.flickHandler, null, o, arg1);

The complete set of configuration parameters for the flick event is in the API docs.

Caveats

  1. The flick event doesn't (yet) support delegation.
  2. The delegate() signature for the gesture events is node.delegate('gesturemove', callback, filter, gestureConfig), reversing the order of the delegation filter and extra params from the hover and key events. This may be changed in a future release.