Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gesture support using Hammer.js #244

Merged
merged 18 commits into from
Jan 8, 2016
Merged

Gesture support using Hammer.js #244

merged 18 commits into from
Jan 8, 2016

Conversation

jchavarri
Copy link
Contributor

Ongoing work to be discussed, don't merge! :)

Related to issue #107. Before I keep working on it, I would like to know your thoughts.

Here's a first attempt to integrate Hammer with Framer, so we can recognize pinches, rotations, panning, etc. From the few tests I've done it seems to work well together with the existing events. I have tried to make both gesture and browser events transparent for the final user, even if behind the scenes they are two completely different things.

I see this as an exercise to explore how gesture events could be handled in Framer. I went with Hammer because they already deal with a lot of corner cases and gives a good idea on how to solve the gesture recognition in an elegant way. But maybe in the future this dependency could be removed by implementing the functionality in Framer?

This is an overview on how Hammer implements classes / concepts:

  • Input: everything that can be consider a source of a gestural event. Subclasses: MouseInput, TouchInput, PointerEventInput, etc. This is also the class calculating velocities, directions and every extra info of the events.
  • Recognizer: The gestures themselves. Subclasses: PanRecognizer, PinchRecognizer, etc. The base class contains a state machine to follow the gesture evolution.
  • Manager: Assign handlers (or listeners) to recognizers based on a specific device input. It has similar responsibilities as Framer's EventManagerElement.

So what I've done for now is adding a GestureManager class that wraps Hammer functionality, and creates recognizers as they are requested depending on the gestures the layer is listening to.

Still to do:

  • Add the remaining events to the list (rotate, pan, etc)
  • Implement removeEventListener: this one is a bit tricky: after removing a listener, we should remove the given gesture recognizer if there are no more events remaining of that type attached to the layer.
  • Make complex examples: using ScrollComponent, PageComponent, sublayers, etc
  • Write tests (are there any existing tests that target events, listeners and handlers?)

Side note: if this PR finally see the light, it would be very nice to integrate this Touch Emulator into Framer Studio, so users could emulate multi touch gestures using their keyboard. That would bring Framer a step closer to the iPhone Simulator!! :)

Finally, a small example that you can copy & paste:

layerA = new Layer
    width: Screen.width
    height: Screen.height
    image: "http://lorempixel.com/900/900/"
# With draggable true some events are more difficult to trigger, but they work
layerA.draggable = false
initialScale = 0
layerA.on Events.PinchStart, (ev) ->
    # TODO layerA.origin = 
    initialScale = layerA.scale
layerA.on Events.PinchEnd, (ev) ->
    if layerA.scale < 1
        layerA.animate
            properties:
                scale: 1
            curve: "spring(300, 40, 0)"
layerA.on Events.Pinch, (ev) ->
    layerA.scale = ev.scale*initialScale
    textLayer.html = "Zoom: " + layerA.scale.toFixed(1)
layerA.on Events.Press, (ev) ->
    textLayer.html = "Long press!"
    layerA.scale = ev.scale
layerA.on Events.SwipeRight, (ev) ->
    textLayer.html = "Swipe right!"
layerA.on Events.SwipeLeft, (ev) ->
    textLayer.html = "Swipe left!"
layerA.on Events.TouchStart, (ev) ->
    textLayer.html = "Touch start!"

textLayer = new Layer
    width: Screen.width
    height: 100
    html: "Zoom: 1.0"
textLayer.style = 
    "font-size" : "50px"
    "line-height" : "100px"
    "font-weight" : "600"
    "text-align" : "center"

@koenbok
Copy link
Owner

koenbok commented Oct 3, 2015

Ho Shit @jchavarri I totally missed this. This is awesome!

@jchavarri
Copy link
Contributor Author

Thanks! :) Do you think this is the right approach to add other gestures to Framer? If yes, I would keep adding the remaining stuff on the todo list in order to finish this PR.

@koenbok
Copy link
Owner

koenbok commented Nov 3, 2015

Yeah this looks really good. I'd love to finish this up and add it.

@jchavarri
Copy link
Contributor Author

👍 I'll keep working on this branch and ping you in this thread once it's "ready for review".

@koenbok
Copy link
Owner

koenbok commented Nov 3, 2015

Awesome!

@jchavarri
Copy link
Contributor Author

@koenbok So I think this is ready for review! I didn't add any testing to it as I don't have any clue on how to test this kind of gestural interaction 😅. I saw that the HammerJS guys have created a "Simulator". Maybe we could add something like this to test it?

In order to test all the available gestures and events, I have created a Framer project. You can test it here, the code for this demo is on Github.

So the next things I'm interested in adding are:

  • Tests (somehow)
  • Using something similar to Touch Emulator to have double touch in the browser

Let me know your thoughts! :)

@koenbok
Copy link
Owner

koenbok commented Nov 30, 2015

Hey @jchavarri I'm going to land a big one first: https://github.com/koenbok/Framer/tree/context-freeze-restore.

This will refactor a bunch of event and context stuff. The main reason is that all the event/dom handling became a huge mess, and I wanted to clean up the context api. I think the implications for this pr are mostly renames (for example EventManager vs DOMEventManager).

@jordandobson
Copy link
Contributor

👏🏻
On Sun, Nov 29, 2015 at 9:09 PM Koen Bok [email protected] wrote:

Hey @jchavarri https://github.com/jchavarri I'm going to land a big one
first: https://github.com/koenbok/Framer/tree/context-freeze-restore

This will refactor a bunch of event and context stuff. I think the
implications for this pr are mostly renames.


Reply to this email directly or view it on GitHub
#244 (comment).

@jchavarri
Copy link
Contributor Author

Ok, cool! I'll keep an eye on the context-free-restore branch so I can merge with it once it's ready.

@koenbok
Copy link
Owner

koenbok commented Dec 9, 2015

Hey @jchavarri I'm ready with https://github.com/koenbok/Framer/tree/context-freeze-restore. Wanna give it a try?

@jchavarri
Copy link
Contributor Author

Sure @koenbok, I will be more than happy to wrap this up! I think I can have something by tomorrow.

Side note: regarding the tests, I saw the HammerJS team uses both manual and unit tests:

  • Manual tests are basically webpages with a lot of features that allow them to quickly check if things are working as they're supposed to. I guess this is something similar to what I did in the framer-gestures.framer project.
  • Unit tests are done using a Simulator that can trigger complex gestures like pinch, etc.

Do you think adding any of these kinds of tests to this PR is worth it?

@jornvandijk
Copy link
Collaborator

@jchavarri You're and utter legend. I can't wait for this to drop.

@jchavarri
Copy link
Contributor Author

@jornvandijk Sorry, but I have to disagree :) you and @koenbok are the original rockstars that started all this top-notch-designed hyper-elegantly-coded prototyping madness! 😊 I am also eager to see what you and the awesome Framer community do with these new events...

So, everything has been merged and integrated with branch context-freeze-restore and the brand new DOMElementManager. I have tested as far as I could and everything seems to work. I wanted to share some points to know your thoughts:

  • I have created a new file LayerEventsTest.coffee where I copied all the previous events tests + some new gestures events tests. The reason is that the file LayerTest.coffee had around 1k lines and it seemed hard to read to me. I hope that's ok!
  • There's now these new "gesture events" object that are returned with every callback attached to a gesture event. I think these differences between "regular events" and "gesture events" callback objects should be reflected on the Framer docs, right? –the HammerJS docs can help to know which information is being passed to the gesture events callback objects–.
  • If you think it can help testing this feature, there's also the companion .framer project to test manually all the gesture events and different cases

I still have pending the addition of the HammerJS Simulator class -or something similar- in order to add more tests for the gesture events.

Let me know your thoughts!

@jornvandijk
Copy link
Collaborator

Thanks for the kind words! Yeah, this is gonna be a substantial update to our docs. Will take some time to write it all out in an easy/understandable way.

@koenbok koenbok changed the title [discussion] First steps on gesture integration using Hammer Gesture support using Hammer.js Dec 14, 2015
@jchavarri jchavarri mentioned this pull request Dec 15, 2015
@jchavarri
Copy link
Contributor Author

Merged with master. Updated to add gesture event helpers (see PR #272 )

@koenbok
Copy link
Owner

koenbok commented Jan 7, 2016

Hmpf, I can't update the branch :-/ @jchavarri could you give me write access to your Framer repo? I think that is the only way to keep the PR intact.

@koenbok
Copy link
Owner

koenbok commented Jan 7, 2016

It would also be great to have some Framer Studio projects with examples of common stuff.

@jchavarri
Copy link
Contributor Author

@koenbok Access granted! :)

Related to the examples, can they be the same examples included in the framer-gestures.framer repo I set up? Or maybe they should be splitted into a separate .framer project each? If they need to be splitted into separate projects, it won't take long as each example is already in a separate file/module.

This is a capture of the main screen that points to the examples I created in that repo:

framer-gestures

@koenbok
Copy link
Owner

koenbok commented Jan 8, 2016

Woop yeah that's prefect.

koenbok added a commit that referenced this pull request Jan 8, 2016
Gesture support using Hammer.js
@koenbok koenbok merged commit d7571f8 into koenbok:master Jan 8, 2016
@koenbok
Copy link
Owner

koenbok commented Jan 8, 2016

Beng!

@jchavarri
Copy link
Contributor Author

image

@jornvandijk
Copy link
Collaborator

🚀

@jchavarri jchavarri deleted the gestures branch January 11, 2016 21:23
@johanneseckert
Copy link

This is awesome, and I was really hoping this would happen someday!
I'm just starting to look at the examples … I like that these new events have all of HammerJS's ev object available during the event. I'm wondering, for consistency reasons, should this object be available for all other/regular events, like drag or click, as well?
Reason is, some of the things inside ev are really interesting, such as ev.direction or ev.angle or ev.distance — those can be extremly useful for drag events

@jchavarri
Copy link
Contributor Author

That's a very good point. These are my thoughts on both observations:

1. Consistency

I think these are all the event types that can be passed to a listener on Framer atm:

  • TouchEvent: passed to listeners of regular DOM events on a mobile device
  • MouseEvent: passed to listeners of regular DOM events on a "non-touch" device. Even if you use on Events.TouchEnd or similar, a MouseEvent will be returned
  • Event aka "HammerEvent": passed to listeners of gesture events.

Hammer already takes care of these differences between TouchEvent, MouseEvent and PointerEvent by abstracting them into an Input class. Quoting from the site:

Input Events
Hammer maps all types of input (mousedown, mousemove, touchmove, pointercancel) to these contants.
| Name | Value
INPUT_START 1
INPUT_MOVE 2
INPUT_END 4
INPUT_CANCEL 8

Apparently there's a hammer.input secret event that is triggered for each of these constants, so maybe we can use all this to unify the events passed to the listeners.

NOTE: I'm afraid there will always be events like MouseWheel that won't be part of the unified event party, as they are very platform specific.

2. LayerDraggable

This one is simpler to tackle :) I think that just by replacing Events.TouchMove for Events.PanMove on the LayerDraggable class a HammerEvent object would be passed to the listeners.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants