I planned to arrange simple progress bar for my media player, drawing a colored rectangle and then changing it's width property as needed. Visually it looks ok - scales nicely (I could not draw it with zero width, so I assigned minimal value of 0.1).
Real problem is different though, and seems very weird, or at least absolutely non obvious. Since I need to monitor user clicks on that progress bar, to support seek operation in media stream, I thought - I would detect click event, take x coordinate as an offset from parent DisplayObject, recalculate into time and make a seek. Now it turns out, that event.localX doesn't really "scale" along with the Sprite. As I said the most right x coordinate for the progress bar initially is 0.1, and it stays that way (!) no matter how wide will the actual bar beco开发者_开发问答me - 5, 100, 1000. If you click the most right pixel of the bar, it will be - 0.1!
Huh?..
I obviously do something wrong. Maybe there is a method, like - refreshCoordinates() or something? What is it?..
Understanding why this happens is very important to understanding how Flash works. The key is to realize that every display object has its own coordinate system, and when your scope is inside that system it doesn't matter if the object itself is rotated, scaled, etc. If you live inside the bar graphic, all you know is that the graphic is 0.1 pixel wide, and that a click occurred on the right border. You have no idea whether the display object you live in has been stretched or transformed somewhere up the hierarchy. That's why the event property you're looking at is called localX
- it tells you where the click occurred locally, within that display object.
This is why, in this situation, it's very common to make the bar graphic 100 pixels wide, and then resize it however you want on the stage. If the graphic is internally 100px, and you detect clicks within that scope, then you can treat localX
like a percentage. And if you then redesign the page and change the visual width of the bar, you don't have to touch the code.
Incidentally, if you want to transform a location from one coordinate system to another, just use localToGlobal
and globalToLocal
together. That is:
var localToThis:Point = new Point( someX, someY );
var globalToStage:Point = localToGlobal( localToThis );
var localToParent:Point = parent.globalToLocal( globalToStage );
(Or another way to fix your problem would be to simply capture the click events further up the display hierarchy, where the bar really is 100px wide, rather than inside the graphic where it isn't.)
One final note: don't get in the habit of making graphics 0.1 pixels wide. With values that are related to rendering, like x
, rotation
, and so on, Flash sometimes rounds things off for performance reasons, below sizes that are visually distinguishable. Just make the object 100px or whatever, and transform it down to as small as you like.
I am guessing this has something to do with Global vs Local co-ordinates. Why don't you try LocalToGlobal
method? Here is an article which explains the function.
I've never come across this before but it sure looks weird. I was able to reproduce the problem drawing through the graphics
object and then changing the sprite width.
Anyway, there's a simple workaround. Draw your bar with the max width upfront and then scale it. Something like this:
var sp:Sprite = new Sprite();
sp.graphics.beginFill(0xff0000);
sp.graphics.drawRect(0,0,200,30);
sp.graphics.endFill();
sp.scaleX = 0;
sp.addEventListener(Event.ENTER_FRAME,handleEnterFrame);
sp.addEventListener(MouseEvent.CLICK,handleClick);
addChild(sp);
function handleClick(e:MouseEvent):void {
trace(e.localX);
}
function handleEnterFrame(e:Event):void {
sp.scaleX += 0.01;
}
I'm using an enter frame to simulate progress, but the point is that you update the scaleX
instead of the width
of the sprite to reflect the progress.
精彩评论