Page 1. Basics

To illustrate drag-and-drop in ActionScript 3, we will first make some simple applications that involve dragging a circle on a rectangular board.

Each of the following examples have the following common code to draw a rectangular board on the stage and then add a circle as a child of the board. It might seem counterintuitive to build the relationships between myPoint, board, and stage before the graphics are added, but doing all of the "addChild" calls up front assures that the layering of the objects is exactly what we want. (The relationship between the board and the circle, though natural, can cause some issues with mouse events as we will see in a later tutorial.) Both of our objects are Sprites, with the "board" visually represented by a gray rectangle and the "myPoint" represented by a blue circle that is fairly large to illustrate some issues.

 

// Part 1 -- Setting up the objects

 

var board:Sprite = new Sprite();

var myPoint:Sprite = new Sprite();

 

this.addChild(board);

board.addChild(myPoint);

 

board.graphics.lineStyle(1,0);

board.graphics.beginFill(0xCCCCCC);

board.graphics.drawRect(0,0,400,300);

board.graphics.endFill();

board.x = 10;

board.y = 10;

 

myPoint.graphics.lineStyle(1,0);

myPoint.graphics.beginFill(0x0000FF,0.7);

myPoint.graphics.drawCircle(0,0,20);

myPoint.graphics.endFill();

myPoint.x = 50;

myPoint.y = 50;

 

Using the startDrag and stopDrag methods

Display Objects have methods called startDrag and stopDrag that make it easy to add this type of interface quickly to any application. The following additional code will add this functionality. The basic idea is that when the mouse is pressed down over our circle (the sprite named "myPoint"), the startDrag method is called and when the mouse is let up over our circle, the stopDrag method is called. Both startDrag and stopDrag are built-in methods of the Sprite class, so nothing else is needed.

 

// Part 2 -- Add drag-and-drop functionality

 

myPoint.addEventListener(MouseEvent.MOUSE_DOWN, startMove);

 

function startMove(evt:MouseEvent):void {

myPoint.startDrag();

}

 

myPoint.addEventListener(MouseEvent.MOUSE_UP, stopMove);

 

function stopMove(e:MouseEvent):void {

myPoint.stopDrag();

}

 

Download

Notes

  • This is quick because it requires so little code.
  • The dragging looks a little rough.
  • The dragging goes beyond the boundaries of the box. This can be remedied by adding an argument to the startDrag method call that specifies a rectangular boundary that the object cannot be dragged beyond. To use this, you should look up the help file for startDrag and be prepared to follow up by reading up on the Rectangle class.
  • It is not clear from this simple example, but we cannot easily control other actions that should be completed during the dragging of the ball. For example, if we want a line to be traced having the ball as one endpoint, it is not easy to have this line updated continuously as the ball is dragged, as one would want.

Drag-and-drop with the MOUSE_MOVE event

Certainly we could make the most of the built-in methods, but because we have greater ambitions for our drag-and-drop interface, we might as well start thinking now about how to do it ourselves. To fashion our own drag-and-drop interface that will give us more control, we examine the MOUSE_MOVE event that is triggered whenever the mouse is moved. We will deliberately take a few attempts at this so that we can better understand some of the subtleties of mouse events.

In our first attempt, we use the following code in place of the "Part 2" code shown above. The difference here is that when the "myPoint" sprite hears the MOUSE_DOWN event, a new listener is attached to myPoint so that it will subsequently hear the MOUSE_MOVE event. When the MOUSE_MOVE event is heard by myPoint, the x and y coordinates of myPoint are changed to correspond to the x and y coordinates of the mouse. Note that we use board.mouseX and board.mouseY because the values myPoint.x and myPoint.y refer to the coordinates of myPoint relative to its parent object, which is the "board" sprite. Hence, these need to be set to the x and y coordinates of the mouse relative to "board." When the MOUSE_UP event is heard, we simply remove the listener registered with the MOUSE_MOVE event, effectively stopping the motion. Also notice the use of the method updateAfterEvent, which refreshes the screen immediately after the mouse move event, making the "myPoint" sprite stay with the mouse cursor as much as possible.

 

// Part 2 -- First attempts are never good

 

myPoint.addEventListener(MouseEvent.MOUSE_DOWN, startMove);

function startMove(evt:MouseEvent):void {

myPoint.addEventListener(MouseEvent.MOUSE_MOVE, pointMove);

}

function pointMove(e:MouseEvent):void {

myPoint.x = board.mouseX;

myPoint.y = board.mouseY;

e.updateAfterEvent();

}

myPoint.addEventListener(MouseEvent.MOUSE_UP, stopMove);

function stopMove(e:MouseEvent):void {

myPoint.removeEventListener(MouseEvent.MOUSE_MOVE, pointMove);

}

 

Nothing in the design addresses the problems with the startDrag/stopDrag approach that we listed in the previous section. In fact, we have made things worse. Try out the applet and see if you can spot its other deficiencies.

The motion is smoother unless you move your mouse too fast in which case the motion actually stops! This happens because we registered our listener for the MOUSE_MOVE event with the circle (the sprite called "myPoint"), and so the MOUSE_MOVE event is only triggered when the mouse moves over the myPoint sprite. In reality, even though only the position of the myPoint sprite is affected by the mouse move, we want the mouse move event to trigger when the mouse moves anywhere over the stage. In addition, we register the listener for the MOUSE_UP event with the stage so that the motion will be stopped when the mouse button is released regardless of where the mouse is located.

The following code (which is identical to the above except that "myPoint" is changed to "stage" in three places, highlighted in bold text) accomplishes the change and gives a very nice smooth motion, as the applet the follows attests.

 

// Part 2 -- Better Attempt

 

myPoint.addEventListener(MouseEvent.MOUSE_DOWN, startMove);

 

function startMove(evt:MouseEvent):void {

stage.addEventListener(MouseEvent.MOUSE_MOVE, pointMove);

}

 

function pointMove(e:MouseEvent):void {

myPoint.x = board.mouseX;

myPoint.y = board.mouseY;

e.updateAfterEvent();

}

 

stage.addEventListener(MouseEvent.MOUSE_UP, stopMove);

 

function stopMove(e:MouseEvent):void {

stage.removeEventListener(MouseEvent.MOUSE_MOVE, pointMove);

}

 

If you think that you only want the "mouse move" event to trigger when you move the mouse over the sprite "board", make this change yourself and give this version a try as well. It works fine, but the behavior when the mouse is dragged off of the board is not as satisfactory as our solution below.

Download

  • Flash CS3 file DragDrop1.fla contains the improved version only.

Notes

  • This gives very smooth motion and functions that handle the repositioning of the point can be extended to manage all other manners of updates or changes while the mouse is in motion.
  • The dragging still goes beyond the boundaries of the box, and indeed the visible part of the stage!
  • You can drop the object off of the stage never to be seen again!

"Mouse move" drag-and-drop with restricted position

Being able to drop an object off-screen is clearly undesirable, so before we build a sample application we need to fix this problem. There are several possible solutions, but the one we will present has the advantage of being flexible enough for further improvements as needed.

We will add the following code to the end of the previous application to define functions called "goodX" and "goodY" that translate the current x and y mouse coordinates into "useable" x and y coordinates. In this case, we simply give instructions that if the current coordinate is too big or too small, then we should really use the biggest (resp. smallest) allowable value instead. To keep the point on the board, it is clear that the smallest allowable x value is simply 0, but the largest allowable x value is the width of the "board" graphic object, which is 400 by our Part I code. We have a similar issue with the y-coordinate.

 

// Part III

 

function goodX(inX:Number):Number {

if (inX < 0) {

return 0;

}

 

if (inX > 400) {

return 400;

}

 

return inX;

}

 

function goodY(inY:Number):Number {

if (inY < 0) {

return 0;

}

 

if (inY > 300) {

return 300;

}

 

return inY;

}

 

Adding this code alone will have no effect -- we need to place the myPoint sprite based on the transformed coordinates, hence we need the following revision of the pointMove function within Part II of our code. Only the new function definition with the two highlighted changes from the previous version is shown.

 

// Revised definition of pointMove in Part II of our script

 

function pointMove(e:MouseEvent):void {

myPoint.x = goodX(board.mouseX);

myPoint.y = goodY(board.mouseY);

e.updateAfterEvent();

}

 

Try this version out below. We think you will agree that the user interface is very nice, and we will see in our first easy application that the do-it-yourself approach allows for a great deal of flexibility.

Download

Notes

  • This gives very smooth motion and functions that handle the repositioning of the point can be extended to manage all other manners of updates or changes while the mouse is in motion. It stops at a sensibly chosen boundary and properly handles the motion of the mouse outside of this boundary.
  • We are playing with fire by having the constants 400 and 300 appear twice in our code. It would be easy for a programmer to inadvertently change these in only one place, leading to bad behavior that would be very difficult to debug. We really should declare variables bWidth = 400 and bHeight = 300 at the top of our script and then use the variable names where these values are needed. We adopt this common sense practice to all subsequent files in this tutorial.

Back to Basic Tutorials              Back to Flash and Math Home

We welcome your comments, suggestions, and contributions. Click the Contact Us link below and email one of us.

Adobe®, Flash®, ActionScript®, Flex® are registered trademarks of Adobe Systems Incorporated.