I was recently working with an AdvancedDataGrid that was in charge of presenting a large amount of data to the user. I was presented with a minor issue (go figure) due to the fact that the max real estate this component could use was about 20% of the total page height.
The issue:
When scrolling through the data with the mouse wheel, the scroll bar was ’stepping’ to far and some rows were getting cut off. For example, if there were 40 rows of data and the amount of visible rows was 5, using the mouse wheel to scroll one notch would move the scroll index from position 0 to 7. This is a problem because it forces the user to either use the scroll arrows or drag the scroll bar to see every row. Which sucks because mouse wheels rule and make everyone’s life easier.
The solution:
Intercept the mouse wheel events that are fired and tell the component how to scroll. It’s quite simple actually. The first thing to do is register 2 event listeners on the Component, like so:
private function init():void
{
this.adg.addEventListener(Event.RENDER, this.updateScroll, false, 0, true);
this.adg.addEventListener(MouseEvent.MOUSE_WHEEL, this.handleMouseWheel, false, 0, true);
}
In the function above, adg references an AdvancedDataGrid, but that’s not really important. The Event.RENDER event is dispatched when the display list is about to be updated and rendered (the keyword being ‘about’). Consult the API Docs for a better description of this event. The MouseEvent.MOUSE_WHEEL is dispatched whenever the user scrolls with the Mouse Wheel.
The next part to look at is the method invoked after Event.RENDER is dispatched: updateScroll(). This method simply updates a variable with the vertical scroll position of the Component:
private function updateScroll(event:Event):void
{
this.scrollPos = this.adg.verticalScrollPosition;
}
The last part to look at is the method invoked after MouseEvent.MOUSE_WHEEL is fired: handleMouseWheel(). This method uses the scrollPos variable that is constantly being updated via updateScroll() and intercepts mouse wheel events in order to override the behavior of vertical scrolling:
private function handleMouseWheel(event:MouseEvent):void
{
var num:int = event.delta / Math.abs(event.delta);
if( ( this.scrollPos - num ) <= 0)
this.adg.scrollToIndex(0);
} else if( ( this.scrollPos - num ) >= this.adg.maxVerticalScrollPosition ) {
this.adg.scrollToIndex( this.adg.maxVerticalScrollPosition );
} else {
this.adg.scrollToIndex( this.scrollPos - num );
}
}
This is also very straight forward: evaluate the current scroll position and proceed accordingly without causing wacky behavior. In other words, if the result of (scrollPos – num) is <= 0 or >= to the max vertical scroll position, send (or keep) the scroll wheel to the appropriate extreme, else scroll 1 unit in the appropriate direction.
Note: eventually I’ll start adding interactive examples here… someday.