// TODO Keep static memory references to all arrays used in _tickUpdateTranslation function _tickUpdateTranslation(timestamp) { var dt = (timestamp - (_tickUpdateTranslation.lastTimestamp || timestamp)) _tickUpdateTranslation.lastTimestamp = timestamp // if (dt >= 20) { log("SLOW FRAME") } var excess = _boundsExcess(bouncingOffset) if (touch.isTouching) { var positionByDrag = [ touch.bouncingScrollAtStart[X] + touch.offset[X], touch.bouncingScrollAtStart[Y] + touch.offset[Y] ] var excess = _boundsExcess(positionByDrag) boundedOffset[X] = positionByDrag[X] - excess[X] boundedOffset[Y] = positionByDrag[Y] - excess[Y] if (_isOutOfBounds(excess)) { // While dragging out of bounds, the excess drag has a halved effect on bouncingOffset _updateTranslation( boundedOffset[X] + excess[X] / OUT_OF_BOUNDS_DRAG_DIVIDER, boundedOffset[Y] + excess[Y] / OUT_OF_BOUNDS_DRAG_DIVIDER ) } else { _updateTranslation(positionByDrag[X], positionByDrag[Y]) } } else if (_isFloating() || _isOutOfBounds(excess)) { var distance = tags.pos.abs(excess) var deceleration = clip(60 / dt, 0, 1) * DECELERATION_RATE if (excess[Y]) { if (excess[Y] * velocity[Y] <= 0) { // Outside bounds, moving back in if (distance[Y] < 0.5 && velocity[Y] < 0.01) { // Close the remaining little gap at once bouncingOffset[Y] -= excess[Y] velocity[Y] = 0 } else { velocity[Y] = -excess[Y] * BOUNCE_BACK_VELOCITY_BY_DISTANCE } } else { // Outside bounds, still moving out velocity[Y] -= excess[Y] * OUT_OF_BOUNDS_SLOWDOWN_RATE / dt } } velocity[X] *= deceleration velocity[Y] *= deceleration var positionByVelocity = [ bouncingOffset[X] + velocity[X] * dt, bouncingOffset[Y] + velocity[Y] * dt, ] _updateTranslation(positionByVelocity[X], positionByVelocity[Y]) var excess = _boundsExcess(positionByVelocity) boundedOffset[X] = positionByVelocity[X] - excess[X] boundedOffset[Y] = positionByVelocity[Y] - excess[Y] } // Cut off early, the last fraction of velocity doesn't have much impact on movement var bouncingScrollExcess = _boundsExcess(bouncingOffset) if (velocity[Y] && Math.abs(velocity[Y]) < VELOCITY_CUTOFF && !_isOutOfBounds(bouncingScrollExcess)) { velocity[Y] = 0 } if (touch.isTouching || _isFloating() || _isOutOfBounds(bouncingScrollExcess)) { // keep animating as long as user is actively touching or the view has a velocity or the view is bouncing requestAnimationFrame(_tickUpdateTranslation) } else { _tickUpdateTranslation.lastTimestamp = null } }
function _startRequestingAnimationFrames() { if (_tickUpdateTranslation.lastTimestamp) { return } requestAnimationFrame(_tickUpdateTranslation) }