views:

124

answers:

1

If I have the following XML in actionscript 3:

<xml>
   <element1 x="10" y="10" width="200" height="200">
       <child>text</child>
       <child x="0" y="0" width="100" height="100">
            content
       </child>
   </element1>
   <element2 x="10" y="10" width="200" height="200">
   </element2>
   <element3>
   </element3>
</xml>

This is just an example. Now, what I want to do is the following: get the deepest child element with x, y, width and height attributes which is within a certain location. So, if the given location is 50x100 then ((child.@x <= x) && (child.@x + child.@width >= x) && (child.@y <= y) && (child.@y + child.@height >= y)) must be valid

In this case it should return the second child element named child with attributes x=0 and y=0 - the code should also keep in mind that the childs of elements' positions are relative to the parents position. So, if the child's X is 0 and the parent's X is 100 then the absolute child position is 100.

I'm struggeling to get this right, could anyone help me out?

In the end, the method

getDeepestChildAtLoc(50, 100)

should in the above example code return

<child x="0" y="0" width="100" height="100">
            content
       </child>

I hope this makes sense. Thank in advance.

Edit:

Judging by the lack of replies this might not be making a lot of sense. In any way, this is what I came up with so far - though it returns "null" all the time so obviousely there is a flaw:

//creates a new object at the given location, if existing elements are at the same location this will become a sub-element
  public static function addNewObject(type:String, x:uint, y:uint):void
  {
   //get page code
   var pageCode:XML = pageCodes[curPageId];
   trace(recProcessXML(pageCode, 0, x, y));
  }

  //recursively process childs to get the deepest child around the given position
  private static function recProcessXML(curElement:XML, depth:uint, targetX:uint, targetY:uint, totParentX:uint = 0, totParentY:uint = 0):XML
  {
   if (!curElement.children().length() > 0)
   { //this element has no further children
    return curElement;
   }
   else
   { //this element has further children
    var newChild:XML;
    var testChild:XML;
    for each (var child:XML in curElement.children())
    { //loop all children
     if (posInsideNode(child, totParentX, totParentY, targetX, targetY))
     { //if the child is still around the given position
      testChild = recProcessXML(child, depth + 1, targetX, targetY, child.@x + totParentX, child.@y + totParentY);
      if (testChild)
      { //if this child has further children
       newChild = testChild;
      }
     }
    }
    return newChild;
   }
   return null;
  }

  //returns whether the given position is inside the node
 private static function posInsideNode(child:XML, offsetX:uint, offsetY:uint, targetX:uint, targetY:uint):Boolean
 {
  trace("posInsideNode child: " + child.localName() + " -> " + child);
  //if all required properties are given for an element with content
  if (([email protected]() == 1) && ([email protected]() == 1) && ([email protected]() == 1) && ([email protected]() == 1))
  {
   //if the new object is inside this child
   if ((Number(child.@x) + offsetX <= targetX) && (Number(child.@x) + offsetX + Number(child.@width) >= targetX) && (Number(child.@y) + offsetY <= targetY) && (Number(child.@y) + offsetY + Number(child.@height) >= targetY))
   {
    return true;
   }
  }
  return false;
 }

Notice also how the depth variable has not been used yet, while it obviousely should as the one with the highest depth should be returned. I'm not sure where to put this in though... any help?

A: 

After three days of overdosis coffee, headache and a ton of googling aswell as way too much trial-and-error I found the solution.

//creates a new object at the given location, if existing elements are at the same location this will become a sub-element
     public static function addNewObject(type:String, x:uint, y:uint):void
     {
      //get page code
      var pageCode:XML = pageCodes[curPageId];
      trace(getDeepestElementAtPos(pageCode, 0, x, y)["xml"].toXMLString());
     }

     //returns the deepest element which surrounds the given position
     private static function getDeepestElementAtPos(curElement:XML, depth:uint, targetX:uint, targetY:uint, totParentX:uint = 0, totParentY:uint = 0):Object
     {
      var deepestElement:Object = new Object();
      deepestElement["xml"] = curElement;
      deepestElement["depth"] = depth;

      var posDeeperChild:Object;
      for each (var child:XML in curElement.children())
      {
       if (posInsideNode(child, totParentX, totParentY, targetX, targetY))
       {
        posDeeperChild = getDeepestElementAtPos(child, depth + 1, targetX, targetY, totParentX + Number(child.@x), totParentY + Number(child.@y));
        if (posDeeperChild["depth"] > depth) deepestElement = posDeeperChild;
       }
      }

      return deepestElement;
     }

     //returns whether the given position is inside the node
     private static function posInsideNode(child:XML, offsetX:uint, offsetY:uint, targetX:uint, targetY:uint):Boolean
     {
      //if all required properties are given for an element with content
      if (([email protected]() == 1) && ([email protected]() == 1) && ([email protected]() == 1) && ([email protected]() == 1))
      {
       //if the new object is inside this child
       if ((Number(child.@x) + offsetX <= targetX) && (Number(child.@x) + offsetX + Number(child.@width) >= targetX) && (Number(child.@y) + offsetY <= targetY) && (Number(child.@y) + offsetY + Number(child.@height) >= targetY))
       {
        return true;
       }
      }
      return false;
     }
Tom