Flex 4.5 HSlider and the Accelerometer? - actionscript-3

I'm trying to use a spark HSlider on a mobile device. I can get the thumb to move just fine in response to the accelerometer. But there are two problems:
1) the thumb flies right off the end of the screen when you tilt it in either direction. I've put in code below to try to stop this but it doesn't work.
2) I've got a little meter needle that is supposed to follow the position of the thumb, i.e. it points at it. This works fine when I drag the thumb -- when the change event is firing -- but not when the accelerometer is making it move. I think (not sure) that this might work if I could force the change event to fire?
Edit: The trace statements show that h.value isn't changing when it's the that accelerometer makes the thumb move. Also I removed a duplicate call to init().
Code:
<?xml version="1.0" encoding="utf-8"?>
<s:View xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark" title="HomeView" creationComplete="init()">
<fx:Script>
<![CDATA[
import flash.sensors.Accelerometer;
import mx.events.FlexEvent;
public var a:Accelerometer = new Accelerometer();
private var xSpeed:Number = 0;
private var newX:Number = 0;
private function init():void
{
this.addEventListener( Event.ADDED_TO_STAGE , addedToStageHandler );
}
private function addedToStageHandler(e:Event):void
{
h.value = h.minimum;
needle.rotationZ = h.value + 180;
if(Accelerometer.isSupported)
{
a.addEventListener(AccelerometerEvent.UPDATE, readA);
stage.autoOrients = false;
}
}
private function readA(e:AccelerometerEvent):void
{
xSpeed -= e.accelerationX * 5;
newX = h.thumb.x + xSpeed;
if(h.thumb.x < 0 )
{
newX = 0;
xSpeed = 0;
}
else if (newX > stage.stageWidth - h.thumb.width) //(newX > stage.stageWidth - RADIUS)
{
newX = stage.stageWidth - h.thumb.width;
xSpeed = 0;
}
else
{
newX += xSpeed
}
h.thumb.x += xSpeed;
trace("thumb.x = " + h.thumb.x);
needle.rotationZ = h.value + 180;
trace("h.value = " + h.value);
trace("needle.rotationZ = " + needle.rotationZ);
}
protected function h_changeHandler(event:Event):void
{
// TODO Auto-generated method stub
needle.rotationZ = h.value + 180;
trace(needle.rotationZ);
}
]]>
</fx:Script>
<s:HSlider change="h_changeHandler(event)" minimum="-54" maximum="54" id="h" width="300" x="158" y="74"/>
<s:BorderContainer x="158" y="200" width="300" height="1">
<s:Rect id="needle" x="150" y="0" width="2" height="100" rotation="180">
<s:fill>
<s:SolidColor color="#FF0000"/>
</s:fill>
</s:Rect>
</s:BorderContainer>
</s:View>

Looks like you are moving the thumb's position directly. You should instead be changing the HSlider.value property and letting the component position the thumb accordingly.
The change event only fires if the value of the HSlider is changed via a user interaction (like a drag/click). Sounds like you might want to listen for the valueCommit event which will fire whenever the value of the HSlider changes whether that is programmatically or via user interaction.

Related

flex 4.6 3D rotation axis

I am trying to perform some 3D rotation on pictures, but it harder than it look.
The fact is that when you rotate a picture on the axis X and/or Y, it look stretched (but it's normal). But when you make a rotation from the axis Z, the picture rotate around the Z axis of the screen instead of it own axis. So it look like a stretched picture which turn around an axis instead of a plate picture, viewed from a side and which turn around it center.
Since I know it's a little confusing, here is the function I am using. You can try it with a circular picture for a better "effect". Just imagine you want a rotating circle, no mater the orientation. You will see that the picture rotate around the axis of the screen insteat of it's own axis.
public function rotate(target:IVisualElement, x:Number = 0, y:Number = 0, z:Number = 0, duration:Number = 1000):void
{
var rotation:Rotate3D = new Rotate3D();
rotation.autoCenterTransform = true;
rotation.angleXTo = x;
rotation.angleYTo = y;
rotation.angleZTo = z;
rotation.duration = duration;
rotation.target = target;
rotation.play();
}
Is there a easy simple way to perform theses rotations without having to redevelop the wheel ?
Finally I managed to have something which work perfectly and without external library. The trick was so simple that I don't understand why I don't tried it before.
Instead of applying X, Y and Z transformations on the same element, I apply the X and Y rotations on a container and the Z axis on the picture inside the container.
Like this, the Z rotation doesn't disturb the other axis anymore.
Here is the working test code:
<fx:Script>
<![CDATA[
private function init():void
{
moveZ();
var timer:Timer = new Timer(5000);
timer.addEventListener(TimerEvent.TIMER, repeat);
timer.start();
}
private function repeat(e:TimerEvent):void
{
moveZ();
}
private function moveX():void
{
rotX += 20;
fx.angleXTo = rotX;
fx.angleYTo = rotY;
fx.angleZTo = 0;
fx.duration = 1000;
fx.play(new Array(container));
}
private function moveY():void
{
rotY += 20;
fx.angleXTo = rotX;
fx.angleYTo = rotY;
fx.angleZTo = 0;
fx.duration = 1000;
fx.play(new Array(container));
}
private function moveZ():void
{
rotZ += 360;
fx.angleXTo = 0;
fx.angleYTo = 0;
fx.angleZTo = rotZ;
fx.duration = 5000;
fx.play(new Array(image));
}
]]>
</fx:Script>
<fx:Declarations>
<fx:Number id="rotX">0</fx:Number>
<fx:Number id="rotY">0</fx:Number>
<fx:Number id="rotZ">0</fx:Number>
<s:Rotate3D id="fx" autoCenterProjection="true" autoCenterTransform="true"/>
</fx:Declarations>
<s:VGroup id="vGroup" left="10" top="10">
<s:Button label="X" buttonDown="moveX()"/>
<s:Button label="Y" buttonDown="moveY()"/>
</s:VGroup>
<s:BorderContainer id="container" width="200" height="200" horizontalCenter="0"
verticalCenter="0">
<s:BitmapImage id="image" width="200" height="200" horizontalCenter="0" smooth="true"
source="#Embed('assets/circle.png')" verticalCenter="0"/>
</s:BorderContainer>

AS3 Extended Jump when Holding Button

So my mario project must include a staple of Mario's movement, and that of course is the option to jump a short height or a fairly large one. As we all know, holding down the jump button makes him jump higher, that's what my goal is here. In my case, that button is X and I am unsure of how to do that.
This is currently my unsuccessful attempt, and gravity is set to 0.87 by default in my variables.
This is in my keyDownHandler (when the key is pressed)
if (event.keyCode == Keyboard.X && onGround == true)
{
vy += jumpForce;
holdJump = true;
onGround = false;
if(holdJump == true && onGround == false)
{
_mario.y += 1;
}
else
{
vy = vy + (grav * 0.20);
holdJump = false;
}
This is in my keyUpHandler (when the key is not pressed/let go)
if (event.keyCode == Keyboard.X)
{
if (holdJump == false)
{
accy = 0;
gravity = 0.80;
incSpeedY = 0;
}
}
Ok, I've extended my comment.
You can use standard vy=vyLast-g*(t-tLast), and just set vyLast to min(0,vyLast) when jump key is released, and set it to jump starting speed when jump key is pressed on the ground.
Here is the sample Adobe Air application with jumping red circle. It implements the logics that I've described into the comment:
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
>
<fx:Script>
<![CDATA[
import flash.utils.getTimer;
import mx.graphics.SolidColor;
public var marioY:Number = 0; //jump height above ground (meters)
public var g:Number = -9.81; //meter/(second^2)
public var lastTime:Number = NaN;
public var lastVerticalSpeed:Number = 0;//speed of a flight -meters/second
public var jumpSpeed:Number = 10;//initial jump speed - meters/second
public var timeRatio:Number = 1000;//milliseconds in a second
public var heightRatio:Number = 50; //pixels/meter
protected function get landed():Boolean{
return marioY <= 0 && lastVerticalSpeed <= 0;
}
protected function onKeyDown(event:KeyboardEvent):void{
if(event.keyCode==Keyboard.UP && landed){
lastVerticalSpeed = jumpSpeed;
trace('fly!');
}
}
protected function onKeyUp(event:KeyboardEvent):void{
if(event.keyCode==Keyboard.UP){
lastVerticalSpeed = Math.min(0,lastVerticalSpeed);
trace('fall!');
}
}
protected function onEnterFrame(event:Event):void{
if(!isNaN(lastTime)){
var deltaTime:Number = (getTimer() - lastTime)/timeRatio;
marioY+=lastVerticalSpeed*deltaTime;
if(landed){
lastVerticalSpeed=0;
marioY=0;
}else{
lastVerticalSpeed+=g*deltaTime;
}
}
mario.y=area.height-marioY*heightRatio-20;
lastTime = getTimer();
}
]]>
</fx:Script>
<s:Group width="100%" height="100%" keyDown="onKeyDown(event)" keyUp="onKeyUp(event)"
enterFrame="onEnterFrame(event)" id="area"
creationComplete="area.setFocus()"
>
<s:Rect width="100%" height="100%" fill="{new SolidColor(0x0000FF)}"/>
<s:Ellipse id="mario" width="10" height="10" fill="{new SolidColor(0xFF0000)}"
y="100" x="100"
/>
</s:Group>
</s:WindowedApplication>

AIR Window Scale and Stage Scale

I have an AIR application that I would like to allow the user to scale from 60% to 200%. I have added a slider in an options menu that controls the scaling of the application. I'm confused on how to go about scaling the entire application properly and need a little help, I've been at this for quite some time now.
The code for this simple test is below. In adding traces everywhere and putting listeners on resize events, I have basically discovered that setting the scaleX and scaleY value of the window does not change the scaleX and scaleY of the stage. But, these stage values cannot be edited and an error is thrown if you try.
So, then I tried adjusting the stage.stageWidth and stage.stageHeight to match stage.width and stage.height. But, in doing that, the contents of the window are scaled again.
Basically what ends up happening is with anything over 100%, or the minWidth & minHeight, components inside the window end up clipping with parts appearing cut off because the stage.stageWidth is not as wide as the stage.width and stage.stageHeight is not as tall as the stage.height.
<?xml version="1.0" encoding="utf-8"?>
<s:Window xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="250" height="300"
minWidth="260" minHeight="280"
showStatusBar="false"
systemChrome="none" transparent="true"
initialize="_init()" creationComplete="_initPostCreation()"
maximizable="false" minimizable="false" xmlns:Components="assets.skins.CompOverlay.Components.*">
<fx:Declarations>
</fx:Declarations>
<s:VGroup left="2" top="2" right="2" bottom="2" gap="0">
<s:Label width="100%" textAlign="center" text="Window Scale" fontSize="14" />
<s:HGroup width="100%">
<s:HSlider id="winScale" minimum="0.6" maximum="2" width="80%" snapInterval="0.01" showDataTip="false" change="_winScale(event)" />
<s:Label width="20%" fontSize="14" textAlign="center" text="{Math.round(winScale.value*100) + '%'}"/>
</s:HGroup>
</s:VGroup>
<fx:Script>
<![CDATA[
import mx.events.ResizeEvent;
private function _init():void
{
}
private function _initPostCreation():void
{
this.addEventListener(Event.CLOSING, this._destructor);
this.stage.scaleMode = StageScaleMode.NO_SCALE;
this.stage.addEventListener(Event.RESIZE, _onResize);
this.addEventListener(ResizeEvent.RESIZE, _onWinResize);
this.stage.align = StageAlign.TOP_LEFT;
}
private function _destructor(event:Event):void
{
this.removeEventListener(Event.CLOSING, this._destructor);
this.stage.removeEventListener(Event.RESIZE, _onResize);
this.removeEventListener(ResizeEvent.RESIZE, _onWinResize);
}
private function _winScale(event:Event):void
{
this.scaleX = event.target.value;
this.scaleY = this.scaleX;
this.width = (260*this.scaleX);
this.height = (300*this.scaleY);
trace(this.width, this.height);
trace(this.scaleX, this.scaleY);
}
private function _onResize(event:Event):void
{
trace('start resize----');
trace('stage.width = '+this.stage.width, 'stage.height = '+this.stage.height);
trace('stage.stageWidth = '+this.stage.stageWidth, 'stage.stageHeight = '+this.stage.stageHeight);
if (this.initialized) {
if (this.stage.width != this.stage.stageWidth) {
this.stage.removeEventListener(Event.RESIZE, _onResize);
this.stage.stageWidth = this.stage.width;
this.stage.stageHeight = this.stage.height;
this.stage.addEventListener(Event.RESIZE, _onResize);
}
trace('stage.width = '+this.stage.width, 'stage.height = '+this.stage.height);
trace('stage.stageWidth = '+this.stage.stageWidth, 'stage.stageHeight = '+this.stage.stageHeight);
trace('stage.scaleX = '+this.stage.scaleX, 'stage.scaleY = '+this.stage.scaleY);
}
trace('end resize----');
}
private function _onWinResize(event:ResizeEvent):void
{
trace ('window resize event');
if (this.stage.width != this.stage.stageWidth) {
event.stopPropagation();
trace('prop stopped');
}
}
]]>
</fx:Script>
</s:Window>
Resizing the window a few times results in this trace output:
start resize----
stage.width = 291.5 stage.height = 316.9
stage.stageWidth = 275 stage.stageHeight = 297
window resize event
prop stopped
window resize event
prop stopped
stage.width = 308.45 stage.height = 337.05
stage.stageWidth = 291 stage.stageHeight = 316
stage.scaleX = 1 stage.scaleY = 1 stage.scaleMode = noScale
end resize----
window resize event
prop stopped
start resize----
stage.width = 308.45 stage.height = 339.2
stage.stageWidth = 291 stage.stageHeight = 318
window resize event
prop stopped
window resize event
prop stopped
stage.width = 326.5 stage.height = 361.45
stage.stageWidth = 308 stage.stageHeight = 339
stage.scaleX = 1 stage.scaleY = 1 stage.scaleMode = noScale
end resize----
I appreciate any help, thanks!

Flex/AS3: a generic click-and-drag zoom example, working except for one issue

I adopted the code from this website,
http://blog.ninjacaptain.com/2010/03/flex-chart-zoom-window/
Note that the bug mentioned in the web blog concerning displaying datatips appears to have been fixed (at least as of 4.5.1 SDK). I'm able to see the datatips fine.
The code works well except for one issue. I've added the complete code below so you can just copy and paste as a new Flex application and run it.
The problem is simply when the user clicks once without dragging, which gives the following error (make sure you click it AS SOON AS the app first runs):
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at mx.charts.chartClasses::CartesianDataCanvas/localToData()[E:\dev\4.5.1\frameworks\projects\charts\src\mx\charts\chartClasses\CartesianDataCanvas.as:580]
Is there a way to capture when the user clicks without dragging like this and call some function to handle it? Or, any way to avoid this error? Thanks for any comments/suggestions.
The code is:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
initialize="init()" width="600" height="520">
<fx:Script>
<![CDATA[
[Bindable]
private var profits:Array;
private var dragStart:Point;
private var dragEnd:Point;
private var zooming:Boolean;
// initializes the data provider with random data
private function init():void{
profits = new Array({month: 0, profit: 15});
for(var i:int=1; i<40; i++)
profits.push({month: i, profit: Math.round(Math.random()*25-10)+profits[i-1].profit});
}
// sets the start point of the zoom window
private function startDraw(e:MouseEvent):void{
zooming = true;
dragStart = new Point(series1.mouseX, series1.mouseY);
}
// draws the zoom window as your mouse moves
private function showDraw(e:MouseEvent):void{
if(zooming){
dragEnd = new Point(series1.mouseX, series1.mouseY);
// finds the top-left and bottom-right ponits of the zoom window
var TL:Point = new Point(); // top-left point
var BR:Point = new Point(); // bottom-right point
if(dragStart.x < dragEnd.x){
TL.x = dragStart.x;
BR.x = dragEnd.x;
}
else{
TL.x = dragEnd.x;
BR.x = dragStart.x;
}
if(dragStart.y < dragEnd.y){
TL.y = dragStart.y;
BR.y = dragEnd.y;
}
else{
TL.y = dragEnd.y;
BR.y = dragStart.y;
}
// prevents the zoom window from going off the canvas
if(TL.x < 0) TL.x = 0;
if(BR.x > chartCanvas.width-1) BR.x = chartCanvas.width-1;
if(TL.y < 0) TL.y = 0;
if(BR.y > chartCanvas.height-1) BR.y = chartCanvas.height-1;
// draw the actual zoom window
chartCanvas.graphics.clear();
chartCanvas.graphics.lineStyle(1, 0x000000, 0.25);
chartCanvas.graphics.beginFill(0xd4e3f0,0.5);
chartCanvas.graphics.drawRect(TL.x, TL.y, BR.x-TL.x, BR.y-TL.y);
chartCanvas.graphics.endFill();
}
}
// clears the drawing canvas and sets the new max/mins
private function finishDraw(e:MouseEvent):void{
zooming = false;
chartCanvas.graphics.clear();
// converts the drag coordinates into axis data points
var chartValStart:Array = chartCanvas.localToData(dragStart);
var chartValEnd:Array = chartCanvas.localToData(dragEnd);
// sets the new maximum and minimum for both axes
haxis.minimum = (chartValStart[0] < chartValEnd[0]) ? chartValStart[0] : chartValEnd[0];
haxis.maximum = (chartValStart[0] < chartValEnd[0]) ? chartValEnd[0] : chartValStart[0];
vaxis.minimum = (chartValStart[1] < chartValEnd[1]) ? chartValStart[1] : chartValEnd[1];
vaxis.maximum = (chartValStart[1] < chartValEnd[1]) ? chartValEnd[1] : chartValStart[1];
}
// resets the axis max/mins
private function resetZoom():void{
haxis.minimum = NaN;
haxis.maximum = NaN;
vaxis.minimum = NaN;
vaxis.maximum = NaN;
}
]]>
</fx:Script>
<s:VGroup>
<mx:Panel title="Line Chart">
<mx:LineChart id="chart1"
mouseDown="startDraw(event)"
mouseMove="showDraw(event)"
mouseUp="finishDraw(event)"
width="510">
<!-- zoom window is drawn here -->
<mx:annotationElements>
<mx:CartesianDataCanvas id="chartCanvas"/>
</mx:annotationElements>
<mx:horizontalAxis>
<mx:LinearAxis id="haxis"/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id="vaxis"/>
</mx:verticalAxis>
<mx:series>
<mx:LineSeries filterData="false" id="series1" xField="month" yField="profit"
displayName="Profit" dataProvider="{profits}"/>
</mx:series>
</mx:LineChart>
</mx:Panel>
<mx:Button label="Reset Zoom" click="resetZoom()" />
</s:VGroup>
</s:Application>
UPDATE:
Here's the solution, in case it's useful to others. I've added an if statement to check for null dragStart and dragEnd values, as discussed in the answer below. Also, I've removed the drop shadow that flex places by default on the line series, so a warning doesn't appear if the zoom area the user selects is too small.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
initialize="init()" width="600" height="520">
<fx:Script>
<![CDATA[
[Bindable]
private var profits:Array;
private var dragStart:Point;
private var dragEnd:Point;
private var zooming:Boolean;
// initializes the data provider with random data
private function init():void{
profits = new Array({month: 0, profit: 15});
for(var i:int=1; i<40; i++)
profits.push({month: i, profit: Math.round(Math.random()*25-10)+profits[i-1].profit});
}
// sets the start point of the zoom window
private function startDraw(e:MouseEvent):void{
zooming = true;
dragStart = new Point(series1.mouseX, series1.mouseY);
}
// draws the zoom window as your mouse moves
private function showDraw(e:MouseEvent):void{
if(zooming){
dragEnd = new Point(series1.mouseX, series1.mouseY);
// finds the top-left and bottom-right ponits of the zoom window
var TL:Point = new Point(); // top-left point
var BR:Point = new Point(); // bottom-right point
if(dragStart.x < dragEnd.x){
TL.x = dragStart.x;
BR.x = dragEnd.x;
}
else{
TL.x = dragEnd.x;
BR.x = dragStart.x;
}
if(dragStart.y < dragEnd.y){
TL.y = dragStart.y;
BR.y = dragEnd.y;
}
else{
TL.y = dragEnd.y;
BR.y = dragStart.y;
}
// prevents the zoom window from going off the canvas
if(TL.x < 0) TL.x = 0;
if(BR.x > chartCanvas.width-1) BR.x = chartCanvas.width-1;
if(TL.y < 0) TL.y = 0;
if(BR.y > chartCanvas.height-1) BR.y = chartCanvas.height-1;
// draw the actual zoom window
chartCanvas.graphics.clear();
chartCanvas.graphics.lineStyle(1, 0x000000, 0.25);
chartCanvas.graphics.beginFill(0xd4e3f0,0.5);
chartCanvas.graphics.drawRect(TL.x, TL.y, BR.x-TL.x, BR.y-TL.y);
chartCanvas.graphics.endFill();
}
}
// clears the drawing canvas and sets the new max/mins
private function finishDraw(e:MouseEvent):void{
zooming = false;
chartCanvas.graphics.clear();
if (dragStart && dragEnd) { // Solution to original posted quesion
// converts the drag coordinates into axis data points
var chartValStart:Array = chartCanvas.localToData(dragStart);
var chartValEnd:Array = chartCanvas.localToData(dragEnd);
// sets the new maximum and minimum for both axes
haxis.minimum = (chartValStart[0] < chartValEnd[0]) ? chartValStart[0] : chartValEnd[0];
haxis.maximum = (chartValStart[0] < chartValEnd[0]) ? chartValEnd[0] : chartValStart[0];
vaxis.minimum = (chartValStart[1] < chartValEnd[1]) ? chartValStart[1] : chartValEnd[1];
vaxis.maximum = (chartValStart[1] < chartValEnd[1]) ? chartValEnd[1] : chartValStart[1];
}
// reset values for next time
dragStart=null;
dragEnd=null;
}
// resets the axis max/mins
private function resetZoom():void{
haxis.minimum = NaN;
haxis.maximum = NaN;
vaxis.minimum = NaN;
vaxis.maximum = NaN;
}
]]>
</fx:Script>
<s:VGroup>
<mx:Panel title="Line Chart">
<mx:LineChart id="chart1"
mouseDown="startDraw(event)"
mouseMove="showDraw(event)"
mouseUp="finishDraw(event)"
width="510">
<!-- zoom window is drawn here -->
<mx:annotationElements>
<mx:CartesianDataCanvas id="chartCanvas"/>
</mx:annotationElements>
<mx:horizontalAxis>
<mx:LinearAxis id="haxis"/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id="vaxis"/>
</mx:verticalAxis>
<mx:series>
<mx:LineSeries filterData="false" id="series1" xField="month" yField="profit"
displayName="Profit" dataProvider="{profits}"/>
</mx:series>
<mx:seriesFilters>
<fx:Array/>
</mx:seriesFilters>
</mx:LineChart>
</mx:Panel>
<mx:Button label="Reset Zoom" click="resetZoom()" />
</s:VGroup>
</s:Application>
You are getting this error because the variable dragEnd is never set if the user just clicks the mouse. The easiest way to prevent this would be check for null values inside your finishDraw function:
private function finishDraw(e:MouseEvent):void
{
zooming = false;
chartCanvas.clear();
if(dragStart && dragEnd)
{
//your stuff here
//...
}
//reset values for next time
dragStart=null;
dragEnd=null;
}
And this should avoid any further 1009 Errors there. Beware I am getting some Warnings if I drag a tiny small zoom window and then release the mouse because Flash has a limit on how big a DisplayObject can be, so you should validate also the dimensions of the zoom window.
Hope this helps!

EFFECT_REPEAT not firing on every iteration of Animate instance when losing focus

I'm not sure if that title is descriptive enough, but here is the basic issue. I have a spark.effects.Animate instance repeating n times with a listener on the EFFECT_REPEAT event. In that event's listener, I'm incrementing a variable. Logic would dictate that if the variable started at 0 and the animation was played with a repeatCount of 3, the variable would be 2 when finished. This works fine, until I focus a different tab. When doing this, on occasion, the repeat event isn't fired/handled (or the animation is just not actually doing the animation) and my count isn't correct when finished.
This is a fully functioning example built against Flex 4.5. To duplicate just click the GO button and maintain focus on the TAB. Then click it again and switch tabs and switch back. The counts don't match.
How can I fix this so that the repeat event is called consistently?
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" width="600" height="400" applicationComplete="application1_applicationCompleteHandler(event)">
<fx:Script>
<![CDATA[
import mx.controls.Image;
import mx.events.EffectEvent;
import mx.events.FlexEvent;
import spark.effects.Animate;
import spark.effects.animation.MotionPath;
import spark.effects.animation.SimpleMotionPath;
private var animate:Animate;
private var someCounter:int = 0;
protected function application1_applicationCompleteHandler(event:FlexEvent):void
{
// Create the graphic
var img:Image = new Image();
img.source = "http://www.google.com/intl/en_com/images/srpr/logo3w.png";
// Add the graphic
addElement( img );
// Create the motion path
var smp:SimpleMotionPath = new SimpleMotionPath();
smp.property = "x";
smp.valueFrom = 0;
smp.valueTo = this.width - 275;
// Add the motion path to a Vector
var paths:Vector.<MotionPath> = new Vector.<MotionPath>();
paths.push( smp );
// Create the animation
animate = new Animate();
animate.easer = null;
animate.target = img;
animate.duration = 150;
animate.repeatCount = 15;
animate.motionPaths = paths;
animate.addEventListener( EffectEvent.EFFECT_REPEAT, animate_effectRepeatHandler );
animate.addEventListener( EffectEvent.EFFECT_END, animate_effectEndHandler );
}
private function animate_effectRepeatHandler( event:EffectEvent ):void
{
lblCounter.text = someCounter.toString();
someCounter++;
}
private function animate_effectEndHandler( event:EffectEvent ):void
{
lblCounter.text = someCounter.toString(); // Sometimes doesn't equal animate.repeatCount - 1
}
protected function button1_clickHandler(event:MouseEvent):void
{
if( !animate.isPlaying )
{
someCounter = 0;
animate.play();
}
}
]]>
</fx:Script>
<mx:Label id="lblCounter" horizontalCenter="0" bottom="50" width="150" height="50" textAlign="center" />
<mx:Button horizontalCenter="0" bottom="0" label="GO" width="150" height="50" click="button1_clickHandler(event)" />
</s:Application>