scroll-to-element
Version:
Smooth scrolling to an element via selector or node reference
101 lines (82 loc) • 2 kB
JavaScript
var ease = require('./ease');
var Emitter = require('./emitter');
function extend(obj, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) obj[key] = src[key];
}
return obj;
}
function Tween(obj) {
if (!(this instanceof Tween)) return new Tween(obj);
this._from = obj;
this.ease('linear');
this.duration(500);
}
Emitter(Tween.prototype);
Tween.prototype.reset = function(){
this.isArray = Object.prototype.toString.call(this._from) === '[object Array]';
this._curr = extend({}, this._from);
this._done = false;
this._start = Date.now();
return this;
};
Tween.prototype.to = function(obj){
this.reset();
this._to = obj;
return this;
};
Tween.prototype.duration = function(ms){
this._duration = ms;
return this;
};
Tween.prototype.ease = function(fn){
fn = 'function' == typeof fn ? fn : ease[fn];
if (!fn) throw new TypeError('invalid easing function');
this._ease = fn;
return this;
};
Tween.prototype.stop = function(){
this.stopped = true;
this._done = true;
this.emit('stop');
this.emit('end');
return this;
};
Tween.prototype.step = function(){
if (this._done) return;
var duration = this._duration;
var now = Date.now();
var delta = now - this._start;
var done = delta >= duration;
if (done) {
this._from = this._to;
this._update(this._to);
this._done = true;
this.emit('end');
return this;
}
var from = this._from;
var to = this._to;
var curr = this._curr;
var fn = this._ease;
var p = (now - this._start) / duration;
var n = fn(p);
if (this.isArray) {
for (var i = 0; i < from.length; ++i) {
curr[i] = from[i] + (to[i] - from[i]) * n;
}
this._update(curr);
return this;
}
for (var k in from) {
curr[k] = from[k] + (to[k] - from[k]) * n;
}
this._update(curr);
return this;
};
Tween.prototype.update = function(fn){
if (0 == arguments.length) return this.step();
this._update = fn;
return this;
};
module.exports = Tween;