import { Scroll } from './Scroll'
|
|
function i (scroll, t, n) {
|
function i (t, scroll, r, o) {
|
if (!t || !t.cancelled) {
|
r(scroll)
|
var a = scroll.done()
|
if (!a) {
|
if (!t.cancelled) {
|
t.id = requestAnimationFrame(i.bind(null, t, scroll, r, o))
|
}
|
}
|
if (a && o) {
|
o(scroll)
|
}
|
}
|
}
|
|
function r (scroll) {
|
if (scroll && scroll.id) {
|
cancelAnimationFrame(scroll.id)
|
}
|
if (scroll) {
|
scroll.cancelled = true
|
}
|
}
|
var o = {
|
id: 0,
|
cancelled: false
|
}
|
i(o, scroll, t, n)
|
return {
|
cancel: r.bind(null, o),
|
model: scroll
|
}
|
}
|
|
export function Scroller (element, options) {
|
options = options || {}
|
this._element = element
|
this._options = options
|
this._enableSnap = options.enableSnap || false
|
this._itemSize = options.itemSize || 0
|
this._enableX = options.enableX || false
|
this._enableY = options.enableY || false
|
this._shouldDispatchScrollEvent = !!options.onScroll
|
if (this._enableX) {
|
this._extent = (options.scrollWidth || this._element.offsetWidth) - this._element.parentElement.offsetWidth
|
this._scrollWidth = options.scrollWidth
|
} else {
|
this._extent = (options.scrollHeight || this._element.offsetHeight) - this._element.parentElement.offsetHeight
|
this._scrollHeight = options.scrollHeight
|
}
|
|
this._position = 0
|
this._scroll = new Scroll(this._extent, options.friction, options.spring)
|
this._onTransitionEnd = this.onTransitionEnd.bind(this)
|
this.updatePosition()
|
}
|
|
Scroller.prototype.onTouchStart = function () {
|
this._startPosition = this._position
|
this._lastChangePos = this._startPosition
|
if (this._startPosition > 0) {
|
this._startPosition /= 0.5
|
} else {
|
if (this._startPosition < -this._extent) {
|
this._startPosition = (this._startPosition + this._extent) / 0.5 - this._extent
|
}
|
}
|
if (this._animation) {
|
this._animation.cancel()
|
this._scrolling = false
|
}
|
this.updatePosition()
|
}
|
Scroller.prototype.onTouchMove = function (x, y) {
|
var startPosition = this._startPosition
|
if (this._enableX) {
|
startPosition += x
|
} else if (this._enableY) {
|
startPosition += y
|
}
|
|
if (startPosition > 0) {
|
startPosition *= 0.5
|
} else if (startPosition < -this._extent) {
|
startPosition = 0.5 * (startPosition + this._extent) - this._extent
|
}
|
this._position = startPosition
|
this.updatePosition()
|
this.dispatchScroll()
|
}
|
Scroller.prototype.onTouchEnd = function (e, r, o) {
|
if (this._enableSnap && this._position > -this._extent && this._position < 0) {
|
if (this._enableY && ((Math.abs(r) < this._itemSize && Math.abs(o.y) < 300) || Math.abs(o.y) < 150)) {
|
this.snap()
|
return
|
}
|
if (this._enableX && ((Math.abs(e) < this._itemSize && Math.abs(o.x) < 300) || Math.abs(o.x) < 150)) {
|
this.snap()
|
return
|
}
|
}
|
if (this._enableX) {
|
this._scroll.set(this._position, o.x)
|
} else if (this._enableY) {
|
this._scroll.set(this._position, o.y)
|
}
|
|
if (this._enableSnap) {
|
var s = this._scroll._friction.x(100)
|
var l = s % this._itemSize
|
var c = Math.abs(l) > this._itemSize / 2 ? s - (this._itemSize - Math.abs(l)) : s - l
|
if (c <= 0 && c >= -this._extent) {
|
this._scroll.setVelocityByEnd(c)
|
}
|
}
|
this._lastTime = Date.now()
|
this._lastDelay = 0
|
this._scrolling = true
|
this._lastChangePos = this._position
|
this._lastIdx = Math.floor(Math.abs(this._position / this._itemSize))
|
this._animation = i(this._scroll, () => {
|
var e = Date.now()
|
var i = (e - this._scroll._startTime) / 1e3
|
var r = this._scroll.x(i)
|
this._position = r
|
this.updatePosition()
|
var o = this._scroll.dx(i)
|
if (this._shouldDispatchScrollEvent && e - this._lastTime > this._lastDelay) {
|
this.dispatchScroll()
|
this._lastDelay = Math.abs(2e3 / o)
|
this._lastTime = e
|
}
|
}, () => {
|
if (this._enableSnap) {
|
if (c <= 0 && c >= -this._extent) {
|
this._position = c
|
this.updatePosition()
|
}
|
if (typeof this._options.onSnap === 'function') {
|
this._options.onSnap(Math.floor(Math.abs(this._position) / this._itemSize))
|
}
|
}
|
if (this._shouldDispatchScrollEvent) {
|
this.dispatchScroll()
|
}
|
this._scrolling = false
|
})
|
}
|
Scroller.prototype.onTransitionEnd = function () {
|
this._element.style.transition = ''
|
this._element.style.webkitTransition = ''
|
this._element.removeEventListener('transitionend', this._onTransitionEnd)
|
this._element.removeEventListener('webkitTransitionEnd', this._onTransitionEnd)
|
if (this._snapping) {
|
this._snapping = false
|
}
|
this.dispatchScroll()
|
}
|
Scroller.prototype.snap = function () {
|
var e = this._itemSize
|
var t = this._position % e
|
var i = Math.abs(t) > this._itemSize / 2 ? this._position - (e - Math.abs(t)) : this._position - t
|
if (this._position !== i) {
|
this._snapping = true
|
this.scrollTo(-i)
|
if (typeof this._options.onSnap === 'function') {
|
this._options.onSnap(Math.floor(Math.abs(this._position) / this._itemSize))
|
}
|
}
|
}
|
Scroller.prototype.scrollTo = function (e, t) {
|
if (this._animation) {
|
this._animation.cancel()
|
this._scrolling = false
|
}
|
if (typeof e === 'number') {
|
this._position = -e
|
}
|
if (this._position < -this._extent) {
|
this._position = -this._extent
|
} else {
|
if (this._position > 0) {
|
this._position = 0
|
}
|
}
|
this._element.style.transition = 'transform ' + (t || 0.2) + 's ease-out'
|
this._element.style.webkitTransition = '-webkit-transform ' + (t || 0.2) + 's ease-out'
|
this.updatePosition()
|
this._element.addEventListener('transitionend', this._onTransitionEnd)
|
this._element.addEventListener('webkitTransitionEnd', this._onTransitionEnd)
|
}
|
Scroller.prototype.dispatchScroll = function () {
|
if (typeof this._options.onScroll === 'function' && Math.round(this._lastPos) !== Math.round(this._position)) {
|
this._lastPos = this._position
|
var e = {
|
target: {
|
scrollLeft: this._enableX ? -this._position : 0,
|
scrollTop: this._enableY ? -this._position : 0,
|
scrollHeight: this._scrollHeight || this._element.offsetHeight,
|
scrollWidth: this._scrollWidth || this._element.offsetWidth,
|
offsetHeight: this._element.parentElement.offsetHeight,
|
offsetWidth: this._element.parentElement.offsetWidth
|
}
|
}
|
this._options.onScroll(e)
|
}
|
}
|
Scroller.prototype.update = function (e, t, n) {
|
var i = 0
|
var r = this._position
|
if (this._enableX) {
|
i = this._element.childNodes.length ? (t || this._element.offsetWidth) - this._element.parentElement.offsetWidth : 0
|
this._scrollWidth = t
|
} else {
|
i = this._element.childNodes.length ? (t || this._element.offsetHeight) - this._element.parentElement.offsetHeight : 0
|
this._scrollHeight = t
|
}
|
if (typeof e === 'number') {
|
this._position = -e
|
}
|
if (this._position < -i) {
|
this._position = -i
|
} else {
|
if (this._position > 0) {
|
this._position = 0
|
}
|
}
|
this._itemSize = n || this._itemSize
|
this.updatePosition()
|
if (r !== this._position) {
|
this.dispatchScroll()
|
if (typeof this._options.onSnap === 'function') {
|
this._options.onSnap(Math.floor(Math.abs(this._position) / this._itemSize))
|
}
|
}
|
this._extent = i
|
this._scroll._extent = i
|
}
|
Scroller.prototype.updatePosition = function () {
|
var transform = ''
|
if (this._enableX) {
|
transform = 'translateX(' + this._position + 'px) translateZ(0)'
|
} else {
|
if (this._enableY) {
|
transform = 'translateY(' + this._position + 'px) translateZ(0)'
|
}
|
}
|
this._element.style.webkitTransform = transform
|
this._element.style.transform = transform
|
}
|
Scroller.prototype.isScrolling = function () {
|
return this._scrolling || this._snapping
|
}
|