index.js 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. var E_NOSCROLL = new Error('Element already at target scroll position')
  2. var E_CANCELLED = new Error('Scroll cancelled')
  3. var min = Math.min
  4. var ms = Date.now
  5. module.exports = {
  6. left: make('scrollLeft'),
  7. top: make('scrollTop')
  8. }
  9. function make (prop) {
  10. return function scroll (el, to, opts, cb) {
  11. opts = opts || {}
  12. if (typeof opts == 'function') cb = opts, opts = {}
  13. if (typeof cb != 'function') cb = noop
  14. var start = ms()
  15. var from = el[prop]
  16. var ease = opts.ease || inOutSine
  17. var duration = !isNaN(opts.duration) ? +opts.duration : 350
  18. var cancelled = false
  19. return from === to ?
  20. cb(E_NOSCROLL, el[prop]) :
  21. requestAnimationFrame(animate), cancel
  22. function cancel () {
  23. cancelled = true
  24. }
  25. function animate (timestamp) {
  26. if (cancelled) return cb(E_CANCELLED, el[prop])
  27. var now = ms()
  28. var time = min(1, ((now - start) / duration))
  29. var eased = ease(time)
  30. el[prop] = (eased * (to - from)) + from
  31. time < 1 ?
  32. requestAnimationFrame(animate) :
  33. requestAnimationFrame(function () {
  34. cb(null, el[prop])
  35. })
  36. }
  37. }
  38. }
  39. function inOutSine (n) {
  40. return 0.5 * (1 - Math.cos(Math.PI * n))
  41. }
  42. function noop () {}