1

I have created an empty sprite to use as a container.

I then add several symbols as children to the container (container.addChild(symbol)).

I then add an event handler to the container (container.addEventListener(MouseEvent.CLICK, containerClick)).

In the event handler I trace the event.localX and event.localY.

When I click on a symbol it reports the localX and localY relative to the symbol's registration point.

What I would like is the localX and localY relative to the container's registration point.

Is that possible?

John Morrison
  • 35
  • 1
  • 4

3 Answers3

1

Yes, there's several ways of doing it.

The most naive approach is to simply add the clicked symbol's x and y position to the localX and localY to get the clicked coordinate in the container's coordinate space (assuming the clicked symbol is a child of the container). But this fails if any transformation such as scaling or rotation of the symbols are involved.

The best approach is to use localToGlobal() and globalToLocal() to convert between coordinate spaces:

private function onSymbolClicked(event : MouseEvent) : void {
    // get the parent of the clicked symbol. We use currentTarget instead
    // of target because we want to get the display object the listener was
    // attached to (currentTarget) and not the clicked display object (target)
    // which might not be the same as currentTarget if the clicked symbol
    // contains children and mouseChildren is set to true. We store the parent
    // in a variable using the most generic data type which is DisplayObjectContainer
    var symbolParent : DisplayObjectContainer = DisplayObjectContainer(event.currentTarget.parent);

    // get the clicked point in global coordinate space and create a Point instance
    var point : Point = new Point(event.stageX, event.stageY);

    // convert the point from global coordinates to the coordinate space
    // of the clicked symbol's parent
    point = symbolParent.globalToLocal(point);

    trace(point);
}
Strille
  • 5,741
  • 2
  • 26
  • 40
  • Interesting but my scenario seems to differ from what you explain. Let's start with you naming the function onSymbolClicked. Does this mean the event listener is attached to the symbol and not the container? If so I don't think it will work for me because I would have to create hundreds or even thousands of listeners. Thoughts/clarification? – John Morrison Oct 24 '13 at 09:43
  • You can add the listener to the container, and then use event.target to determine which symbol inside the container you clicked on. Note that if the symbol you are interested in contains display objects as children and the symbol has mouseChildren set to true event.target will contain a reference to the symbol's child. – Strille Oct 24 '13 at 10:08
  • OK. I did some testing with your solution. It works but with a modification. When you ask for event.currentTarget.parent you are asking for the stage. Your solution works fine when you change that to event.currentTarget. Since my implementation will never use transformations on the symbols I'm inclined to use the solution provided by @CyanAngel because it doesn't create a new object. Having your solution in my toolbox will be helpful. – John Morrison Oct 24 '13 at 18:25
  • I have been working with your solution, which works great BTW, but I can't find any documentation on DisplayObjectContainer taking an argument. In fact all the documentation indicates DisplayObjectContainer can't be called directly. Would you direct me to any references pleas? – John Morrison Nov 04 '13 at 18:46
  • You can't create instances of it, but it's a data type. So you can "cast" any subclass (Loader, Sprite, MovieClip) to that data type. – Strille Nov 04 '13 at 19:34
0

I don't think there is a property in the event that will give you that, but some maths should give you what you need.

As you identified, the localX/Y is relative to the coordinates of the event target, if the target is a UIComponent its coordinates are relative to it's parent. So add one to another.

var containerX:Number;
var containerY:Number;

if(event.target !== container){
containerX = event.localX + event.target.x;
containerY = event.localY + event.target.y;
} else {
containerX = event.localX;
containerY = event.localY;
}
CyanAngel
  • 1,240
  • 1
  • 14
  • 28
  • 1
    Wouldn't just checking `event.currentTarget.localX` and `event.currentTarget.localY` be a better solution? That will always return the clicked coord in the container's coordinate space no matter where/what you clicked on. – Strille Oct 24 '13 at 11:18
  • My experience with `event.currentTarget` is that its dynamic depending on the events current position in the lifecycle. By using the fixed dispatcher (`event.target`) the code doesn't have to determine what level of the UI its executing at. – CyanAngel Oct 24 '13 at 11:46
  • @Strille - my testing shows the currentTarget does not have a localX attribute. Error #1069: Property localX not found on flash.display.Sprite and there is no default value. – John Morrison Oct 24 '13 at 18:02
  • Sorry, I meant `.mouseX` instead of `.localX`. – Strille Oct 25 '13 at 07:25
  • `container.mouseX` might be a good option, but I'd still advice against using `event.currentTarget` to resolve that unless you have your event listener on the container as the property shifts. Great explanation of how that works [here](http://stackoverflow.com/a/2334192/1856411) – CyanAngel Oct 25 '13 at 08:52
0
var rec:Rectangle = event.target.getBounds(event.target.parent);

var wantedX:Number = rec.x + event.localX;
var wantedY:Number = rec.y + event.localY;
Pan
  • 2,101
  • 3
  • 13
  • 17