10.15.2008 / Finding the nearest component in Flex

In Flex, we sometimes need to find the component nearest to the mouse cursor. The following example will show you how to do so. Here are the basic steps:

  1. We will set up an event listener to watch for mouse movements.
  2. On every mouse movement, we will loop through all the application’s children, evaluating each one.
  3. We retrieve the bounding rectangle for the component we are currently evaluating.
  4. If the cursor is to the left or right of the component, we find the distance between the x position of the cursor and the x position of the nearest vertical side of the bounding rectangle. If it’s not to the left or the right, the horizontal distance is zero.
  5. If the cursor is above or below the component, we find the distance between the y position of the cursor and the y position of the nearest horizontal side of the bounding rectangle. If it’s not to the top or the left, the vertical distance is zero.
  6. We use the Pythagorean theorem to find the actual distance between the cursor and the component using the two distances previously determined.
  7. If it is a shorter distance to the component we are evaluating than the distance to any of the components previously evaluated, we’ll make note of it.
  8. Finally, we report the closest component found.


Now for the code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="creationComplete();">
	<mx:Script>
		<![CDATA[
			import mx.core.UIComponent;
 
			/**
			 * @private
			 * Listen to mouse movements.
			 */
			private function creationComplete():void
			{
				addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler);
			}
 
			/**
			 * @private
			 * On each mouse move, evaluate the mouse cursor position
			 * to find the nearest child.
			 */
			private function mouseMoveHandler(event:MouseEvent):void
			{
				var closestDistance:Number;
				var closestChild:UIComponent;
 
				// Loop through children and find the child closest to the
				// mouse cursor.
				for each (var child:UIComponent in getChildren())
				{
					var distance:Number = getDistanceFromRect(
							event.stageX, event.stageY, child.getBounds(stage));
 
					if (isNaN(closestDistance) || distance < closestDistance)
					{
						closestDistance = distance;
						closestChild = child;
					}
				}
 
				trace('Closest Child: ' + UIComponent(closestChild).id);
			}
 
			/**
			 * @private
			 * Gets the distance between a point from a rectangle.  This doesn't evaluate the distance of
			 * the point from the center of the rectangle, but instead the distance of the point
			 * from the closest edge of the rectangle.
			 * 
			 * @param x The X coordinate of the point to be evaluated.
			 * @param y The Y coordinate of the point to be evaluated.
			 * @param rect The rectangle from which the distance will be measured to the point.
			 * 
			 * @return The distance in pixels between the point and the rectangle.
			 */
			private function getDistanceFromRect(x:Number, y:Number, rect:Rectangle):Number
			{
				// If the rectange contains the point we are evaluating, then there is
				// no distance between the point and the rectangle.
				if (rect.contains(x, y))
				{
					return 0;
				}
				else
				{
					// Retrieve distances to the closest edge.
					var xDist:Number = 0;
					var yDist:Number = 0;
 
					if (x < rect.left)
					{
						xDist = rect.left - x;
					}
					else if (x > rect.right)
					{
						xDist = x - rect.right;
					}
 
					if (y < rect.top)
					{
						yDist = rect.top - y;
					}
					else if (y > rect.bottom)
					{
						yDist = y - rect.bottom;
					}
 
					// Return the distance between the point and the nearest edge
					// using the Pythagorean theorem.
					return Math.sqrt(Math.pow(xDist, 2) + Math.pow(yDist, 2));
				}
			}
		]]>
	</mx:Script>
 
	<mx:Label id="topLeftLabel" text="Top-Left" top="10" left="10"/>
	<mx:Button id="bottomLeftButton" label="Bottom-Left" bottom="10" left="10"/>
	<mx:Text id="middleRightText" text="Middle-Right" verticalCenter="0" right="10"/>
 
</mx:Application>

Tags: , , ,


Comment

10.28.2008 / Andy said:

Congrats on the kid!! We are having a baby girl too — almost the same time as well (due ~ Feb 9). Interesting that you changed jobs, but I am glad that you are liking it.

We are still thoroughly enjoying Houston and XOM — I feel bad for this year’s almost recruits, it was a tough year for all campus recruiting from XOM. Very VERY few full time spots available.

congrats again on the girl!!


Leave a Comment

Your email address is required but will not be published.




Comment