1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-30 06:28:31 +00:00

Allow smooth scrolling animated chat (#452)

* Allow smooth scrolling animated chat
* update to use requestAnimationFrame
This commit is contained in:
neuspadrin 2018-07-03 18:18:39 -04:00 committed by Mike
parent 5626a3c389
commit be1e1bfd47

View file

@ -45,6 +45,23 @@ export default class Scroller extends Module {
]
}
});
this.settings.add('chat.scroller.smooth-scroll', {
default: 0,
ui: {
path: 'Chat > Behavior >> General',
title: 'Smooth Scrolling',
description: 'Animates new chat messages into view. Will speed up if necessary to keep up with chat.',
component: 'setting-select-box',
data: [
{value: 0, title: 'Disabled'},
{value: 1, title: 'Slow'},
{value: 2, title: 'Medium'},
{value: 3, title: 'Fast'},
{value: 4, title: 'Very Fast'}
]
}
});
}
onEnable() {
@ -64,6 +81,15 @@ export default class Scroller extends Module {
}
});
this.smoothScroll = this.chat.context.get('chat.scroller.smooth-scroll');
this.chat.context.on('changed:chat.scroller.smooth-scroll', val => {
this.smoothScroll = val;
for(const inst of this.ChatScroller.instances) {
inst.ffzSetSmoothScroll(val);
}
});
this.ChatScroller.ready((cls, instances) => {
const t = this,
old_catch = cls.prototype.componentDidCatch,
@ -223,6 +249,56 @@ export default class Scroller extends Module {
//this.ffzHideFrozen();
}
cls.prototype.smoothScrollBottom = function() {
if(this.state.ffzSmoothAnimation){
cancelAnimationFrame(this.state.ffzSmoothAnimation);
}
this.isScrollingToBottom = true;
// Step setting value is # pixels to scroll per 10ms.
// 1 is pretty slow, 2 medium, 3 fast, 4 very fast.
let step = this.ffz_smooth_scroll;
const scrollContent = this.scroll.scrollContent;
const targetTop = scrollContent.scrollHeight - scrollContent.clientHeight;
const difference = targetTop - scrollContent.scrollTop;
// If we are falling behind speed us up
if (difference > scrollContent.clientHeight) {
// we are a full scroll away, just jump there
step = difference;
} else if (difference > 200) {
// we are starting to fall behind, speed it up a bit
step += step * parseInt(difference / 200, 10);
}
let prevTime = Date.now();
const smoothAnimation = () => {
if(this.state.ffzFrozen) {
this.isScrollingToBottom = false;
return;
}
// See how much time has passed to get a step based off the delta
const currentTime = Date.now();
const delta = currentTime - prevTime;
const currentStep = step * (delta / 10);
// we need to move at least one full pixel for scrollTop to do anything in this delta.
if (currentStep >= 1) {
prevTime = currentTime;
if (scrollContent.scrollTop < (scrollContent.scrollHeight - scrollContent.clientHeight)) {
scrollContent.scrollTop += currentStep;
this.state.ffzSmoothAnimation = requestAnimationFrame(smoothAnimation);
} else {
scrollContent.scrollTop = scrollContent.scrollHeight - scrollContent.clientHeight;
this.isScrollingToBottom = false;
}
} else {
// the frame happened so quick since last update we didn't move a full pixel yet.
// should only be possible if the FPS of a browser went over 60fps.
this.state.ffzSmoothAnimation = requestAnimationFrame(smoothAnimation);
}
}
smoothAnimation();
}
cls.prototype.ffzInstallHandler = function() {
if ( this._ffz_handleScroll )
@ -231,8 +307,13 @@ export default class Scroller extends Module {
const t = this;
this._old_scroll = this.scrollToBottom;
this.scrollToBottom = function() {
if ( ! this.ffz_freeze_enabled || ! this.state.ffzFrozen )
return this._old_scroll();
if ( ! this.ffz_freeze_enabled || ! this.state.ffzFrozen ) {
if (this.ffz_smooth_scroll !== 0) {
this.smoothScrollBottom();
} else {
this._old_scroll();
}
}
}
this._ffz_handleScroll = this.handleScrollEvent;
@ -394,6 +475,11 @@ export default class Scroller extends Module {
}
cls.prototype.ffzSetSmoothScroll = function(value) {
this.ffz_smooth_scroll = value;
}
for(const inst of instances)
this.onMount(inst);
});
@ -420,6 +506,8 @@ export default class Scroller extends Module {
if ( this.freeze !== 0 )
inst.ffzEnableFreeze();
inst.ffzSetSmoothScroll(this.smoothScroll);
}
onUnmount(inst) { // eslint-disable-line class-methods-use-this