neft
Version:
Universal Platform
147 lines (119 loc) • 4.05 kB
text/coffeescript
'use strict'
utils = require 'src/utils'
assert = require 'src/assert'
eventLoop = require 'src/eventLoop'
module.exports = (impl) ->
{Types, Renderer} = impl
{now} = Date
{round} = Math
pending = []
nowTime = now()
vsync = ->
nowTime = now()
eventLoop.lock()
i = 0; n = pending.length
while i < n
anim = pending[i]
if anim._running and not anim._paused
updateAnimation anim, Renderer.PropertyAnimation.ON_PENDING
i++
else
# remove element in not ordered list
# this array may change due loop
pending[i] = pending[n - 1]
pending.pop()
anim._impl.pending = false
n--
eventLoop.release()
if pending.length > 0
requestAnimationFrame vsync
return
updateAnimation = (anim, stateFlags) ->
data = anim._impl
progress = (nowTime - data.startTime) / anim._duration
if progress < 0
progress = 0
else if progress > 1
progress = 1
data.progress = progress
running = progress isnt 1 or (anim._running and anim._loop and anim._when)
fromVal = if data.reversed then data.to else data.from
toVal = if data.reversed then data.from else data.to
if progress is 1
val = toVal
else
val = data.easing(
anim._duration * progress,
fromVal,
(toVal - fromVal),
anim._duration
)
target = anim._target
property = anim._property
if progress is 1
stateFlags |= Renderer.PropertyAnimation.ON_STOP
if val is val and target and property # isNaN hack
if (anim._updateProperty & stateFlags) > 0 or not data.propertySetter
anim._updatePending = true
target[property] = val
anim._updatePending = false
else
impl[data.propertySetter].call target, val
if progress is 1
if running
data.startTime += anim._loopDelay + anim._duration
else
data.startTime = 0
anim.running = false
return
addAnimationIntoPending = (anim) ->
data = anim._impl
unless data.pending
if pending.length is 0
requestAnimationFrame vsync
pending.push anim
data.pending = true
return
DATA =
type: 'number'
pending: false
startTime: 0
pauseTime: 0
from: 0
to: 0
DATA: DATA
createData: impl.utils.createDataCloner 'PropertyAnimation', DATA
create: (data) ->
impl.Types.PropertyAnimation.create.call @, data
startAnimation: do (_super = impl.startAnimation) -> ->
_super.call @
if .type is 'number'
data =
data.from =
data.to =
addAnimationIntoPending @
data.startTime = now()
updateAnimation @, Renderer.PropertyAnimation.ON_START
data.startTime +=
return
stopAnimation: do (_super = impl.stopAnimation) -> ->
_super.call @
data =
if data.type is 'number' and data.startTime isnt 0
updateAnimation @, Renderer.PropertyAnimation.ON_STOP
data.startTime = 0
return
resumeAnimation: do (_super = impl.resumeAnimation) -> ->
_super.call @
if .type is 'number'
data =
addAnimationIntoPending @
data.startTime += Date.now() - data.pauseTime
data.pauseTime = 0
return
pauseAnimation: do (_super = impl.pauseAnimation) -> ->
_super.call @
data =
if data.type is 'number'
data.pauseTime = Date.now()
return