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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions framer/Color.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,13 @@ inputData = (color, g, b, alpha) ->
if typeof color == "string"
color = stringToObject(color)

if !color
color =
r:0
g:0
b:0
a:0

if color.hasOwnProperty("type")
type = color.type

Expand Down
3 changes: 3 additions & 0 deletions framer/Components/ScrollComponent.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,9 @@ class exports.ScrollComponent extends Layer

wrapComponent = (instance, layer, options = {correct:true}) ->

if not (layer instanceof Layer)
throw new Error("ScrollComponent.wrap expects a layer, not #{layer}. Are you sure the layer exists?")

# This function wraps the given layer into a scroll or page component. This is
# great for importing from Sketch or Photoshop.

Expand Down
14 changes: 11 additions & 3 deletions framer/DOMEventManager.coffee
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{_} = require "./Underscore"
{EventEmitter} = require "./EventEmitter"
{GestureManagerElement} = require "./GestureManager"

Utils = require "./Utils"

Expand All @@ -8,14 +9,21 @@ EventManagerIdCounter = 0
class DOMEventManagerElement extends EventEmitter

constructor: (@element) ->
@_elementGestureManager = new GestureManagerElement(@element)

addListener: (eventName, listener, capture=false) ->
super(eventName, listener)
@element.addEventListener(eventName, listener, capture)
if Events.isGestureEvent eventName
@_elementGestureManager.addEventListener(eventName, listener, capture)
else
@element.addEventListener(eventName, listener)

removeListener: (eventName, listener) ->
super(eventName, listener)
@element.removeEventListener(eventName, listener)
if Events.isGestureEvent eventName
@_elementGestureManager.removeEventListener(eventName, listener)
else
@element.removeEventListener(eventName, listener)

# Keep the DOM API working
addEventListener: @::addListener
Expand All @@ -38,4 +46,4 @@ class exports.DOMEventManager

reset: ->
for element, elementEventManager of @_elements
elementEventManager.removeAllListeners()
elementEventManager.removeAllListeners()
49 changes: 49 additions & 0 deletions framer/Events.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,62 @@ Events.AnimationDidStart = "start"
Events.AnimationDidStop = "stop"
Events.AnimationDidEnd = "end"

# Gesture events
_gestures = []

# Pan
_gestures.push Events.Pan = "pan" # This event includes all the other Pan events
_gestures.push Events.PanStart = "panstart"
_gestures.push Events.PanMove = "panmove"
_gestures.push Events.PanEnd = "panend"
_gestures.push Events.PanCancel = "pancancel"
_gestures.push Events.PanLeft = "panleft"
_gestures.push Events.PanRight = "panright"
_gestures.push Events.PanUp = "panup"
_gestures.push Events.PanDown = "pandown"

# Pinch
_gestures.push Events.Pinch = "pinch" # This event includes all the other Pinch events
_gestures.push Events.PinchStart = "pinchstart"
_gestures.push Events.PinchMove = "pinchmove"
_gestures.push Events.PinchEnd = "pinchend"
_gestures.push Events.PinchCancel = "pinchcancel"
_gestures.push Events.PinchIn = "pinchin"
_gestures.push Events.PinchOut = "pinchout"

# Press
_gestures.push Events.Press = "press"
_gestures.push Events.PressUp = "pressup"

# Rotate
_gestures.push Events.Rotate = "rotate" # This event includes all the other Rotate events
_gestures.push Events.RotateStart = "rotatestart"
_gestures.push Events.RotateMove = "rotatemove"
_gestures.push Events.RotateEnd = "rotateend"
_gestures.push Events.RotateCancel = "rotatecancel"

# Swipe
_gestures.push Events.Swipe = "swipe"
_gestures.push Events.SwipeLeft = "swipeleft"
_gestures.push Events.SwipeRight = "swiperight"
_gestures.push Events.SwipeUp = "swipeup"
_gestures.push Events.SwipeDown = "swipedown"

# Tap
_gestures.push Events.Tap = "tap"
_gestures.push Events.SingleTap = "singletap"
_gestures.push Events.DoubleTap = "doubletap"

# Scroll events
Events.Scroll = "scroll"

# Image events
Events.ImageLoaded = "load"
Events.ImageLoadError = "error"

Events.isGestureEvent = (eventName) ->
return eventName in _gestures

# Extract touch events for any event
Events.touchEvent = (event) ->
touchEvent = event.touches?[0]
Expand Down
143 changes: 143 additions & 0 deletions framer/GestureManager.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
Hammer = require "hammerjs"

class exports.GestureManagerElement

constructor: (@element) ->

@_events = {}
@_manager = null

_getEventFamily: (eventName) ->

eventFamily = undefined

switch eventName

when Events.Pan, Events.PanStart, Events.PanMove, Events.PanEnd, Events.PanCancel, Events.PanLeft, Events.PanRight, Events.PanUp, Events.PanDown
eventFamily = Events.Pan

when Events.Pinch, Events.PinchStart, Events.PinchMove, Events.PinchEnd, Events.PinchCancel, Events.PinchIn, Events.PinchOut
eventFamily = Events.Pinch

when Events.Press, Events.PressUp
eventFamily = Events.Press

when Events.Rotate, Events.RotateStart, Events.RotateMove, Events.RotateEnd, Events.RotateCancel
eventFamily = Events.Rotate

when Events.Swipe, Events.SwipeLeft, Events.SwipeRight, Events.SwipeUp, Events.SwipeDown
eventFamily = Events.Swipe

when Events.Tap, Events.SingleTap
eventFamily = Events.Tap

when Events.DoubleTap # Tap and DoubleTap need different type of recognizers
eventFamily = Events.DoubleTap

else

return eventFamily


_getDependentRecognizersForEventFamily: (eventFamily) ->

# We need to add simultaneous recognition for certain gestures to be detected together
# See http://hammerjs.github.io/recognize-with/
# All these dependencies come from https://cdn.rawgit.com/hammerjs/hammer.js/master/tests/manual/visual.html
existingRecognizers = []

switch eventFamily

when Events.Pan # Pan depends on Swipe, Rotate and Pinch
if swipe = @_manager.get(Events.Swipe)
existingRecognizers.push(swipe)
if rotate = @_manager.get(Events.Rotate)
existingRecognizers.push(rotate)
if pinch = @_manager.get(Events.Pinch)
existingRecognizers.push(pinch)

when Events.Swipe # Swipe depends on Pan
if pan = @_manager.get(Events.Pan)
existingRecognizers.push(pan)

when Events.Rotate # Rotate depends on Pan and Pinch
if pan = @_manager.get(Events.Pan)
existingRecognizers.push(pan)
if pinch = @_manager.get(Events.Pinch)
existingRecognizers.push(pinch)

when Events.Pinch # Pinch depends on Pan and Rotate
if pan = @_manager.get(Events.Pan)
existingRecognizers.push(pan)
if rotate = @_manager.get(Events.Pinch)
existingRecognizers.push(rotate)

when Events.DoubleTap # DoubleTap depends on Tap
if tap = @_manager.get(Events.Tap)
existingRecognizers.push(tap)

else

return existingRecognizers


addEventListener: (eventName, listener) ->
#Lazy creation
@_manager ?= new Hammer.Manager(@element)

validEvent = true
recognizer = undefined

# Get event family to add different recognizers
eventFamily = @_getEventFamily(eventName)

# Add recognizer if needed
switch eventFamily

when Events.Pan
if not @_manager.get(Events.Pan)
recognizer = new Hammer.Pan({ event: Events.Pan})

when Events.Pinch
if not @_manager.get(Events.Pinch)
recognizer = new Hammer.Pinch({ event: Events.Pinch})

when Events.Press
if not @_manager.get(Events.Press)
recognizer = new Hammer.Press({ event: Events.Press})

when Events.Rotate
if not @_manager.get(Events.Rotate)
recognizer = new Hammer.Rotate({ event: Events.Rotate})

when Events.Swipe
if not @_manager.get(Events.Swipe)
recognizer = new Hammer.Swipe({ event: Events.Swipe})

when Events.Tap
if not @_manager.get(Events.Tap)
recognizer = new Hammer.Tap({ event: Events.Tap})

when Events.DoubleTap
if not @_manager.get(Events.DoubleTap)
recognizer = new Hammer.Tap({ event: Events.DoubleTap, taps: 2})

else
validEvent = false

if recognizer
# Add other recognizers if they existed already
existingRecognizers = @_getDependentRecognizersForEventFamily(eventFamily)
if existingRecognizers.length > 0
@_manager.add(recognizer).recognizeWith(existingRecognizers)
else
@_manager.add recognizer

if validEvent
@_manager.on eventName, listener

removeEventListener: (eventName, listener) ->
# The EventManager already checks that the listener has been registered
# so we can remove it safely
# -- Should we remove the recognizers as well?? --
@_manager.off eventName, listener
37 changes: 37 additions & 0 deletions framer/Layer.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,43 @@ class exports.Layer extends BaseClass
onDragAnimationDidEnd: (cb) -> @on(Events.DragAnimationDidEnd, cb)
onDirectionLockDidStart: (cb) -> @on(Events.DirectionLockDidStart, cb)

onPan: (cb) -> @on(Events.Pan, cb)
onPanStart: (cb) -> @on(Events.PanStart, cb)
onPanMove: (cb) -> @on(Events.PanMove, cb)
onPanEnd: (cb) -> @on(Events.PanEnd, cb)
onPanCancel: (cb) -> @on(Events.PanCancel, cb)
onPanLeft: (cb) -> @on(Events.PanLeft, cb)
onPanRight: (cb) -> @on(Events.PanRight, cb)
onPanUp: (cb) -> @on(Events.PanUp, cb)
onPanDown: (cb) -> @on(Events.PanDown, cb)

onPinch: (cb) -> @on(Events.Pinch, cb)
onPinchStart: (cb) -> @on(Events.PinchStart, cb)
onPinchMove: (cb) -> @on(Events.PinchMove, cb)
onPinchEnd: (cb) -> @on(Events.PinchEnd, cb)
onPinchCancel: (cb) -> @on(Events.PinchCancel, cb)
onPinchIn: (cb) -> @on(Events.PinchIn, cb)
onPinchOut: (cb) -> @on(Events.PinchOut, cb)

onPress: (cb) -> @on(Events.Press, cb)
onPressUp: (cb) -> @on(Events.PressUp, cb)

onRotate: (cb) -> @on(Events.Rotate, cb)
onRotateStart: (cb) -> @on(Events.RotateStart, cb)
onRotateMove: (cb) -> @on(Events.RotateMove, cb)
onRotateEnd: (cb) -> @on(Events.RotateEnd, cb)
onRotateCancel: (cb) -> @on(Events.RotateCancel, cb)

onSwipe: (cb) -> @on(Events.Swipe, cb)
onSwipeLeft: (cb) -> @on(Events.SwipeLeft, cb)
onSwipeRight: (cb) -> @on(Events.SwipeRight, cb)
onSwipeUp: (cb) -> @on(Events.SwipeUp, cb)
onSwipeDown: (cb) -> @on(Events.SwipeDown, cb)

onTap: (cb) -> @on(Events.Tap, cb)
onSingleTap: (cb) -> @on(Events.SingleTap, cb)
onDoubleTap: (cb) -> @on(Events.DoubleTap, cb)

##############################################################
## DESCRIPTOR

Expand Down
2 changes: 1 addition & 1 deletion framer/Print.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ exports.print = (args...) ->

printPrefix = "» "
printNode = document.createElement("div")
printNode.innerHTML = _.escape(printPrefix + args.map(Utils.inspect).join(", ")) + "<br>"
printNode.innerHTML = _.escape(printPrefix + args.map((obj) -> Utils.inspect(obj)).join(", ")) + "<br>"
printNode.style["-webkit-user-select"] = "text"
printNode.style["cursor"] = "auto"

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"url": "https://github.com/koenbok/Framer.git"
},
"devDependencies": {
"hammerjs": "^2.0.4",
"eventemitter3": "^1.1.1",
"gulp-util": "^3.0.7",
"husl": "^6.0.1",
Expand Down
1 change: 1 addition & 0 deletions test/tests.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require "./tests/EventEmitterTest"
require "./tests/UtilsTest"
require "./tests/BaseClassTest"
require "./tests/LayerTest"
require "./tests/LayerEventsTest"
require "./tests/LayerStatesTest"
require "./tests/VideoLayerTest"
require "./tests/ImporterTest"
Expand Down
Loading