Skip to content

Instantly share code, notes, and snippets.

@matori
Last active August 29, 2015 14:19
Show Gist options
  • Select an option

  • Save matori/9c6f2d6cfa14fde6b2d5 to your computer and use it in GitHub Desktop.

Select an option

Save matori/9c6f2d6cfa14fde6b2d5 to your computer and use it in GitHub Desktop.
Swipe
"use strict"
normalize = ->
nomalizedEvents = ["start", "move", "end", "cancel"]
touchEvents = ["touchstart", "touchmove", "touchend", "touchcancel"]
MSPointerEvents = ["MSPointerDown", "MSPointerMove", "MSPointerUp", "MSPointerCancel"]
pointerEvents = ["pointerdown", "pointermove", "pointerup", "pointercancel"]
mouseEvents = ["mousedown", "mousemove", "mouseup", null]
if window.Modernizr and window.Modernizr.hasOwnProperty "touch"
modernizrTouchDetect = window.Modernizr.touch
supportTouch = modernizrTouchDetect or (("ontouchstart" of window) or window.DocumentTouch and document instanceof DocumentTouch)
supportMSPointer = window.navigator.msPointerEnabled and not window.navigator.pointerEnabled
supportPointer = window.navigator.pointerEnabled
pointerType = ""
if supportPointer
supportEvents = pointerEvents
pointerType = "pointer"
else if supportMSPointer
supportEvents = MSPointerEvents
pointerType = "mspointer"
else if supportTouch
supportEvents = touchEvents
pointerType = "touch"
else
supportEvents = mouseEvents
pointerType = "mouse"
eventType = {}
for type, idx in nomalizedEvents
eventType[type] = supportEvents[idx]
eventType["type"] = pointerType
eventType
module.exports = normalize()
"use strict"
pointerEvents = require "./normalize-pointer-event-type"
isPointer = pointerEvents.type is "pointer"
isMSPointer = pointerEvents.type is "mspointer"
isTouch = pointerEvents.type is "touch"
isMouse = pointerEvents.type is "mouse"
class Pointer
defaultConfig =
threshold: 100 # スワイプしたと判断できる最小移動距離
allowedTime: 500 # スワイプしたと判断できる制限時間
touchAction: "none" # PointerEvents 向けの CSS `touch-action` プロパティの値
throttle: 64 # move 時のスロットルタイム
stopPropagation: false # `event.stopPropagation` するかどうか
mouseFallback: true # `mousedown`, `mousemove`, `mouseup` でのフォールバックをするかどうか
startCallback: (event, direction, distance) ->
moveCallback: (event, direction, distance) ->
endCallback: (event, direction, distance, isSwipe) ->
constructor: (elements, userConfig) ->
if "jquery" of elements
throw "Pointer class does not allow jQuery object."
@destroy()
return
@elements = if elements.hasOwnProperty "length" then elements else [elements]
@config = @_setConfig userConfig
if @config.mouseFallback is false and isMouse
@destroy()
return
@_reset()
@_init()
_reset: ->
@throttleTimer = undefined
@isPointerDown = undefined
@startTime = undefined
@elapsedTime = undefined
@startX = undefined
@startY = undefined
@isSwipe = undefined
@direction =
x: undefined
y: undefined
@distance =
x: undefined
y: undefined
return
_setConfig: (userConfig) ->
config = {}
for configKey, configVal of defaultConfig
config[configKey] = configVal
for userConfigKey, userConfigVal of userConfig
config[userConfigKey] = userConfigVal
config
_getPointerObj: (evt) ->
return if isTouch then evt.changedTouches[0] else evt
_onPointerStart: (evt) =>
evt.preventDefault()
if @config.stopPropagation
evt.stopPropagation()
pointerObj = @_getPointerObj evt
@throttleTimer = null
@isPointerDown = true
@startTime = new Date().getTime()
@startX = pointerObj.pageX
@startY = pointerObj.pageY
@isSwipe = false
@direction =
x: "default"
y: "default"
@distance =
x: 0
y: 0
@config.startCallback evt, @direction, @distance
_onPointerMove: (evt) =>
if not @isPointerDown
return
if not @throttleTimer
@throttleTimer = setTimeout =>
@throttleTimer = null
evt.preventDefault()
if @config.stopPropagation
evt.stopPropagation()
pointerObj = @_getPointerObj evt
@distance.x = pointerObj.pageX - @startX
@distance.y = pointerObj.pageY - @startY
@direction.x = if @distance.x < 0 then "left" else "right"
@direction.y = if @distance.y < 0 then "up" else "down"
@config.moveCallback evt, @direction, @distance
, @config.throttle
_onPointerEnd: (evt) =>
evt.preventDefault()
if @config.stopPropagation
evt.stopPropagation()
@throttleTimer = null
@isPointerDown = false
@elapsedTime = new Date().getTime() - @startTime
if @elapsedTime <= @config.allowedTime
if Math.abs(@distance.x) >= @config.threshold or Math.abs(@distance.y) >= @config.threshold
@isSwipe = true
@config.endCallback evt, @direction, @distance, @isSwipe
_onPointerCancel: (evt) ->
evt.preventDefault()
if config.stopPropagation
evt.stopPropagation()
@_reset()
_attachEvents: =>
for element in @elements
element.addEventListener pointerEvents.start, @_onPointerStart, false
element.addEventListener pointerEvents.move, @_onPointerMove, false
element.addEventListener pointerEvents.end, @_onPointerEnd, false
if not isMouse
element.addEventListener pointerEvents.cancel, @_onPointerCancel, false
_detachEvents: ->
for element in @elements
element.removeEventListener pointerEvents.start, @_onPointerStart, false
element.removeEventListener pointerEvents.move, @_onPointerMove, false
element.removeEventListener pointerEvents.end, @_onPointerEnd, false
if not isMouse
element.removeEventListener pointerEvents.cancel, @_onPointerCancel, false
_init: ->
if isPointer or isMSPointer
for element in @elements
element.style.touchAction = element.style.msTouchAction = @config.touchAction
@_attachEvents()
destroy: ->
@_detachEvents()
@_reset()
if isPointer or isMSPointer
for element in @elements
element.style.touchAction = element.style.msTouchAction = ""
@elements = undefined
@config = undefined
module.exports = Pointer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment