Skip to content

Commit

Permalink
Merge branch 'feature/add-interval'
Browse files Browse the repository at this point in the history
  • Loading branch information
Yuya Hashimoto committed Apr 12, 2013
2 parents 723327c + 2d27036 commit 2b22e8d
Show file tree
Hide file tree
Showing 4 changed files with 601 additions and 90 deletions.
201 changes: 180 additions & 21 deletions build/coffee/src/flickable.coffee
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
do (root = this, factory = (window, documentd) ->
do (root = this, factory = (window, document) ->
NS = "Flickable"

class Helper
Expand Down Expand Up @@ -133,6 +133,85 @@ do (root = this, factory = (window, documentd) ->
move: if hasTouch then "touchmove" else "mousemove"
end: if hasTouch then "touchend" else "mouseup"
}

# インライン属性で定義された幅の取得がザルでござる〜
# てか 要素の幅の取得、全パターン網羅するのってエグエグなんだなぁ〜
# あー jQuery つかいたい jQuery 最高! 天才! ジーニアス! 頭いい
getWidth: (element) ->
if element is undefined then throw new Error("Element Not Found")

css = window.getComputedStyle(element)
boxSizingVal = undefined
hasBoxSizing = do ->
properties = [
"-webkit-box-sizing"
"-moz-box-sizing"
"-o-box-sizing"
"-ms-box-sizing"
"box-sizing"
]

for prop in properties
if element.style[prop] isnt undefined
boxSizingVal = element.style[prop]
return true
return false

# if not css["width"]
# width = parseFloat(element.style.width.match(/\d+/), 10)
# else if not hasBoxSizing or boxSizingVal is "content-box"
if not hasBoxSizing or boxSizingVal is "content-box"
styleParser = (props) ->
value = []
total = 0

for prop, i in props
if css[prop]
value[i] = parseFloat(css[props[0]].match(/\d+/), 10)
total += value[i]

return total

border = styleParser(["border-right-width", "border-left-width"])
padding = styleParser(["padding-right", "padding-left"])
width = element.scrollWidth + border + padding;
# else if hasBoxSizing and boxSizingVal is "border-box" or not hasBoxSizing
else if element.scrollWidth is 0
width = parseFloat(element.style.width.match(/\d+/), 10)

if not element.style.boxSizing or not element.style.webkitBoxSizing
if element.style.paddingRight then width += parseFloat(element.style.paddingRight.match(/\d+/), 10)
if element.style.paddingLeft then width += parseFloat(element.style.paddingLeft.match(/\d+/), 10)

return width
else
width = element.scrollWidth

getTranslate: (use3d = true, x, y = 0, z = 0) ->
if @opts.use3d then "translate3d(#{x}px, 0, 0)" else "translate(#{x}px, 0)"

# ブラウザのバージョンによって正しいのが取得できなかったりしそうな不安感たっぷりのメソッドである
# なのでもうちょっといい方法あればそれにしたい
getTransitionEndEventName: ->
ua = window.navigator.userAgent.toLowerCase()
match = /(webkit)[ \/]([\w.]+)/.exec(ua) or
/(firefox)[ \/]([\w.]+)/.exec(ua) or
/(msie) ([\w.]+)/.exec(ua) or
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) or []
browser = match[1]
version = parseFloat(match[2], 10)

if browser is "msie" and version >= 10 then browser = "modernIE"

switch browser
when "webkit"
transitionEndName = "webkitTransitionEnd"
when "opera"
transitionEndName = "oTransitionEnd"
when "firefox", "modernIE"
transitionEndName = "transitionend"
else
transitionEndName = undefined

class Flickable
constructor: (element, opts = {}) ->
Expand All @@ -148,20 +227,25 @@ do (root = this, factory = (window, documentd) ->
else if not @el
throw new Error("Element Not Found")


# Set Options
@distance = null
@maxPoint = null
@gestureStart = false
@currentPoint = @currentX = @maxX = 0
@gestureStart = @didCloneNode = false

@currentPoint = @currentX = @maxX = 0
@scrolling = @moveReady = @startPageX = @startPageY = @basePageX = @startTime = null
@distance = @maxPoint = @timerId = @scrolling =
@moveReady = @startPageX = @startPageY = @basePageX = @startTime = null

@opts.use3d = if @opts.disable3d then false else @support.transform3d
@opts.useJsAnimate = false

@opts.disableTouch = @opts.disableTouch or false
@opts.disable3d = @opts.disable3d or false

@opts.autoPlay = @opts.autoPlay or false
# @opts.interval = @opts.interval or 6600
# @opts.interval = @opts.interval or 500
@opts.interval = @opts.interval or 2500
@opts.loop = @opts.loop or if @opts.autoPlay then true else false

@opts.transition = @opts.transition or {}
@opts.transition =
timingFunction: @opts.transition["timingFunction"] or "cubic-bezier(0.23, 1, 0.32, 1)"
Expand All @@ -187,9 +271,13 @@ do (root = this, factory = (window, documentd) ->
@gestureStart = false
, false

@refresh()
@el.addEventListener(@events.start, @, false)

if @opts.autoPlay then @_startAutoPlay()
if @opts.loop then @_cloneNode()

@refresh()

handleEvent: (event) ->
switch event.type
when @events.start
Expand All @@ -202,6 +290,8 @@ do (root = this, factory = (window, documentd) ->
@_click(event)

refresh: ->
@_setTotalWidth()

getMaxPoint = =>
childNodes = @el.childNodes
itemLength = 0
Expand All @@ -227,23 +317,15 @@ do (root = this, factory = (window, documentd) ->

toPrev: ->
if not @hasPrev() then return

@moveToPoint(@currentPoint - 1)

toNext: ->
if not @hasNext() then return

@moveToPoint(@currentPoint + 1)

moveToPoint: (point = @currentPoint, duration = @opts.transition["duration"]) ->
beforePoint = @currentPoint

if point < 0
@currentPoint = 0
else if point > @maxPoint
@currentPoint = @maxPoint
else
@currentPoint = parseInt(point, 10)
beforePoint = @currentPoint
@currentPoint = if point < 0 then 0 else if point > @maxPoint then @maxPoint else parseInt(point, 10)

if @support.cssAnimation
@helper.setStyle @el,
Expand All @@ -255,11 +337,12 @@ do (root = this, factory = (window, documentd) ->

if (beforePoint isnt @currentPoint)
@helper.triggerEvent(@el, "flpointmove", true, false)
if @opts.loop then @_loop()

_setX: (x, duration = @opts.transition["duration"]) ->
@currentX = x

if @support.cssAnimation
if @support.cssAnimation and not @browser.isLegacy
@helper.setStyle @el,
transform: @_getTranslate(x)
else if @opts.useJsAnimate
Expand All @@ -270,6 +353,12 @@ do (root = this, factory = (window, documentd) ->
_touchStart: (event) ->
if @opts.disableTouch or @gestureStart then return

if @opts.loop
if @currentPoint is @maxPoint
@moveToPoint(1, 0)
else if @currentPoint is 0
@moveToPoint(@maxPoint - 1, 0)

@el.addEventListener(@events.move, @, false)
document.addEventListener(@events.end, @, false)

Expand All @@ -294,6 +383,7 @@ do (root = this, factory = (window, documentd) ->
@helper.triggerEvent(@el, "fltouchstart", true, false)

_touchMove: (event) ->
if @opts.autoPlay then @_clearAutoPlay()
if not @scrolling or @gestureStart then return

pageX = @helper.getPage(event, "pageX")
Expand Down Expand Up @@ -335,6 +425,7 @@ do (root = this, factory = (window, documentd) ->
@scrolling = false

@basePageX = pageX
if @opts.autoPlay then @_startAutoPlay()

_touchEnd: (event) ->
@el.removeEventListener(@events.move, @, false)
Expand Down Expand Up @@ -377,18 +468,86 @@ do (root = this, factory = (window, documentd) ->
_getTranslate: (x) ->
if @opts.use3d then "translate3d(#{x}px, 0, 0)" else "translate(#{x}px, 0)"

_cloneNode: ->
childNodes = @el.childNodes
itemAry = []

if not @opts.loop or @didCloneNode then return

for node in childNodes
if node.nodeType is 1 then itemAry.push(node)

firstItem = itemAry.shift()
lastItem = itemAry.pop()

@el.insertBefore(lastItem.cloneNode(true), firstItem)
@el.appendChild(firstItem.cloneNode(true))

@didCloneNode = true

_startAutoPlay: ->
if not @opts.autoPlay then return

toNextFn = => @toNext()
interval = @opts.interval

do =>
@timerId = window.setInterval(toNextFn, interval)

_clearAutoPlay: ->
# timerId = @timerId
window.clearInterval(@timerId)

tmpClearAutoPlay: ->
timerId = @timerId
window.clearInterval(timerId)

_setTotalWidth: ->
childNodes = @el.childNodes
itemAry = []

for node in childNodes
if node.nodeType is 1 then itemAry.push(node)

itemWidth = @helper.getWidth(itemAry[0])
totalWidth = itemWidth * itemAry.length

@el.style.width = "#{totalWidth}px"

# 毎回コストかかってる感じなのでチューニングしたい
_loop: ->
lastPoint = @maxPoint - 1
clearTime = @opts.interval / 2
smartLoop = =>
if @currentPoint is @maxPoint
@moveToPoint(1, 0)
else if (@currentPoint is 0)
@moveToPoint(lastPoint, 0)
transitionEndEventName = @helper.getTransitionEndEventName()

if transitionEndEventName isnt undefined
@el.addEventListener(transitionEndEventName, smartLoop, false)
window.setTimeout =>
@el.removeEventListener(transitionEndEventName, smartLoop, false)
, clearTime
else
timerId = smartLoop
window.clearTimeout ->
smartLoop()
, clearTime

_jsAnimate: (x, duration = @opts.transition["duration"]) ->
begin = +new Date()
from = parseInt(@el.style.left, 10)
to = x
duration = parseInt(duration, 10)
easing = (time, duration) ->
-(time /= duration) * (time - 2)
timer = setInterval ->
timer = window.setInterval ->
time = new Date() - begin

if time > duration
clearInterval(timer)
window.clearInterval(timer)
now = to
else
pos = easing(time, duration)
Expand Down
Loading

0 comments on commit 2b22e8d

Please sign in to comment.