Archive for April, 2009

Drag and Drop of rotated objects

Flex | Posted by Emanuele Spinella
Apr 06 2009

Adding drag and drop capabilities to a display object is quite simple: you have to listen for a MOUSE_DOWN event on that object and call the startDrag method.

< mx:Box id="cnt" width="400" height="400" x="200" y="100"
        backgroundColor="#555555">
	< mx:Canvas x="65" y="37" width="194" height="94"
		backgroundColor="#EF1414" id="img"
                mouseDown="startMove(event)"
		mouseUp="stopMove(event)">
	< /mx:Canvas>
< /mx:Box>

In the example above, there is a Box that acts as a container for a Canvas. The mouseDown event is then listened by the startMove method.

private function startMove(evt:Event):void
{
       img.startDrag();
}

The startDrag method without parameters lets you drag the object wherever you want.
To release the object, listen for the MOUSE_UP event and call the stopDrag method. The stopMove listener do this.

private function stopMove(evt:Event):void
{
      img.stopDrag();
}

If you want to drag only within a certain area, for example the cnt box, you need to define a bounding rectangle as a parameter of the startDrag method.
Let's modify the startMove method:

private function startMove(evt:Event):void
{
	// Bounding rectangle
	var boundingRect:Rectangle = new Rectangle();
 
	// Starting point in the container coordinates system
    	boundingRect.x = 0;
	boundingRect.y = 0;
 
    	// Allowed horizontal and vertical displacemnt
	boundingRect.width = cnt.width - img.width;
	boundingRect.height = cnt.height - img.height;
 
    	// Start drag
	img.startDrag(false,boundingRect);
}

It's simple, isn't it?
Now suppose to rotate the img object, specifying a rotation parameter.

< mx:Box id="cnt" width="400" height="400" x="200" y="100"
	backgroundColor="#555555">
	< mx:Canvas x="65" y="37" width="194" height="94"
		backgroundColor="#EF1414" id="img"
		rotation="0"
		mouseDown="startMove(event)"
		mouseUp="stopMove(event)">
	< /mx:Canvas>
< /mx:Box>

It seems that something doesn't work!
The rotation is only a visual effect, but for calculations about the bounds, the object is considered as unrotated!
Click here to see the result (the rotation is set to 45 degrees).

Unfortunately we need to keep in consideration the specified rotation while setting up the bounding rectangle.
We can use the getBounds method to obtain the rectangle whose sides are tangent to the img vertices.

private function startMove(evt:Event):void
{
	var rect:Rectangle = img.getBounds(cnt);
        ...
}

Basing on that rectangle we can calculate the right starting point, vertical and horizontal displacements for the draggable area.

private function startMove(evt:Event):void
{
		var rect:Rectangle = img.getBounds(cnt);
 
		// Bounding rectangle
		var boundingRect:Rectangle = new Rectangle();
 
		// Starting point in the container coordinates system
		boundingRect.x = (img.x-rect.x);
		boundingRect.y = (img.y-rect.y);
		boundingRect.width = (cnt.width-rect.width);
		boundingRect.height = (cnt.height-rect.height);
 
		// Start drag
	        img.startDrag(false,boundingRect);
}

Ok! It works!
If the rotation is 0 (zero) boundingRect.x and boundingRect.y are both 0 (zero), while rect.width and rect.height coincide with img.width and img.height. Now this is only a particular case!

Click here for the complete example.

Italian version on Actionscript.it