Easy Flash Custom Scrollbar Class (AS2) – taterboy
September 10th, 2008 | Filed under: Flash AS2 to AS3, Tips

I know there are some really nice scroll components similar to this on the web, but I think this still has merit. It seems like every job comes with a different scroll bar design, the buttons and scroll bar can be any shape, size or configuration. While most Flash scroll bar components are easily skinned, this is kind of the opposite of skinning. You create the artwork, convert each item to a MovieClip, then apply the class. The code wraps the artwork instead of the artwork skinning the code.

This class started around 3 years ago and has been modified for many different projects and continued to evolve into what we have today. It is not perfect, but it can handle most jobs needing custom scroll bars.

Some of the features include:
Auto On/Off - you may need a scrolling clip that could change in size as dynamic content is displayed or entered. When the scroll bar is not needed, it will turn itself off and back on when it is needed. Or you can manually turn it on and with your code.

Easing - Control the amount of ease or delay of the scrolling object.

Scroll Bar Resizing - To simulate the function of desktop applications, the scroll bar will automatically scale depending on the amount of scroll, This feature can be turned on or off.

Auto Resize - Say you have a project that needs multiple scroll bars. One 150 px tall, the other 500 px tall. With this class you can build one set of artwork and the class will automatically adjust the bottom button, scroll background, scrollbar scroll area to fit the needed size.

Down Button Flip - This will not change the world, but if you have an Up Button that is exactly like the bottom button just flipped vertically. The class will compensate for this, saving a few minutes of development time and a few kilobytes.

Scroll Background Hiding and resizing - Many scroll bars have a background track, you may want it visible when the scroll bars are disabled as a visual place holder. This feature can be turned on or off.

Works without a scroll bar or without up and down buttons.

Button Type Effects - Even though the buttons and scrollbars are made with movieClips, sample code and calls are provided to give them button type effects on rollOver, rollOut, press and release.

Usage may seem a little complex at first, but if you like designing and using custom scroll bars and buttons, it is totally worth it.

1. Create all your scroll objects, they should be converted to MovieClips.
(upButton, DownButton, ScrollBar, and ScrollBkg)

2. Place the up and down buttons, scroll bar, and scroll background into a new movieClip.
(ScrollObject)

3. Align the top button and scrollbar to it’s starting position.

4. Create the MovieClip to be scrolled and mask it with another MovieClip.
(ScrollMovieClip, MaskMC)

5. Apply the class, this is the most complex part.

var scrollSet:HDScrollMC = HDScrollMC(ScrollObject,ScrollMovieClip,MaskMC,UpButton,DownButton,ScrollBar,ScrollBarResize,ScrollBkg,ScrollBkgHide,DownButtonFlip,ResizeScrollObjects,AutoOn,Ease);

This is where you assign all the MovieClips and enable any of the features. Other than the 7 MovieClips that the class points to, the other 6 arguments are features to enable or disable.

ScrollBarResize: Boolean
ScrollBkgHide: Boolean
DownButtonFlip: Boolean
ResizeScrollObjects: Boolean
AutoOn: Boolean
Ease: Number

Once it is enabled, it can manage itself or you can manage it manually with a method like so:
scrollSet.ScrollStatus(true); or scrollSet.ScrollStatus(false);

When you are done with everything, you can strip all the code out by calling scrollSet.killScrollBar();

import mx.utils.Delegate;
class com.hdi.util.HDScrollMC{
	/*
	HDScrollMC oringinally created 11/2005 by Todd Williams and HD Interactive.
	©2005 - 2008 HD Interactive & Taterboy, Inc.
	version: 2.1
 
	Compatibility:  Action Script 2, Flash Player 7 and higher.
	Purpose:
	To Build a scrollbar class that is truly portable and can be applied to custom artwork
	of any size and shape. This class wraps the graphics instead of graphics wrapping the code.
	This gives the designer complete 	control over look and feel. One of the major features
	needed was to have one set of scroll objects to be 	used in multiple instances and allow
	them to automatically conform to different scrolling needs. One set of scroll objects can
	control a scroll window that is 200 pixels tall or 600 pixels tall on the same stage at the 
	same time.
 
	Features:
		1. Automatically arranges scroll objects so that one set scrollbar objects can be used in multiple 
		    instances with different sized scrolling windows.
		2. Resizing scroll bar similar to OS and desktop application scroll bar behavior.
		3. Customizable Easing options for enhanced feel and response.
		4. Code Wraps to custom artwork instead of skinning a preexisting component.
		5. Auto on and off. The scroll bar is smart enough to know when it is needed or not.
		6. Code provided to build button type effects into MovieClip buttons and scrollbar.
		7. Have multiple scrolling objects visible and functioning on the same stage at a time.
 
 
	Preparation:
	To prepare graphic objects for use with HDScrollMC, you will need to create 7 MovieClips.
	MC 1. The MovieClip to be scrolled:
		 For scrolling text, create a TextField inside of a MovieClip, fill it with text manually, 
		 or use dynamic text and the TextField.autoSize = true;
 
	MC 2. Mask for MC 1 display area: This must be a MovieClip so that class can determine the size of the 
		masked area.
 
	MC 3. Container for Scroll Objects: To make it possible to have multiple scrolling objects on the
	stage at the same time, it is best to have at least the scrollbar and scroll button objects in a
	container, the mask and MC to be scrolled can also be in this container if desired.
 
	MC 4 & 5.  Scroll buttons UP and Down. These buttons are not required if a scrollbar only design is 
		needed. Scroll buttons can be movieClips or buttons. Code for rollover and press events will be 		sent to each button. If you want to use a MovieClip, disperse your button states on frames as you 		would a button and add a stop action to the first frame. Also the down button and be a vertically 		flipped instance if the top button if the artwork allows for this.
 
		The scroll buttons receive the following method calls from the class, use the method below for 
		MovieClips with button type effects.
		btnEvent(1); roll on
		btnEvent(0); roll out
		btnEvent(2); mouse down
		btnEvent(1); mouse up
		Sample:
		function btnEvent(val){
			if(val == 1){
				//roll on / release
			}
			else if(val == 2){
				//press
			}
			else{
				//roll out
			}
		}
		Super Simple Sample:
		function btnEvent(val){
			gotoAndStop(val+1);
		}
 
	MC 6. Scroll Bar: Must be a MovieClip and like the buttons, code will be sent for rollover and press events.
		A scrollbar is not required if a button only design is required. For the scroll bar has a resize feature 
		with two modes. The scroll bar will resize bases on the amount of scroll and the size of the scroll 
		area, similar to OS scroll bars. Mode 1 is the scrollbar MovieClip resizes the whole MovieClip. Some 
		graphic distortion or stretching may occur. You can set the scale9Grid to this MovieClip prior to 
		enabling this class. Mode 2 uses three MovieClips within the Scroll Bar to represent the top, middle 
		and bottom of the scroll bar, the middle will stretched will the top and bottom MovieClips will retain 
		their graphic integrity. To use this option divide the Scrollbar into three horizontal slices. Create 
		MovieClip instances named scrollbBarTop, scrollBarBot, and scrollBarMid.
 
		The scrollbar receives the following method calls from the class, use the method below for 
		MovieClips with button type effects.
 
		barEvent(1); roll on
		barEvent(0); roll out
		barEvent(2); mouse down
		barEvent(1); mouse up
		Sample:
		function barEvent(val){
			if(val == 1){
				//roll on / release
			}
			else if(val == 2){
				//press
			}
			else{
				//roll out
			}
		}
		Super Simple Sample:
		function btnEvent(val){
			gotoAndStop(val+1);
		}
 
	MC 7. Scroll background, Must be a MovieClip,  will span the entire size of the scroll area
		if the class is set to resize the objects. This MovieClip can be used to have a decorative
		track for the scroll area and can be set to vanish or remain when the scrollbar is enabled
		or disabled. This object is not required.
 
	Usage:
		Place the class folder in the working directory next to the fla you are using;
		add import com.hdi.util.HDScrollMS; to the actions panel before the code below.
 
	HDScrollMC(ScrollObject,ScrollMovieClip,MaskMC,UpButton,DownButton,ScrollBar,
	ScrollBarResize,ScrollBkg,ScrollBkgHide,DownButtonFlip,ResizeScrollObjects,AutoOn,Ease);
 
	I know there are a lot of arguments, and the descriptions/Usage are as follows:
	ScrollObject - (required) target of scroll object container, MC 3 from the preparation list.
	ScrollMovieClip - (required) target of MovieClip to be scrolled, MC 1 from preparation list.
	MaskMC - (required) target to Mask for the scrolling MovieClip, MC 2 from preparation list.
	UpButton - target or null, to Up Button MovieClip or Button. MC 4 & 5 from preparation list.
	DownButton - target  or null, to Down Button MovieClip or Button. MC 4 & 5 from preparation list.
	ScrollBar - target or null, to Scroll Bar MovieClip. MC 6 from preparation list.
	ScrollBarResize - Boolean: true or false, To enable scroll bar resizing depending on scroll amount.
	ScrollBkg - target or null, to scroll background graphic.
	ScrollBkgHide - Boolean: true or false, default behavior is to hide scroll background and scroll objects;
	DownButtonFlip - Boolean: true or false, If the down button is an instance of the up button that is
		vertically flipped.
	ResizeScrollObjects - Boolean: true or false, when scroll bar loads, it calculates the size of the mask, 
		buttons, scrollbars and distributes them to the appropriate height and coordinates. This allows 
		different instances of a set of scroll objects to be used with different sized scrolling Objects. 
	AutoOn - Boolean: true or false, Turns control of turning the scroll bar objects on and off to the class.
		If the scrolling MovieClip changes in size the class will automatically enable or disable the
		scroll objects.
	Ease - Number, changes the scrolling MovieClip's response to scroll events. set to 0 for no delay.
 
 
	Other methods and properties:
 
	scrollStatus:  property (Boolean) - tells if scrolling is enabled or disabled.
	setScrollStatus: Function - manually enables/disables scrolling.
	killScrollBar: Function - permanently disables the scrollbar and removes all listeners and events.
 
	Tips:
	1. For best performance, zero out  x and y coordinates to whole numbers on all MovieClips. 	
	Also try to build artwork with artwork rounded to the nearest whole pixel. This stops a lot
	of the little glitches 	that can appear when a user interacts with the scrolling objects.
 
	2. If you do not want you scroll objects to flash on then off on load, set the scroll Object
	Container's (MC 3) 	alpha property to 0. The class will automatically set it to 100 when enabled.
 
	3. By default the class uses the scroll background  and/or the up button to align and distribute
	the rest of the 	objects. You should align the top button and the top of the scroll background.
	The top of the scrollbar 	should be aligned to the button of the top button. These coordinates
	are used as starting points for all of 	the scroll objects and will return them to these
	positions when the scroll bar is reset.
 
	*/
	private var scrollObj:Object; //scroll MovieClip containing up button, down button, scrollbar, background.
	private var tClip:Object; //MovieClip that holds the text clip.
	private var tMask:Object; //Mask for the Text MovieClip, must be a MovieClip.
	private var dwnBtn:Object; //Down button, should be movieClip or button.
	private var upBtn:Object; //Down button, should be movieClip or button.
	private var scrollBar:Object; //MovieClip to do the scrolling.
	private var barAutoSize:Boolean; //Resizes the scroll bar to the scroll amount.
	private var scrollBkg:Object; //Background behind scrollButtons and scrollBar.
	private var scrollBkgHide:Boolean; //When scroll objects are not on, ScrollBkg is can be visible or not.
	private var flipDwnButton:Boolean; // If you have flipped the upBtn to make the dwnBtn. Used for autoResize.
	private var resizeObj:Boolean; // Resizes scroll objects to match the mask size and location.
	private var autoOn:Boolean; //Let's the scroll object control if the scrollBar is on or off, depending on the size of the text box.
	private var easeIn:Number; // Amount of delay for scrolling text to ease into possition.
	private var scrollYPos:Number;
	public var scrollStatus:Boolean; //Scrollbar is On or Off.
	private var inc:Number;
	private var resetAllSizes:Function;
	function HDScrollMC(targObj,tclip,tmask,upbtn,dwnbtn,sbar,barsize,sbkg,sbkgHide,flip,reSize,auto,ease){
		scrollObj = targObj;
		tClip = tclip;
		tMask = tmask;
		upBtn = upbtn;
		dwnBtn = dwnbtn;
		scrollBar = sbar;
		barAutoSize = barsize;
		scrollBkg = sbkg;
		scrollBkgHide = sbkgHide;
		flipDwnButton = flip;
		resizeObj = reSize;
		autoOn = auto;
		easeIn = ease;
		scrollYPos = tClip._y;
		if(tMask._height >= tClip._height){
			scrollStatus = false;
			if(scrollBkgHide && scrollBkg){
				scrollBkg._visible = false;
			}
		}
		else{
			scrollStatus = true;
		}
		var testConfig:Boolean = true;
		if(scrollObj == null || scrollObj == undefined){
			trace("ERROR: ScrollObject (arg 0) needs to be a valid MovieClip ");
			testConfig = false;
		}
		if(tMask == null || tMask == undefined){
			trace("ERROR: MaskMC (arg 2) needs to be a valid MovieClip - please mask the scrolling object with a named instance of a MovieClip");
			testConfig = false;
		}
		if(easeIn == NaN || easeIn == undefined){
			trace("ERROR: Ease (arg 12) needs to be a Number - 0 for no ease, 1 and higher to add ease/delay to the scrolling object");
			testConfig = false;
		}
		if((scrollBar == null || scrollBar == undefined) && (upBtn == null || upBtn == undefined) && (dwnBtn == null || dwnBtn == undefined)){
			trace("ERROR: Very funny, you need at least 1 control object (scrollBar, upBtn or dwnBtn) assigned to initiate scrolling");
			testConfig = false;
		}
		if(testConfig){
			init();
		}
	}
	public function setScrollStatus(val,overRide){
		scrollStatus = val;
		scrollObj.stat = val;
		scrollObj.yPos = scrollObj.starty;
		tClip._y = scrollObj.starty;
		scrollBar._y = scrollObj.bary;
		setSizes();
		if(val){
			upBtn._visible = true;
			dwnBtn._visible = true;
			scrollBar._visible = true;
			scrollBkg._visible = true;
		}
		else{
			upBtn._visible = false;
			dwnBtn._visible = false;
			scrollBar._visible = false;
			if(scrollBkgHide){
				scrollBkg._visible = false;
			}
		}
	}
	public function killScrollBar(){
		tClip._y = scrollObj.starty;
		scrollBar._y = scrollObj.bary;
		scrollObj.yPos = scrollObj.starty;
		upBtn._visible = false;
		dwnBtn._visible = false;
		scrollBar._visible = false;
		delete scrollObj.onEnterFrame;
		delete scrollBar.onMouseUp;
		delete scrollBar.onMouseDown;
		delete scrollBar.onMouseMove;
		delete upBtn.onMouseUp;
		delete upBtn.onMouseDown;
		delete dwnBtn.onMouseUp;
		delete dwnBtn.onMouseDown;
		delete upBtn.onRollOut;
		delete upBtn.onRollOver;
		delete dwnBtn.onRollOut;
		delete dwnBtn.onRollOver;
		delete scrollBar.onRollOut;
		delete scrollBar.onRollOver;
                clearInterval(inc);
		//Mouse.removeListener(scrollObj.myWheel);
	}
	private function setSizes(){
		if(tClip._y < scrollObj.starty - (tClip._height - scrollObj.maskh)){
			if(tClip._height <= scrollObj.maskh){
				scrollObj.yPos = scrollObj.starty;
			}
			else{
				scrollObj.yPos = scrollObj.starty - (tClip._height - scrollObj.maskh);
			}
		}
		else if(tClip._y > scrollObj.starty){
			scrollObj.yPos = scrollObj.starty;
		}
 
		tClip._y = scrollObj.yPos;
 
		if(barAutoSize == true){
		//setup dynamic scrollbar height.
			var sbHeight:Number;
			if(tClip._height > scrollObj.maskh){
				sbHeight = Math.floor((scrollObj.maskh / Math.ceil(tClip._height)) * scrollObj.bardist);
			}
			else{
				//sbHeight = 
			}
			if(sbHeight < 20){
				sbHeight = 20;
			}
			if(scrollBar.scrollbBarTop._name == undefined){
 
				scrollBar._height = sbHeight;
			}
			else{
				scrollBar.sheight = sbHeight
				scrollBar.scrollBarMid._height = scrollBar.sheight - (scrollBar.scrollbBarTop._height + scrollBar.scrollbBarTop._height);
				scrollBar.scrollbBarTop._y = scrollBar.scrollBarMid._height + scrollBar.scrollBarMid._y;
			}
 
		}
 
		scrollObj.bht = Math.ceil(scrollBar._height);
		scrollObj.barslack = (scrollObj.boty - scrollObj.topy) - scrollObj.bht;
		scrollObj.scrolldist = Math.ceil(Math.ceil(tClip._height) - (scrollObj.maskh)) + 10;
		scrollObj.scrollspeed = scrollObj.scrolldist / 8;
		scrollObj.yspeed = tMask._height/10;//16;
		scrollObj.upscroll = 0;
		scrollObj.dwnscroll = 0;
		scrollBar._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy;
	}
	private function setCoors(){
		tMask._height = Math.ceil(tMask._height);
		scrollObj.maskh = tMask._height;
		if(resizeObj){
			flipDwnButton == true? dwnBtn._y = Math.round(tMask._height): dwnBtn._y = Math.round((tMask._height) - dwnBtn._height);
			//flipDwnButton == true? dwnBtn._y = Math.round(tMask._height + tMask._y): dwnBtn._y = Math.round((tMask._height + tMask._y) - dwnBtn._height);
 
			if(scrollBkg != null){
				upBtn != null ? scrollBkg._height = scrollObj.maskh: scrollBkg._height = scrollObj.maskh;
			}
 
		}
		upBtn._y = Math.floor(upBtn._y);
		scrollObj.tht = Math.ceil(tClip._height);
		scrollObj.starty = tClip._y;
		scrollObj.barx = scrollBar._x;
		scrollObj.bary = scrollBar._y;
		if(upBtn != null){
			scrollObj.topy = Math.round(upBtn._y + upBtn._height);
			flipDwnButton == true? scrollObj.boty = Math.round(dwnBtn._y - dwnBtn._height): scrollObj.boty = Math.round(dwnBtn._y);
		}
		else{
			scrollObj.topy = Math.round(scrollBar._y);
			scrollObj.boty = Math.round(scrollBar._y + tMask._height);
		}
		scrollObj.bardist = (scrollObj.boty - scrollObj.topy);
		setSizes();
	}
 
	private function init(){
		setCoors();
		if(scrollStatus == false){
			upBtn._visible = false;
			dwnBtn._visible = false;
			scrollBar._visible = false;
		}
		else{
			upBtn._visible = true;
			dwnBtn._visible = true;
			scrollBar._visible = true;
		}
		scrollObj._alpha = 100;
		scrollObj.objectRef = this;
		scrollBar.objectRef = this;
		upBtn.objectRef = this;
		dwnBtn.objectRef = this;
		var scrollParent:Object = scrollObj;
 
		scrollObj.stat = scrollStatus;
		scrollObj.yPos = scrollYPos;
 
		/*//Enable MouseWheel - PC only and untested
		scrollObj.myWheel = new Object();
		scrollObj.myWheel.onMouseWheel = function(delta){
			//trace(delta);
 			if(scrollObj.stat){
				if(delta > 0){
					if(scrollObj.yPos < scrollObj.starty - scrollObj.yspeed){
						scrollObj.yPos += Math.round(scrollObj.yspeed);
						scrollBar._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy;
					}
					else{
						scrollObj.yPos = scrollObj.starty;
						scrollBar._y = scrollObj.topy;
					}
				}
				else if(delta < 0){
					if(scrollObj.yPos > scrollObj.starty - (scrollObj.scrolldist - scrollObj.yspeed)){
						scrollObj.yPos -= Math.round(scrollObj.yspeed);
						scrollBar._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy; 
					}
					else{
						scrollObj.yPos = scrollObj.starty - scrollObj.scrolldist;
						scrollBar._y = scrollObj.boty - scrollObj.bht;
					}
				}
			}
		}
		Mouse.addListener(scrollObj.myWheel);*/
 
		if(resizeObj){
			resetAllSizes = setCoors;//setSizes;
		}
 
		scrollBar.onMouseDown = function(){
			if(this._visible == true){
				if(this.hitTest(_root._xmouse, _root._ymouse, false)){
					this.barEvent(2);
					scrollParent.scrollchk = true;
					this.startDrag(false,scrollParent.barx,scrollParent.topy,scrollParent.barx,scrollParent.boty - scrollParent.bht);
					this.onMouseMove = function(){
						if(scrollParent.scrollchk == true){
							scrollParent.yPos = scrollParent.starty - (scrollParent.scrolldist * ((this._y - scrollParent.topy)  / scrollParent.barslack));
						}
 
					}
				}
			}
			else{
			}
		}
		scrollBar.onMouseUp = function(){
			scrollParent.scrollchk = false;
			if(this.hitTest(_root._xmouse, _root._ymouse, false)){
				this.barEvent(1);
			}
			this.stopDrag();
		}
		scrollBar.onRollOut = function(){
			this.barEvent(0);
		}
		scrollBar.onRollOver = function(){
			this.barEvent(1);
		}
		upBtn.onMouseDown = function(){
			if(this._visible == true){
				if(this.hitTest(_root._xmouse, _root._ymouse, false)){
					this.btnEvent(2);
					scrollParent.upscroll = 1;
				}
			}
		}
		upBtn.onMouseUp = function(){
			if(this.hitTest(_root._xmouse, _root._ymouse, false)){
				this.btnEvent(1);
			}
			else{
				this.btnEvent(0);
			}
			scrollParent.upscroll = 0;
		}
		upBtn.onRollOut = function(){
			this.btnEvent(0);
		}
		upBtn.onRollOver = function(){
			this.btnEvent(1);
		}
		dwnBtn.onMouseDown = function(){
			if(this._visible == true){
				if(this.hitTest(_root._xmouse, _root._ymouse, false)){
					this.btnEvent(2);
					scrollParent.dwnscroll = 1;
				}
			}
		}
		dwnBtn.onMouseUp = function(){
			if(this.hitTest(_root._xmouse, _root._ymouse, false)){
				this.btnEvent(1);
			}
			else{
				this.btnEvent(0);
			}
			scrollParent.dwnscroll = 0;
		}
		dwnBtn.onRollOut = function(){
			this.btnEvent(0);
		}
		dwnBtn.onRollOver = function(){
			this.btnEvent(1);
		}
		/*scrollObj.onEnterFrame = function(){
			if(this.upscroll == 1){
				if(this.yPos < this.starty - this.yspeed){
					this.yPos += Math.round(this.yspeed);
					this.objectRef.scrollBar._y = (((this.starty - this.yPos) / this.scrolldist) * this.barslack) + this.topy;
				}
				else{
					this.yPos = this.starty;
					this.objectRef.scrollBar._y = this.topy;
				}
			}
			if(this.dwnscroll == 1){
				if(this.yPos > this.starty - (this.scrolldist - this.yspeed)){
					this.yPos -= Math.round(this.yspeed);
					this.objectRef.scrollBar._y = (((this.starty - this.yPos) / this.scrolldist) * this.barslack) + this.topy; 
				}
				else{
					this.yPos = this.starty - this.scrolldist;
					this.objectRef.scrollBar._y = this.boty - this.bht;
				}
			}
 
			if(this.objectRef.scrollStatus){
				var dirStat:Number = 0;
				this.dwnscroll == 1 ? dirStat = -1:null;
				this.upscroll == 1 ? dirStat = 1:null;
				this.objectRef.easeMainClip(this.objectRef.tClip,this.yPos,this.objectRef.easeIn,dirStat);
				if(this.objectRef.autoOn){
					if(this.objectRef.tClip._height <= this.objectRef.tMask._height){
						this.objectRef.setScrollStatus(false);
					}
					var checkScrollDist:Number = Math.ceil(Math.ceil(this.objectRef.tClip._height) - (this.maskh)) + 10;
					if(this.scrolldist < this.objectRef.checkScrollDist){
						//reset size - ;
						this.objectRef.setSizes();
					}
					else if (this.scrolldist > this.objectRef.checkScrollDist){
						//reset size + ;
						this.objectRef.setSizes();
					}
				}
 
			}
			else{
				if(this.objectRef.autoOn){
					if(this.objectRef.tClip._height > this.objectRef.tMask._height){
						this.objectRef.setScrollStatus(true);
					}
				}
			}
		}*/
		inc = setInterval(Delegate.create(this, frameLoop),10);
	}
 
	private function frameLoop(){
		if(scrollObj.upscroll == 1){
				if(scrollObj.yPos < scrollObj.starty - scrollObj.yspeed){
					scrollObj.yPos += Math.round(scrollObj.yspeed);
					scrollBar._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy;
				}
				else{
					scrollObj.yPos = scrollObj.starty;
					scrollBar._y = scrollObj.topy;
				}
			}
			if(scrollObj.dwnscroll == 1){
				if(scrollObj.yPos > scrollObj.starty - (scrollObj.scrolldist - scrollObj.yspeed)){
					scrollObj.yPos -= Math.round(scrollObj.yspeed);
					scrollBar._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy; 
				}
				else{
					scrollObj.yPos = scrollObj.starty - scrollObj.scrolldist;
					scrollBar._y = scrollObj.boty - scrollObj.bht;
				}
			}
 
			if(scrollStatus){
				var dirStat:Number = 0;
				scrollObj.dwnscroll == 1 ? dirStat = -1:null;
				scrollObj.upscroll == 1 ? dirStat = 1:null;
				easeMainClip(tClip,scrollObj.yPos,easeIn,dirStat);
				if(autoOn){
					if(tClip._height <= tMask._height){
						setScrollStatus(false);
					}
					var checkScrollDist:Number = Math.ceil(Math.ceil(tClip._height) - (scrollObj.maskh)) + 10;
					if(scrollObj.scrolldist < checkScrollDist){
						//reset size - ;
						if(resetAllSizes && tMask._height != scrollObj.maskh){
							resetAllSizes()
						}
						setSizes();
					}
					else if (scrollObj.scrolldist > checkScrollDist){
						//reset size + ;
						if(resetAllSizes && tMask._height != scrollObj.maskh){
							resetAllSizes()
						}
						setSizes();
					}
				}
 
			}
			else{
				if(autoOn){
					if(tClip._height > tMask._height){
						setScrollStatus(true);
					}
				}
			}
			updateAfterEvent();
	}
	private function easeMainClip(obj,val,ease,dir){
		if(ease > 0){
			if(dir == 0){
				if(Math.floor(obj._y) > val + 1){
					dir = -1;
				}
				else if(Math.ceil(obj._y) < val - 1){
					dir = 1;
				}
			}
			if(dir == -1){
				obj._y -= (obj._y - val)/ease;
			}
			else if(dir == 1){
				obj._y += (val - obj._y)/ease;
			}
			else{
				obj._y = val;
			}
		}
		else{
			obj._y = val;
		}
	}
}

Demo:

Source Here

Major Update and rewrite (2.0), Please download again to update your files

1. Multiple instances now work
2. Scrollbar background will be invisible if the text is not the correct size.
3. Added in code for resizing the text MC and mask to be more browser like. Not fully tested but does not seem to break other features.
4. Added code for scroll wheel support, but is it commented out. I have not tested it yet with multiple instances.

Horizontal version (2.0) is is available here.
Horizontal Scroll Source

UPDATE: 2.1

Source can be updated, using the links above.
added - clearInterval(inc); to the killScrollBar method.

Thanks for the input and testing.

Technorati Tags: , ,

Related Posts:

|

41 Comments »

  1. hey, i started to use this and got the graphics made and went to load this in and got stuck this is y first AS project (yes my school is nuts) and was wondering if i could get help with what i need to code inside my Timeline to get this to work thanks

    Comment by richard — September 19, 2008 @ 8:19 am

  2. Did you get the source files?

    Make sure you have the com folder in the same directory as the fla you are working. If you copied the code, then place it in a file called HDScrollMC.as. Then place it in the following folder structure.
    com > hdi > util > HDScrollMC.as

    **place this on the first frame.
    //import HDScrollMS Class
    import com.hdi.util.HDScrollMC;

    ** then something like this:
    // my scrollbar and buttons are inside a MovieClip instance called sbars. this makes it so the scrollbars do not flash on load.
    sbars._alpha = 0;
    // if you want to use scale9Grid on the scroll graphics so there is not any distortion
    sbars.sbar.scale9Grid = true;
    // actual code to start the scroll bar working.
    var scrollSet:HDScrollMC = new HDScrollMC(sbars,sClip,tMask,sbars.upBtn,sbars.dwnBtn,sbars.sbar,true,sbars.sbkg,false,false,true,true,10);

    Arguments
    1. all my buttons and scroll bars are MovieClip instances inside a MovieClip instance called sbars
    2. sClip is the instance name of the MovieClip I want to scroll.
    3. tMask is the MovieClip instance of the mask that defines the viewable area.
    4.sbars.upBtn = target to up button instance
    5. sbars.dwnBtn = target to down Button instance
    6.sbars.sbar = target to scrollbar instance
    7. tells the class if the scrollbar should resize or not
    8. sbars.sbkg = target to scroll background track instance.
    9. tells class if the background graphic should hide when scrollbar is disabled.
    10. tells the class if the button button is a veritcally flipped version of the top button. (sometimes I am really lazy)
    11. tells class if it should monitor the scroll area to see if it needs to enable/disable the scrollbars automatically.
    If the the scroll MC will change in size because of dynamic text or loaded elements, the scroll bar can set the status automatically
    12. easing. 10 is nice and smooth but responsive.

    Hope this helps. Good luck.

    Comment by taterboy — September 19, 2008 @ 8:46 am

  3. Hey,

    first of all, this scroller class is great! I have one question. I’m trying to use this for a full browser project and need the scroller to scale the _y with onResize. can I call a method from with the onResize function to do this?
    When I use the original call:
    var scrollSet:HDScrollMC = new HDScrollMC(sbars, sClip, tMask, sbars.upBtn, sbars.dwnBtn, sbars.sbar, true, sbars.sbkg, false, false, true, true, 10);

    it works but the sBar resets to the top without resetting the target movieclip.

    Is there a way to stop the sBar from resetting, or can I call something else to re size the scroll on stage resize?

    Thanks a lot!!
    J

    Comment by Jason — September 19, 2008 @ 6:44 pm

  4. Here is a mod, you can replace the old HDScrollMC.as with.
    http://www.taterboy.com/blog/downloads/HDScrollMC.as.zip

    On resize, change the height of the MaskMC. If you have it set to resize and auto scroll status is true, it should work.

    I am not sure if this still works for with the original features without resizing the mask, when I have more time I will post a complete update.

    Thanks,

    Comment by taterboy — September 19, 2008 @ 7:52 pm

  5. Perfect! That works great. the mask is set to scale onResize and the scroller goes with it.
    Thanks for putting this out there.

    Comment by Jason — September 20, 2008 @ 6:22 am

  6. hi, nice work !!
    love how it works, can i set the scrollbar vertical and have a vertical easing?
    is it simple?

    Ben

    Comment by ben — September 23, 2008 @ 7:08 am

  7. Not sure if I understand your question.

    Comment by taterboy — September 23, 2008 @ 7:15 am

  8. lol yeah i made a mistake!!
    fast reply and thx for that,
    I mean instead of a vertical scollbar and easing i just want an horizontal one with horizontal easing.

    If its possible it will made my day!!

    Comment by ben — September 23, 2008 @ 7:22 am

  9. I was afraid that is what you were talking about, I have had that in the back of my mind for a while, just haven’t had time to update it. I should be able to modify it pretty fast to do that though, hang on.

    Comment by taterboy — September 23, 2008 @ 7:27 am

  10. yeah, that can be very cool. I looked your code but my AS is limited, as i just need horizontal scrolling i tryed to change all y in x & x in y :)
    don’t joke….

    thx for the help!

    Comment by ben — September 23, 2008 @ 7:38 am

  11. Here is a horizontal version.
    http://www.taterboy.com/blog/downloads/scrollHorizontal.zip

    Hope it helps.

    Comment by taterboy — September 23, 2008 @ 7:56 am

  12. I basically did a find and replace for _y to _x, and _height to _width. Then there were a few tweaks for the button/mouse hitTest and the scrollbar startdrag.

    Comment by taterboy — September 23, 2008 @ 8:00 am

  13. Wonderfull, many thx for the help, it made my day I appreciate dat!
    exactly what i wanted, will now try to integrate it in my project !
    i put your site in my favorite, we keep in touch.

    Comment by ben — September 23, 2008 @ 8:12 am

  14. Thank you!

    Comment by taterboy — September 23, 2008 @ 8:25 am

  15. Its me again, I have one more question….
    watch >>> on home page >>> http://www.realityshock.com/marc/template.html
    i just want when i click on the next buton it slide to the 4 next photo.
    can you help me again, would be wicked !

    thx again for your source!

    Comment by ben — September 24, 2008 @ 3:32 pm

  16. That would be a little different solution, You need something like this.

    http://www.taterboy.com/blog/downloads/MoveHorizontal.zip
    code below.

    // set on load, sets the default x position and the width of one full movement.
    // looks for the mask as a MovieClip. or you can enter the coordinates and x position manually.
    var portX:Number = tMask._x;
    var portWidth:Number = tMask._width;
     
    //set this once all the slides are in place.
    var id:Number = 1;
    var pages:Number = Math.floor(sClip._width/portWidth);
     
     
    // When you want to move the slides back an forth set this variable
    // id is the location of the portfolio.
    var newX:Number = portX - (portWidth * (id));
    // then call this function. portDisplay is the target to the scrolling movieclip.
    moveAni(portDisplay,newX);
     
    //You could have a function like this.
    function nextPage(val){
    	if(val > 0 && id <= pages){
    		id += 1;
    	}
    	else if(val < 0 && id > 1){
    		id -= 1;
    	}
    	var newX:Number = portX - (portWidth * (id - 1));
     
    	// just in case the port is not divided into exact equal parts.
    	// and you want the last page to not to go too far to the left.
    	// if it does not matter then comment this out.
    	if(val > 0 && id > pages){
    		if(Math.floor(sClip._width/portWidth) < (sClip._width/portWidth)){
    			newX = portX - (sClip._width - portWidth);
    		}
    	}
     
    	// then call this function. portDisplay is the target to the scrolling movieclip.
    	moveAni(sClip,newX);
    }
     
    //your buttons would call this like so.
    rtBtn.onRelease = function(){
    	nextPage(1);
     
    }
    ltBtn.onRelease = function(){
    	nextPage(-1);
    }
     
     
    //then add this code somewhere on the maintimeline.
    var moveCnt:Number = 0;
    var moveObj:MovieClip;
    function moveAni(obj,val){
    	if(moveObj){
    		moveObj.removeMovieClip();
    	}
    	moveObj = this.createEmptyMovieClip("m" + moveCnt,this.getNextHighestDepth());
    	moveObj.targ = obj;
    	moveObj.val = val;
    	if(moveObj.targ._x > val){
    		moveObj.dir = 0;
    	}
    	else{
    		moveObj.dir = 1;
    	}
    	moveObj.onEnterFrame = function(){
    		if(this.dir == 1){
    			if(Math.ceil(this.targ._x) < this.val - 1){
    				this.targ._x += (this.val - this.targ._x)/10;
    			}
    			else{
    				this.targ._x = this.val;
    				delete this.onEnterFrame;
    				this.removeMovieClip();
    			}
    		}
    		else{
    			if(Math.floor(this.targ._x) > this.val + 1){
    				this.targ._x -= (this.targ._x - this.val)/10;
    			}
    			else{
    				this.targ._x = this.val;
    				delete this.onEnterFrame;
    				this.removeMovieClip();
    			}
    		}
    	}
     
    	moveCnt ++;
    }
     
     
    stop();

    Comment by taterboy — September 24, 2008 @ 4:42 pm

  17. Your god >> You have all the answers of my questions…
    Exactly what i wanted, it work very well !!
    many thx Taterboy !

    Comment by ben — September 24, 2008 @ 5:41 pm

  18. Nice site by the way. Has a lot of nice features. I really like the texture in the background.
    Thanks.

    Comment by taterboy — September 25, 2008 @ 6:35 am

  19. awesome scrollbar, and so easy to use
    thank

    Comment by Zack — October 3, 2008 @ 1:43 am

  20. First off all great work.
    embeding non latin characters is possible?
    cause I am working with it for a day and always brings up problems.

    Comment by bill — October 8, 2008 @ 12:16 am

  21. Do you mean using non-latin characters as arguments for the new class instance or in the MovieClip that is to be scrolled?

    Comment by taterboy — October 8, 2008 @ 6:34 am

  22. This is a great scroll bar, thank you for it! One question though. How would you set the mask dynamically with as2?

    sClip.setMask(tMask);

    gives the error:

    ERROR: MaskMC (arg 2) needs to be a valid MovieClip - please mask the scrolling object with a named instance of a MovieClip

    I’d like to attach the scrollbar to dynamically created text objects in a separate movie but am trying to get things working on the sample you provided first. Any guidance would be greatly appreciated. Thanks again!

    Comment by eighty4 — October 20, 2008 @ 8:38 pm

  23. sClip.setMask(tMask); is correct.

    Just make sure you set it before you set the scrollbar.
    sClip.setMask(tMask);
    var scrollSet:HDScrollMC = new HDScrollMC(sbars,sClip,tMask,sbars.upBtn,sbars.dwnBtn,sbars.sbar,true,sbars.sbkg,false,false,true,true,10);

    Also check to make sure all the arguments for the HDscrollMC are valid. That error is saying that the sClip does not exist . sClip should be the MovieClip with your dynamic text objects. If the new MC has a different name, make sure you replace sClip with the new name in the arguments.

    Comment by taterboy — October 21, 2008 @ 6:45 am

  24. hey taterboy awesome scoller!

    Just trying to implement multiple scrollers, and I’m fairly new to this. See below what i have so far:

    - Movie clip with multiple frames
    - Each frame has a new sClip and sbars mc
    - Each frame calls the class…

    import com.hdi.util.HDScrollMC;

    sbars._alpha = 0;
    sbars.sbar.scale9Grid = true;

    var scrollSet:HDScrollMC = new HDScrollMC(sbars,sClip,tMask,sbars.upBtn,sbars.dwnBtn,sbars.sbar,true,sbars.sbkg,false,false,true,true,10);

    What am I doing wrong? if you scroll down on any item, and then change to another frame, the scrollbar is way off on the _y

    Your help will be much appreciated

    Comment by Colin — October 23, 2008 @ 1:19 am

  25. Before you call the HDScrollMC Class you need to reset the y position of the scrollbar(sbar). When the class loads it checks the y position to determine where the top _y is. If the class is called and the scrollbar is not at the top position, then it sets the current position as top _y.

    You can try something like, sbars.sbar._y = 0 (if 0 is the top position).

    Another issue may be the previous call to the class has not ended, and it still executing. you may want to kill the current instance of the class before advancing to the next frame.
    try this scrollSet.killScrollBar();

    Hope this helps.

    Comment by taterboy — October 23, 2008 @ 7:08 am

  26. Mate I have to agree with everyone here you really are a legend! you have all the answers

    I managed to fix my problem. It turns out by giving the sbars MC and sClip MC all a different instance name … ie sClip1 and sBars1, etc… this solved my problem site works great and looks great with your scollers… http://www.vipportfolio.com.au

    thanks again

    Comment by Colin — October 23, 2008 @ 3:31 pm

  27. Thanks for the kind words and the link.

    Comment by taterboy — October 24, 2008 @ 6:28 am

  28. Your Scrollbar Class is awesome!!!
    I guess you never use the UIScrollBar component in Flash, right?
    One more idea: do you think it is possible to add mousewheel function to your class?

    Comment by Jochen — October 27, 2008 @ 7:43 am

  29. You mean there is already a UIScrollBar? :) We use a ton of custom UI elements, we find it easier this way. Thanks for the compliment.

    MouseWheel does not work cross platform (Mac) that is why I did not include it in the original class. If you want to modify it to add this functionality, use this code below.

    //Place this line in the killScrollBar() function - removes listener

    Mouse.removeListener(scrollObj.myWheel);

    //Place this code in the init() function - I placed mine right above this line: scrollObj.stat = scrollStat;

                    //Enable MouseWheel - PC only
    		scrollObj.myWheel = new Object();
    		scrollObj.myWheel.onMouseWheel = function(delta){
    			trace(delta);
     
    			if(scrollObj.stat){
    				_root.dt.text = delta + " /  " +  scrollObj.stat;
    				if(delta > 0){
    					if(scrollObj.yPos < scrollObj.starty - scrollObj.yspeed){
    						scrollObj.yPos += Math.round(scrollObj.yspeed);
    						scrollBarClip._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy;
    					}
    					else{
    						scrollObj.yPos = scrollObj.starty;
    						scrollBarClip._y = scrollObj.topy;
    					}
    				}
    				else if(delta < 0){
    					if(scrollObj.yPos > scrollObj.starty - (scrollObj.scrolldist - scrollObj.yspeed)){
    						scrollObj.yPos -= Math.round(scrollObj.yspeed);
    						scrollBarClip._y = (((scrollObj.starty - scrollObj.yPos) / scrollObj.scrolldist) * scrollObj.barslack) + scrollObj.topy; 
    					}
    					else{
    						scrollObj.yPos = scrollObj.starty - scrollObj.scrolldist;
    						scrollBarClip._y = scrollObj.boty - scrollObj.bht;
    					}
    				}
    			}
    		}
    		Mouse.addListener(scrollObj.myWheel);

    There is a little bug when scrolling a MovieClip with a TextField. When auto is set to true and the scrollbar is turned on, if the textfield changes size smaller then the scroll area, the MouseWheel will still move the TextField’s text up and down one line. pretty minor.

    Comment by taterboy — October 27, 2008 @ 11:19 am

  30. Like the other ones, I only have good comments for your scrollbar class, very weel designed, it’s perfect for my needs!!

    But I think I found two bugs…

    1- did you try using two instances at the same time? Ex : I have a scroller MC and made two instances on the stage for two diffenrent group of content MC and mask MC (off course each with different instance name). I created two new HDScrollMC objects one for each group of scroll elements… of course again everything with different names… well it doesn’t work quite well… you might want to check it out.

    2- I did put the hideBkgnd to true, put it does not hide on init if the content is empty right on the begining (the scroller does hide, but not the background!). Once the content is filled then emptied, only then will the background disapear.

    Once again, all in all, it’s a fantastic class.
    Thanks

    Comment by Skipp — November 14, 2008 @ 7:13 pm

  31. I will have to look into that, I have used it on two instances at the same time and that is why it is designed that way it is, but I may have done some updates to it since which may have added some bugs, I will look into it and post an update if needed.

    also good catch on the background not working on init, I will check that out too.

    Thanks,

    Comment by taterboy — November 14, 2008 @ 7:24 pm

  32. So I am trying to load a loadVars and then style sheet into the sClip movie and it comes up invisible. I am not getting errors and if I like select the “invisible” text I can in fact copy and past. I have my own non-eased version of a scroller but this I cannot get to work on your wonderful class.

     
     
    import com.hdi.util.HDScrollMC;	
     
     
    var myFlashVar:String = myVars;
     
    sectionLabel.text = sectionTitle;
    var tvColor:String = sectionColor;
     
     
    trace("the TV BG color is" + tvColor);
     
    //---------------------------------\\
    var myLV:LoadVars = new LoadVars();
     
    myLV.onLoad = function (success) {
    	if (success){
    		trace("initial load vars success");
    		sClip.op.htmlText = myLV.info;
    	} else {
    		sClip.op.text = "There has been an error loading the requested information.  Please contact the Webmaster and report your error.";
    	}
    }
    //---------------------------------\\
     
    //---------------------------\\
    var cssStyles:TextField.StyleSheet = new TextField.StyleSheet ();
    cssStyles.load ("whiteStyles.css");
    trace("css var loaded");
    cssStyles.onLoad = function (success) {
    	if (success) {
    		sClip.op.styleSheet = cssStyles;
    		myLV.load(myVars);
    		trace("css styled text has loaded into dynamic text field");
    	} else {
    		sClip.op.text = "There has been an error loading the requested information.  Please contact the Webmaster and report your error.";
    	}
    }	
    //---------------------------\\
     
     
     
    tvBody_mc.gotoAndPlay(tvColor);
     
    stop();
     
     
     
    sectionLabel.autoSize = TextFieldAutoSize.LEFT;
     
     
    tvBody_mc.host_mc.setMask(screenMask_mc);
     
     
     
    // NEW SCROLLER ACTIONS
     
    //HDScrollMC(ScrollObject,ScrollMovieClip,MaskMC,UpButton,DownButton,ScrollBar,
    	//ScrollBarResize,ScrollBkg,ScrollBkgHide,DownButtonFlip,ResizeScrollObjects,AutoOn,Ease);
     
    sbars._alpha = 0;
    sbars.sbar.scale9Grid = true;
    var scrollSet:HDScrollMC = new HDScrollMC(sbars,sClip,tMask,sbars.upBtn,sbars.dwnBtn,sbars.sbar,true,sbars.sbkg,false,false,true,true,10);
     
    btn1.onRelease = function(){
    	sClip.op.htmlText = myLV.info;
    	sClip.op.autoSize = true;
    }
    btn2.onRelease = function(){
    	sClip.op.htmlText = myLV2.info;
    	sClip.op.autoSize = true;
    }
     
    stop();
     
    </code>
     
     
    From my txt file that gets called from a flashVars set on the html:
     
    <code>
    info=PRIZE BONANZA 
     
    Win $750, $1,000, or $1,250 if you refer a winner.
    New this year. Every month several HOT JOBS will qualify for double loot. HOT JOBS are SSOE%27s hard to fill positions. Prizes for a HOT JOBS hire are $1,500, $2,000 and $2,500.
    THERE%27S MORE! You%27ll get to spin the wheel and win one of these prizes:
     
     Big screen TV 
     Navigation system

    Comment by Carlitos — November 18, 2008 @ 12:33 pm

  33. Sorry didnt know how to wrap code. Tried using the typical syntax but didnt work.

    c.

    Comment by Carlitos — November 18, 2008 @ 12:45 pm

  34. Nice coding!

    But is there already a fix for comment 30 - problem 1?

    I’m having the same problem, please help!

    Comment by Rood — November 25, 2008 @ 3:45 pm

  35. The class has been updated to fix both issues from comment 30.

    Comment by taterboy — November 26, 2008 @ 12:25 pm

  36. Here is some sample code I used to get css to work with this setup.

    first change the textField font type to Device Font.

    //to load css
    var cssStyles:TextField.StyleSheet = new TextField.StyleSheet();
    cssStyles.onLoad = function (success) {
    	trace(success);
    	if (success) {
    		sClip.op.styleSheet = cssStyles;
    		sClip.op.htmlText = "<p class='body'>" + lessText +"</p>";
    		sClip.setMask(tMask);
    		//myLV.load(myVars);
    		trace("css styled text has loaded into dynamic text field");
    	} else {
    		trace("error");
    		sClip.op.text = "There has been an error loading the requested information.  Please contact the Webmaster and report your error.";
    	}
    }	
    cssStyles.load ("whiteStyles.css");

    //css file (whiteStyles.css)
    .body {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 24px;
    font-weight: bold;
    color:#00ff00;
    }

    Comment by taterboy — November 26, 2008 @ 12:28 pm

  37. I swapped your “less text” variable for my myLV.load(myVars) statement but it works. Thanks a ton I dig the edit ability of this and I wanted to use it as I have a couple others that I normally use but this was more fitting to what I was working on.

    Thanks again

    c.

    Comment by Carlitos — November 26, 2008 @ 1:18 pm

  38. Thanks for the bugs fix!! Do you have de fix for the Horizontal version also?

    When you have time, it would be nice to have the horizontal version in the same class and specified by a parameter…. I’m making your work here!! ;)

    Thanks a lot, very nice work!!

    Comment by Skipp — November 28, 2008 @ 10:20 am

  39. The horizontal version has been updated, http://www.taterboy.com/blog/downloads/scrollHorizontal.zip
    I was planning on updating everything, thanks for keeping me honest.

    Comment by taterboy — November 29, 2008 @ 8:52 pm

  40. Great scroller! Nice and simple. Easy to customize. Quick question, can I add a “buffer” to the end of the horizontal scroll? My scroll bar goes about 5-10 pixels to far to the right.

    Comment by Jason — December 3, 2008 @ 10:52 pm

  41. These variables control how far the scroll bar moves left and right
    scrollObj.barslack
    scrollObj.scrolldist (this is the one I would try first)

    also in the startDrag method, there are calculations for the left and right end points. You would have to add some buffer code in there too.

    First make sure all the art work and scroll object’s x and y coordinates are whole numbers if you are placing things on the stage. This helps the calculations. For some reason, things start to over lap when the coordinates are not whole numbers. I try to adjust this in the class and this may not be an issue, but something worth looking into.

    Comment by taterboy — December 4, 2008 @ 1:27 am

RSS feed for comments on this post. TrackBack URL

Leave a comment