Files
2015-11-13 16:53:28 -06:00

111 lines
2.2 KiB
TypeScript

import {raf} from '../util/dom';
export class ScrollTo {
constructor(ele, x, y, duration) {
if (typeof ele === 'string') {
// string query selector
ele = document.querySelector(ele);
}
if (ele) {
if (ele.nativeElement) {
// angular ElementRef
ele = ele.nativeElement;
}
if (ele.nodeType === 1) {
this._el = ele;
}
}
}
start(x, y, duration, tolerance) {
// scroll animation loop w/ easing
// credit https://gist.github.com/dezinezync/5487119
let self = this;
if (!self._el) {
// invalid element
return Promise.resolve();
}
x = x || 0;
y = y || 0;
tolerance = tolerance || 0;
let ele = self._el;
let fromY = ele.scrollTop;
let fromX = ele.scrollLeft;
let xDistance = Math.abs(x - fromX);
let yDistance = Math.abs(y - fromY);
if (yDistance <= tolerance && xDistance <= tolerance) {
// prevent scrolling if already close to there
this._el = ele = null;
return Promise.resolve();
}
return new Promise((resolve, reject) => {
let start;
// start scroll loop
self.isPlaying = true;
// chill out for a frame first
raf(() => {
start = Date.now();
raf(step);
});
// scroll loop
function step() {
let time = Math.min(1, ((Date.now() - start) / duration));
// where .5 would be 50% of time on a linear scale easedT gives a
// fraction based on the easing method
let easedT = easeOutCubic(time);
if (fromY != y) {
ele.scrollTop = parseInt((easedT * (y - fromY)) + fromY, 10);
}
if (fromX != x) {
ele.scrollLeft = parseInt((easedT * (x - fromX)) + fromX, 10);
}
if (time < 1 && self.isPlaying) {
raf(step);
} else if (!self.isPlaying) {
// stopped
this._el = ele = null;
reject();
} else {
// done
this._el = ele = null;
resolve();
}
}
});
}
stop() {
this.isPlaying = false;
}
dispose() {
this.stop();
this._el = null;
}
}
// decelerating to zero velocity
function easeOutCubic(t) {
return (--t) * t * t + 1;
}