I'm getting many reports that the mousewheel behaves differently in different browsers when using this scrollbar class. In some browsers (like Firefox) it's extremely slow while in others (mostly newer versions of Safari on Snow Leopard) it's perfect.
Any ideas what's going on here and how to fix it? I'm using the Mootools library. One line to pay attention to here is the wheel: (Browser.firefox) ? 20 : 1
line. This is where you set the speed or steps for the mousewheel.
Here it is set up in a jsFiddle: http://jsfiddle.net/brandondurham/6SUyM/
var ScrollBar = new Class({
Implements: [Events, Options],
options: {
wheel: (Browser.firefox) ? 20 : 1
},
initialize: function(main, options) {
this.setOptions(options);
this.main = $(main);
this.content = this.main.getFirst();
this.vScrollbar = new Element('div', {
'class': 'scrollbar'
}).inject(this.content, 'after');
this.vTrack = new Element('div', {
'class': 'track'
}).inject(this.vScrollbar);
this.vThumb = new Element('div', {
'class': 'handle'
}).inject(this.vTrack);
this.bound = {
'vStart': this.vStart.bind(this),
'end': this.end.bind(this),
'vDrag': this.vDrag.bind(this),
'vTouchDrag': this.vTouchDrag.bind(this),
'wheel': this.wheel.bind(this),
'vPage': this.vPage.bind(this),
};
this.vScrollbar.set('tween', {
duration: 200,
transition: 'cubic:out'
});
this.main.addEvent('mouseenter', function(event){
this.vScrollbar.get('tween').cancel();
this.vScrollbar.tween('width', 12);
}.bind(this));
this.main.addEvent('mouseleave', function(event){
this.vScrollbar.get('tween').cancel();
this.vScrollbar.tween('width', 0);
}.bind(this));
this.vPosition = {};
this.vMouse = {};
this.update();
this.attach();
this.scrollContent = new Fx.Scroll(this.content, {
duration: 800,
transition: Fx.Transitions.Cubic.easeOut,
});
this.scrollThumb = new Fx.Morph(this.vThumb, {
duration: 400,
transition: Fx.Transitions.Cubic.easeOut,
});
},
update: function() {
var panel_id = (this.content.getFirst()) ? this.content.getFirst().get('id') : '';
if ((this.content.scrollHeight <= this.main.offsetHeight) || panel_id == 'random-doodle') this.main.addClass('noscroll');
else this.main.removeClass('noscroll');
this.vContentSize = this.content.offsetHeight;
this.vContentScrollSize = this.content.scrollHeight;
this.vTrackSize = this.vTrack.offsetHeight;
this.vContentRatio = this.vContentSize / this.vContentScrollSize;
this.vThumbSize = (this.vTrackSize * this.vContentRatio).limit(12, this.vTrackSize);
this.vScrollRatio = this.vContentScrollSize / this.vTrackSize;
this.vThumb.setStyle('height', this.vThumbSize);
this.vUpdateThumbFromContentScroll();
this.vUpdateContentFromThumbPosition();
},
vUpdateContentFromThumbPosition: function() {
this.content.scrollTop = this.vPosition.now * this.vScrollRatio;
},
vUpdateContentFromThumbPosition2: function() {
var pos = this.vPosition.now * this.vScrollRatio;
this.scrollContent.start(0, pos);
},
vUpdateThumbFromContentScroll: function() {
this.vPosition.now = (this.content.scrollTop / this.vScrollRatio).limit(0, (this.vTrackSize - this.vThumbSize));
this.vThumb.setStyle('top', this.vPosition.now);
},
vUpdateThumbFromContentScroll2: function(pos) {
this.vPosition.now = (this.content.scrollTopNew / this.vScrollRatio).limit(0, (this.vTrackSize - this.vThumbSize));
this.scrollThumb.start({
'top': this.vPosition.now
});
},
attach: function() {
if (this.options.wheel) this.content.addEvent('mousewheel', this.bound.wheel);
this.content.addEvent('touchstart', this.bound.vStart);
this.vThumb.addEvent('mousedown', this.bound.vStart);
this.vTrack.addEvent('mouseup', this.bound.vPage);
},
wheel: function(event) {
this.content.scrollTop -= event.wheel * this.options.wheel;
this.vUpdateThumbFromContentScroll();
event.stop();
},
scrollTo: function(pos){
myInstance = this;
this.content.scrollTopNew = pos;
this.scrollContent.start(0, this.content.scrollTopNew);
myInstance.vUpdateThumbFromContentScroll2(pos);
},
vPage: function(event) {
// if scrolling up
if (event.page.y > this.vThumb.getPosition().y) {
myInstance = this;
this.content.scrollTopNew = this.content.scrollTop.toInt() + this.content.offsetHeight.toInt();
this.scrollContent.start(0, this.content.scrollTopNew);
}
// if scrolling down
else {
myInstance = this;
this.content.scrollTopNew = this.content.scrollTop.toInt() - this.content.offsetHeight.toInt();
this.scrollContent.start(0, this.content.scrollTopNew);
}
myInstance.vUpdateThumbFromContentScroll2(event.page.y);
event.stop();
},
vStart: function(event) {
this.vMouse.start = event.page.y;
this.vPosition.start = this.vThumb.getStyle('top').toInt();
document.addEvent('touchmove', this.bound.vTouchDrag);
document.addEvent('touchend', this.bound.end);
document.addEvent('mousemove', this.bound.vDrag);
document.addEvent('mouseup', this.bound.end);
this.vThumb.addEvent('mouseup', this.bound.end);
event.stop();
},
end: function(event) {
document.removeEvent('touchmove', this.bound.vTouchDrag);
document.removeEvent('mousemove', this.bound.vDrag);
document.removeEvent('mouseup', this.bound.end);
this.vThumb.removeEvent('mouseup', this.bound.end);
event.stop();
},
vTouchDrag: function(event) {
this.vMouse.now = event.page.y;
this.vPosition.now = (this.vPosition.start - (this.vMouse.now - this.vMouse.start)).limit(0, (this.vTrackSize - this.vThumbSize));
this.vUpdateContentFromThumbPosition();
this.vUpdateThumbFromContentScroll();
event.stop();
},
vDrag: function(event) {
this.vMouse.now = event.page.y;
this.vPosition.now = (this.vPosition.start + (this.vMouse.now - this.vMouse.start)).limit(0, (this.vTrackSize - this.vThumbSize));
this.vUpdateContentFromThumbPosition();
this.vUpdateThumbFromContentScroll();
event.stop();
}
});
this.options.wheel
being 20. any particular reason why you wouldn't use a step of 20 for all browsers? also, you may want to track dragging viathis.dragging = true;
and check for that in the mouseleave function that hides the scrollbar if you mouseout - you shouldn't disappear it whilst dragging. changeend
to setthis.dragging
to false again and check if moused out so you can hide it if left the container. – Berthoud