import { requestAnimationFrame } from './utils'; function scrollTo(...args) { let [left, top, duration, easing, callback] = args; if (args.length === 4 && typeof easing === 'function') { callback = easing; [left, top, duration, callback, easing] = args; } if (typeof easing === 'undefined') easing = 'swing'; return this.each(function animate() { const el = this; let currentTop; let currentLeft; let maxTop; let maxLeft; let newTop; let newLeft; let scrollTop; // eslint-disable-line let scrollLeft; // eslint-disable-line let animateTop = top > 0 || top === 0; let animateLeft = left > 0 || left === 0; if (typeof easing === 'undefined') { easing = 'swing'; } if (animateTop) { currentTop = el.scrollTop; if (!duration) { el.scrollTop = top; } } if (animateLeft) { currentLeft = el.scrollLeft; if (!duration) { el.scrollLeft = left; } } if (!duration) return; if (animateTop) { maxTop = el.scrollHeight - el.offsetHeight; newTop = Math.max(Math.min(top, maxTop), 0); } if (animateLeft) { maxLeft = el.scrollWidth - el.offsetWidth; newLeft = Math.max(Math.min(left, maxLeft), 0); } let startTime = null; if (animateTop && newTop === currentTop) animateTop = false; if (animateLeft && newLeft === currentLeft) animateLeft = false; function render(time = new Date().getTime()) { if (startTime === null) { startTime = time; } const progress = Math.max(Math.min((time - startTime) / duration, 1), 0); const easeProgress = easing === 'linear' ? progress : (0.5 - (Math.cos(progress * Math.PI) / 2)); let done; if (animateTop) scrollTop = currentTop + (easeProgress * (newTop - currentTop)); if (animateLeft) scrollLeft = currentLeft + (easeProgress * (newLeft - currentLeft)); if (animateTop && newTop > currentTop && scrollTop >= newTop) { el.scrollTop = newTop; done = true; } if (animateTop && newTop < currentTop && scrollTop <= newTop) { el.scrollTop = newTop; done = true; } if (animateLeft && newLeft > currentLeft && scrollLeft >= newLeft) { el.scrollLeft = newLeft; done = true; } if (animateLeft && newLeft < currentLeft && scrollLeft <= newLeft) { el.scrollLeft = newLeft; done = true; } if (done) { if (callback) callback(); return; } if (animateTop) el.scrollTop = scrollTop; if (animateLeft) el.scrollLeft = scrollLeft; requestAnimationFrame(render); } requestAnimationFrame(render); }); } // scrollTop(top, duration, easing, callback) { function scrollTop(...args) { let [top, duration, easing, callback] = args; if (args.length === 3 && typeof easing === 'function') { [top, duration, callback, easing] = args; } const dom = this; if (typeof top === 'undefined') { if (dom.length > 0) return dom[0].scrollTop; return null; } return dom.scrollTo(undefined, top, duration, easing, callback); } function scrollLeft(...args) { let [left, duration, easing, callback] = args; if (args.length === 3 && typeof easing === 'function') { [left, duration, callback, easing] = args; } const dom = this; if (typeof left === 'undefined') { if (dom.length > 0) return dom[0].scrollLeft; return null; } return dom.scrollTo(left, undefined, duration, easing, callback); } export { scrollTo, scrollTop, scrollLeft };