hammerjs / hammer.js

A javascript library for multi-touch gestures :// You can touch this
http://hammerjs.github.io
MIT License
24.11k stars 2.63k forks source link

Feature request: Go fully declarative for recognizeWith/requireFailure #680

Open molily opened 10 years ago

molily commented 10 years ago

Currently I have something like this:

var h = new Hammer.Manager(target, {
  recognizers: [
    [Hammer.Tap],
    [Hammer.Tap, {event: 'doubletap', taps: 2}]
    // Swipe and pinch omitted
  ]
});

var tapRecognizer = h.get('tap');
var doubleTapRecognizer = h.get('doubletap');
doubleTapRecognizer.recognizeWith(tapRecognizer);
tapRecognizer.requireFailure(doubleTapRecognizer);

Apparently (correct me if I’m wrong) I have to specify the mutual recognizeWith/requireFailure programmatically even though the declarative recognizers: […] way allows to specify recognizeWith/requireFailure.

What I would like to write is:

var h = new Hammer.Manager(target, {
  recognizers: [
    [Hammer.Tap, null, null, 'doubletap'],
    [Hammer.Tap, {event: 'doubletap', taps: 2}, 'tap']
    // Swipe and pinch omitted
  ]
});

This doesn’t work because the double tap recognizer hasn’t been created when the tap recognizer is created. The current code in the Manager constructor:

each(options.recognizers, function(item) {
  var recognizer = this.add(new (item[0])(item[1]));
  item[2] && recognizer.recognizeWith(item[2]);
  item[3] && recognizer.requireFailure(item[3]);
}, this);

My proposal (rough sketch, untested):

// First create all recognizers
each(options.recognizers, function(item) {
  var recognizer = this.add(new (item[0])(item[1]));
}, this);
// Then connect them
each(options.recognizers, function(item) {
  if (!(item[2] || item[3])) return;
  // Probably there is a better way to get the recognizer again
  var event = item[1] && item[1].event ? item[1].event : item[0].prototype.defaults.event;
  var recognizer = this.get(event);
  item[2] && recognizer.recognizeWith(item[2]);
  item[3] && recognizer.requireFailure(item[3]);
}, this)

I hope you get what I’m trying to say. :) What do you think? Personally I like the declarative syntax a lot and with this change it would cover more things that are possible programatically.

runspired commented 9 years ago

@arschmitz my new easy recognizer maker for ember does something in the same vein, might be worth thinking this one over. The rough version of which is below:

makeRecognizer(name, details) {

    let eventName = name.toLowerCase();
    let gesture = capitalize(details.recognizer);

    let options = details.options || {};
    options.event = eventName;

    let Recognizer = new Hammer[gesture](options);

    if (details.include) {
      let included = details.include.map((name) => {
        return this.lookup(name);
      });

      RSVP.all(included).then((recognizers) => {
        Recognizer.recognizeWith(recognizers);
      });

    }

    if (details.exclude) {
      let excluded = details.exclude.map((name) => {
        return this.lookup(name);
      });

      RSVP.all(excluded).then((recognizers) => {
        Recognizer.requireFailure(recognizers);
      });

    }

    this.register(name, Recognizer);

  },
runspired commented 9 years ago

To make a recognizer for the ember library, you do this


export default {
  include: ['tap'], //an array of recognizers to recognize with.
  exclude: [], //an array of recognizers that must first fail
  options: {
    taps: 2  // the settings to pass to the recognizer, event will be added automatically
  },
  recognizer: 'tap' // `tap|press|pan|swipe|rotate|pinch` the base Hammer recognizer to use
};
arschmitz commented 9 years ago

So i had been thinking about something along these lines already because of the direction we decided for touch-action using a MO this is how pep decided where to emit pointer events as well. So i think a declaritive approach is something i want to do just need to find right approach

runspired commented 9 years ago

:+1: