Skip to content

Instantly share code, notes, and snippets.

@w-jerome
Last active June 18, 2019 16:43
Show Gist options
  • Save w-jerome/dcd726f2e52dcee1f42c8ccd9feb1c77 to your computer and use it in GitHub Desktop.
Save w-jerome/dcd726f2e52dcee1f42c8ccd9feb1c77 to your computer and use it in GitHub Desktop.
Javascript - Scroll Utils
var $output = document.querySelector('.js-output');
function debugRender(obj) {
$output.innerHTML = '';
$output.appendChild(document.createTextNode(JSON.stringify(obj, function(key, value) {
if (value === window || (value && typeof value.nodeName === 'string')) {
return '[DOM]';
}
return value;
}, 4)));
}
var scroll_hack = new Scrolling(window, {
onScrollStart: function() {
debugRender(this);
},
onScroll: function(event) {
debugRender(this);
},
onScrollEnd: function() {
debugRender(this);
},
});
debugRender(scroll_hack);
<div class="section section--full || js-section-scroll">
Section full
</div>
<div class="section section--full || js-section-scroll">
Section full
</div>
<div class="section section--full || js-section-scroll">
Section full
</div>
<div class="section section--full || js-section-scroll">
Section full
</div>
<div class="section section--full || js-section-scroll">
Section full
</div>
<div class="output">
<pre class="js-output"></pre>
<div>
<small><em>(speed : px/ms)</em></small>
</div>
<br>
<div>
<button type="button" onclick="scroll_hack.displayUpdate()">
display update
</button>
</div>
</div>
function Scrolling(selector, options) {
if (typeof selector !== 'object' || !selector) {
return this;
}
options = (typeof options === 'object') ? options : {};
this.$scroll = selector;
this.direction = 'down';
this.viewport = 0;
this.height = 0;
this.percent = 0;
this.speed = 0;
this.scroll_position_start = 0;
this.scroll_position_end = 0;
this.is_scrolling = false;
this.on_scroll_distance = 0;
this.on_scroll_histories_length = (typeof options.on_scroll_histories_length === 'number' && options.on_scroll_histories_length > 1) ? options.on_scroll_histories_length : 2;
this.on_scroll_histories = [];
this.on_scroll_histories_times = [];
this.timeout_on_scroll = null;
this.timeout_on_scroll_time = (typeof options.timeout_on_scroll_time === 'number' && options.timeout_on_scroll_time > 0) ? options.timeout_on_scroll_time : 50;
this.scroll_object_property = (this.$scroll === window) ? 'pageYOffset' : 'scrollTop';
this.onScrollStart = (typeof options.onScrollStart === 'function') ? options.onScrollStart : function() {};
this.onScroll = (typeof options.onScroll === 'function') ? options.onScroll : function() {};
this.onScrollEnd = (typeof options.onScrollEnd === 'function') ? options.onScrollEnd : function() {};
if (!this.$scroll) {
return this;
}
// Init
this.$scroll.addEventListener('scroll', this.handleScroll.bind(this));
this.displayUpdate();
}
Scrolling.prototype.displayUpdate = function() {
if (this.$scroll === window) {
this.height = document.querySelector('body').clientHeight;
this.viewport = this.$scroll.innerHeight;
} else {
this.height = this.$scroll.clientHeight;
this.viewport = this.$scroll.innerHeight;
}
}
Scrolling.prototype.handleScroll = function(event) {
if (!this.timeout_on_scroll) {
this.scroll_position_start = this.scroll_position_end;
this.onScrollStart();
}
this.is_scrolling = true;
window.clearTimeout(this.timeout_on_scroll);
this.timeout_on_scroll = setTimeout(function() {
this.scrollEnd();
}.bind(this), 50);
this.on_scroll_histories.push(this.$scroll[this.scroll_object_property]);
this.on_scroll_histories_times.push(event.timeStamp);
if (this.on_scroll_histories.length > this.on_scroll_histories_length) {
this.on_scroll_histories.shift();
this.on_scroll_histories_times.shift();
}
if (this.on_scroll_histories.length > 1) {
if (this.on_scroll_histories[(this.on_scroll_histories.length - 1)] < this.on_scroll_histories[(this.on_scroll_histories.length - 2)]) {
this.direction = 'up';
} else {
this.direction = 'down';
}
this.on_scroll_distance = this.on_scroll_histories[(this.on_scroll_histories.length - 1)] - this.on_scroll_histories[(this.on_scroll_histories.length - 2)];
this.speed = Math.abs(this.on_scroll_distance) / (this.on_scroll_histories_times[(this.on_scroll_histories_times.length - 1)] - this.on_scroll_histories_times[(this.on_scroll_histories_times.length - 2)]);
this.percent = (100 * this.$scroll[this.scroll_object_property] / (this.height - this.viewport));
}
this.onScroll(event);
}
Scrolling.prototype.scrollEnd = function(event) {
this.is_scrolling = false;
window.clearTimeout(this.timeout_on_scroll);
this.timeout_on_scroll = null;
this.on_scroll_distance = 0;
this.speed = 0;
this.scroll_position_end = this.$scroll[this.scroll_object_property];;
this.onScrollEnd();
}
html,
body {
margin: 0;
}
.section {
display: flex;
align-items: center;
justify-content: center;
background-color: #ccc;
}
.section:not(:last-child) {
border-bottom: 1px solid rgba(0, 0, 0, 0.3);
}
.section--min {
height: 80vh;
}
.section--full {
height: 100vh;
}
.section--bigger {
height: 200vh;
}
.output {
z-index: 1;
position: fixed;
display: block;
top: 1em;
left: 1em;
background-color: #fff;
padding: 1em;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment