Skip to content
Permalink
Browse files

Fixed all last known pinch/pan/rotate bugs

  • Loading branch information...
Koen Bok
Koen Bok committed Jan 28, 2016
1 parent c82d1b2 commit f201e2f312399bba2101c0f75e9b12893d3e8e75
Showing with 58 additions and 45 deletions.
  1. +26 −26 framer/GestureInputRecognizer.coffee
  2. +16 −9 framer/LayerDraggable.coffee
  3. +10 −6 framer/LayerPinchable.coffee
  4. +6 −4 framer/Utils.coffee
@@ -67,17 +67,18 @@ class exports.GestureInputRecognizer
@_process(@_getGestureEvent(event))

touchend: (event) =>

# Only fire if there are no fingers left on the screen
return unless (event.touches.length == 0) or (event.touches.length == event.changedTouches.length)


if Utils.isTouch()
return unless (event.touches.length == 0)
else
return unless (event.touches.length == event.changedTouches.length)

@em.wrap(window).removeEventListener("touchmove", @touchmove)
@em.wrap(window).removeEventListener("touchend", @touchend)
@em.wrap(window).removeEventListener("webkitmouseforcechanged", @_updateMacForce)

event = @_getGestureEvent(event)

@_process(event)

for eventName, value of @session.started
@["#{eventName}end"](event) if value
@@ -280,7 +281,6 @@ class exports.GestureInputRecognizer
else
@pan(event)


# Detect pinch, rotate and scale events

# Stop panning if we go from 2 to 1 finger
@@ -306,16 +306,9 @@ class exports.GestureInputRecognizer

@session.lastEvent = event

_getEventPoint: (event) ->
if event.touches?.length > 1
return Utils.pointCenter(
@_getTouchPoint(event, 0),
@_getTouchPoint(event, 1))
if event.touches?.length == 1
return @_getTouchPoint(event, 0)
return point =
x: event.pageX
y: event.pageY
_getEventPoint: (event) ->
return @_getTouchPoint(event, 0) if event.touches.length
return {x:event.pageX ,y:event.pageY}

_getGestureEvent: (event) ->

@@ -341,6 +334,9 @@ class exports.GestureInputRecognizer

fingers: event.touches?.length or 0 # Number of fingers used √
touchCenter: @_getEventPoint(event) # Center between two fingers √
touchCenterStart: @_getEventPoint(event) #
touchCenterDelta: null
touchCenterOffset: @_getEventPoint(event) #
touchOffset: {x:0, y:0} # Offset between two fingers √
touchDistance: 0 # Distance between two fingers √
scale: 1 # Scale value from two fingers √
@@ -352,10 +348,9 @@ class exports.GestureInputRecognizer
event.start = @session.startEvent.point
event.offset = Utils.pointSubtract(event.point, event.start)
event.offsetTime = event.time - @session.startEvent.time
event.offsetAngle = Utils.pointAngle(
@_getTouchPoint(@session.startEvent, 0),
@_getTouchPoint(event, 0))
event.offsetAngle = Utils.pointAngle(@session.startEvent.point, event.point)
event.offsetDirection = @_getDirection(event.offset)
event.touchCenterStart = @session.startEvent.touchCenter

# Properties relative to the previous event
if @session?.lastEvent
@@ -370,7 +365,8 @@ class exports.GestureInputRecognizer
touchPointA = @_getTouchPoint(event, 0)
touchPointB = @_getTouchPoint(event, 1)
event.touchCenter = Utils.pointCenter(touchPointB, touchPointA)
event.touchDistance = Utils.pointDistance(touchPointA, touchPointB)
event.touchCenterOffset = Utils.pointSubtract(event.touchCenter, event.touchCenterStart)
event.touchDistance = Utils.pointDistance(touchPointA, touchPointB)
event.rotation = Utils.pointAngle(touchPointA, touchPointB)

# Special cases
@@ -386,12 +382,16 @@ class exports.GestureInputRecognizer
event.scale = event.touchDistance / @session.started.pinch.touchDistance
event.scaleDirection = @_getScaleDirection(event.scale - @session.lastEvent.scale)

# Sanitize the rotation
# if @session?.lastEvent
# if event.rotation - @session.lastEvent.rotation > 180
# event.rotation -= 360
# if event.rotation - @session.lastEvent.rotation < 180
# event.rotation += 360
# If this is a pinch end event, there was no movement so we use the last one
if not event.scaleDirection and @session?.lastEvent
event.scaleDirection = @session.lastEvent.scaleDirection

# For delta we switch to center-compare if there are two fingers
if @session?.lastEvent
if event.fingers != @session.lastEvent.fingers == 2
event.delta = {x:0, y:0}
if event.fingers == 2 and @session.lastEvent.fingers == 2
event.delta = Utils.pointSubtract(event.touchCenter, @session.lastEvent.touchCenter)

# Convert point style event properties to dom style:
# event.delta -> event.deltaX, event.deltaY
@@ -158,12 +158,16 @@ class exports.LayerDraggable extends BaseClass
x: touchEvent.clientX - @_correctedLayerStartPoint.x
y: touchEvent.clientY - @_correctedLayerStartPoint.y

@_point = @layer.point

@emit(Events.DragStart, event)

_touchMove: (event) =>

return unless @enabled

@_lastEvent = event

event.preventDefault()
event.stopPropagation() unless @propagateEvents

@@ -174,11 +178,13 @@ class exports.LayerDraggable extends BaseClass
y: touchEvent.clientY
t: Date.now() # We don't use timeStamp because it's different on Chrome/Safari

# See if horizontal/vertical was set and set the offset
point = {}

scaleX = (1 / @layer.canvasScaleX() * @layer.scale * @layer.scaleX)
scaleY = (1 / @layer.canvasScaleY() * @layer.scale * @layer.scaleY)

point = @layer.point
point.x = @_layerStartPoint.x + (event.offset.x * (1 / @layer.canvasScaleX() * @layer.scale * @layer.scaleX)) if @horizontal
point.y = @_layerStartPoint.y + (event.offset.y * (1 / @layer.canvasScaleY() * @layer.scale * @layer.scaleY)) if @vertical
point.x = @_point.x + (event.delta.x * scaleX) if @horizontal
point.y = @_point.y + (event.delta.y * scaleY) if @vertical

# Constraints and overdrag
point = @_constrainPosition(point, @_constraints, @overdragScale) if @_constraints
@@ -192,11 +198,6 @@ class exports.LayerDraggable extends BaseClass
point.x = @_layerStartPoint.x if @_directionLockEnabledX
point.y = @_layerStartPoint.y if @_directionLockEnabledY

# Pixel align all moves
if @pixelAlign
point.x = parseInt(point.x) if @horizontal
point.y = parseInt(point.y) if @vertical

# Update the dragging status
if point.x isnt @_layerStartPoint.x or point.y isnt @_layerStartPoint.y
@_isDragging = true
@@ -206,6 +207,12 @@ class exports.LayerDraggable extends BaseClass
if @isDragging
@emit(Events.DragWillMove, event)

@_point = _.clone(point)

if @pixelAlign
point.x = parseInt(point.x) if @horizontal
point.y = parseInt(point.y) if @vertical

@layer.point = @updatePosition(point)

if @isDragging
@@ -64,13 +64,17 @@ class exports.LayerPinchable extends BaseClass
@layer.x -= xDiff
@layer.y -= yDiff

# This is not a great fix, we should add this in the draggable. Basically
# we need to account in the draggable for a change of origin relative to
# the dragging start offset.
# # This is not a great fix, we should add this in the draggable. Basically
# # we need to account in the draggable for a change of origin relative to
# # the dragging start offset.

if @layer._draggable
@layer.draggable._layerStartPoint.x -= xDiff
@layer.draggable._layerStartPoint.y -= yDiff
# if @layer._draggable
# @layer.draggable._originDiff ?= {x:0, y:0}
# @layer.draggable._originDiff.x += xDiff
# @layer.draggable._originDiff.y += yDiff


# print "_centerOrigin"

_pinchStart: (event) =>
@_reset()
@@ -548,10 +548,10 @@ Utils.loadImage = (url, callback, context) ->

# Point

Utils.pointDivide = (pointA, pointB, fraction) ->
Utils.pointDivide = (point, fraction) ->
return point =
x: (pointA.x + pointB.x) / fraction
y: (pointA.y + pointB.y) / fraction
x: point.x / fraction
y: point.y / fraction

Utils.pointAdd = (pointA, pointB) ->
return point =
@@ -607,7 +607,9 @@ Utils.pointInFrame = (point, frame) ->
return true

Utils.pointCenter = (pointA, pointB) ->
return Utils.pointDivide(pointA, pointB, 2)
return point =
x: (pointA.x + pointB.x) / 2
y: (pointA.y + pointB.y) / 2

Utils.pointAngle = (pointA, pointB) ->
return Math.atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180 / Math.PI

0 comments on commit f201e2f

Please sign in to comment.
You can’t perform that action at this time.