Hey guys, I’ve been away from this thread for a while, been really busy with work. After thinking about the “not showing the bottom of the scroll” situation, I figured out what it was and came up with a solution.
The math that is used in the Easing Equation deals with proportional movement. The value never quite makes it all the way, this is because we are doing floating point division, we could easily achieve a smooth easing effect using integer division.
Again the problem is that currently we are ALWAYS approaching the end position, but never quite make it there. This is where our integer division comes in to play, we utilize integer division with the bit shift operator, we will bit-shift the value to the right by 3 binary digits.
I have composed a class and an example file…
This class only works with Flash 8, so I have posted the class code so that you can look through it.
The only reason it is specific to Flash 8 is because I use a Rectangle as the viewable property, again this is for my personal use, if you’d like to use it and are not running Flash 8 you will need to convert it yourself.
MyScrollbar.as
import flash.geom.Rectangle;
/*
* This is a generic scrollbar class, it has some requirements that have
* to be met in order for it to work.
* Requirements:
* - a dragger movieclip (instance name = dragger)
* - a track movieclip (instance name = track)
* - both up and down buttons (instance names = up,down)
*
* Notes:
* - At the moment this is only meant to work with scrolling on the y axis.
*
*@author: Michael Avila (MichaelxxOA)
*@version: 1.0
*/
class MyScrollbar
{
// the content we will be scrolling
private var content:MovieClip;
// the movieclip that represents the viewable area of our content, most likely a mask
private var viewable:Rectangle;
// elements in the scrollbar
public var dragger:MovieClip;
private var track:MovieClip;
private var up:MovieClip;
private var down:MovieClip;
// the limits as to how far the dragger can move in any direction
public var left:Number;
public var top:Number;
public var right:Number;
public var bottom:Number;
// how fast the dragger will move
public var move_speed:Number = 3;
/*
* Scrolling equation values
*/
// how much of our content can be scrolled, defaults at 0
private var scrollable:Number = 0;
// where our content will sit when it is at 0% scrolled, defaults at 0.
// it is likely that we will set this to be the initial position of our content, before any scrolling is applied
private var top_scroll:Number = 0;
/* Constructor */
public function MyScrollbar()
{
// initialize all boundaries
left = track._x;
top = track._y;
right = track._x;
bottom = track._y + (track._height - dragger._height);
// Register this object to receive events from the Mouse class
Mouse.addListener( this );
}
/*
* PUBLIC API
*
* - Two of these methods have to be invoked before our scrollbar will work
* We will need to call, setContent() and setViewable(). The others are optional.
*/
public function setContent( content:MovieClip ):Void
{
this.content = content;
setScrollProps();
}
public function setViewable( viewable:Rectangle ):Void
{
this.viewable = viewable;
setScrollProps();
}
// set easing either true/false
public function setEasing( value:Boolean, speed:Number ):Void
{
content.isEasing = value;
if (speed > 0 && value)
{
content.speed = speed;
}
}
/*
* Private Methods
*
* Probably the single most important function in our class, this will set our contents newY property to
* it's proper value
*/
// public for the event handlers.. still not considered part of the API
public function updateContentPos():Void
{
var percent_scrolled:Number = (dragger._y-track._y)/(track._height-dragger._height);
// instead of setting the _y property directly, we simple set newY
// that way we can adjust how we handle the new Y coordinate we'd like to move to
content.newY = Math.round(top_scroll - (percent_scrolled * scrollable));
}
private function setScrollProps():Void
{
// if either viewable or content hasn't been set we cannot successfully set our scroll properties
// so return out of the function
if (viewable == undefined || content == undefined) return;
// if not then set properties
scrollable = content._height - viewable.height;
top_scroll = content._y;
initElements();
checkScrollability();
}
// checks whether or not our content is scrollable, if it is not than we hide the dragger and disable the
// other elements
private function checkScrollability():Void
{
if (scrollable < 0)
{
dragger._visible = false;
up._alpha = 50;
down._alpha = 50;
track._alpha = 50;
}
}
/**
* Executes when the mouse wheel is scrolled.
*/
private function onMouseWheel ( delta:Number ) : Void
{
var speed:Number = (delta > 0) ? move_speed : -move_speed;
dragger._y = Math.min( bottom, Math.max(top, dragger._y-speed));
updateContentPos();
}
/*
* This function might be a little messy as it is created to initialize all elements and their event handlers.
* The only thing that we are doing odd in this method is the fact that we are setting a src property on each
* element. We do this so that we can make calls to functions in the MyScrollbar class.
*
* Another thing about our src property is that in order for the compiler to not throw an error we have to
* declare it with a null value, our declared src property is not the src property that we will be accessing
* in our elements event handlers.
*/
private function initElements():Void
{
var src;// trick compiler.
// set src properties on all elements
dragger.src = this;
track.src = this;
up.src = this;
down.src = this;
// CONTENTS EVENT HANDLERS
var newY; // trick compiler
var isEasing;
var speed; // trick the compiler
content.speed = move_speed;
content.onEnterFrame = function()
{
if (this.isEasing)
{
this._y += (this.newY-this._y) >> this.speed;
return;
}
this._y = this.newY;
}
// DRAGGERS EVENT HANLDERS
dragger.onPress = function()
{
this.startDrag(false, this.src.left, this.src.top, this.src.right, this.src.bottom);
this.onMouseMove = function()
{
this.src.updateContentPos();
}
}
dragger.onMouseUp = function()
{
stopDrag();
delete this.onMouseMove;
}
// UP BUTTONS EVENT HANDLERS
up.onPress = function()
{
this.onEnterFrame = function()
{
this.src.dragger._y = Math.max(this.src.top, this.src.dragger._y-this.src.move_speed);
this.src.updateContentPos();
}
}
up.onDragOut = up.onRelease = function()
{
delete this.onEnterFrame;
}
// DOWN BUTTONS EVENT HANDLERS
down.onPress = function()
{
this.onEnterFrame = function()
{
this.src.dragger._y = Math.min(this.src.bottom, this.src.dragger._y+this.src.move_speed);
this.src.updateContentPos();
}
}
down.onDragOut = down.onRelease = function()
{
delete this.onEnterFrame;
}
}
}
Take Care.
_Michael