In this recipe we will animate the transition when switching between two data sets. We will show how to animate without using any libraries. To do so we will use the bar chart as a base. We are going to start by fading in the chart. After that, we will grow the bars until they reach their desired size. In order to animate the switch between the two data sets, we will first shrink the current bars until we can't see them so that we can expand the new bars after.
Copy over the files from Chapter 3, Creating Bar Charts, the Building vertical bar charts recipe, as we will start from those.
The following are the steps needed to animate a bar chart:
Bar.as
class, add the _onEnterFrame
function:private function _onEnterFrame(event:Event):void { var distance:Number = Math.abs(height - _targetHeight); if (distance < 0.1) { height = _targetHeight; removeEventListener(Event.ENTER_FRAME, _onEnterFrame); } else { height -= (height - _targetHeight) / 4; //the 4 here impacts on the speed of the animation, higher being slower } }
Bar.as
, add the two public functions animateIn
and animateOut
, as shown in the following code snippet:public function animateIn():void { _targetHeight = _startingHeight; addEventListener(Event.ENTER_FRAME, _onEnterFrame); } public function animateOut():void { _targetHeight = 0; addEventListener(Event.ENTER_FRAME, _onEnterFrame); }
BarChart.as
, start by setting the alpha
variable to 0
in the constructor.animateIn
and _onEnterFrame
functions:public function animateIn():void { addEventListener(Event.ENTER_FRAME, _onEnterFrame); setTimeout(_animateInBars, 1500); } private function _onEnterFrame(event:Event):void { if (alpha > .95) { alpha = 1; removeEventListener(Event.ENTER_FRAME, _onEnterFrame); } else { alpha += (1 - alpha) / 8; //the 8 here impacts on the speed of the animation, higher being slower } }
Vector
so that you animate them later on._animateInBars
and _animateOutBars
functions:private function _animateInBars():void { for (var i:int = 0; i < _barVector.length; i++) { _barVector[i].animateIn(); } } private function _animateOutBars():void { for (var i:int = 0; i < _barVector.length; i++) { _barVector[i].animateOut(); } }
update
and its follow up function _continueUpdate
:public function update(data:Vector.<BarData>):void { _data = data; _animateOutBars(); setTimeout(_continueUpdate, 800); } private function _continueUpdate():void { var i:int; for (i = 0; i < _barVector.length; i++) { removeChild(_barVector[i]); } _barVector = new Vector.<Bar>(); var bar:Bar; for (i = 0; i < _data.length; i++) { bar = new Bar(_barWidth, _data[i].data * _scaleHeight); bar.x = 10 + _barSpacing + _barWidth / 2 + i * (_barWidth + _barSpacing); bar.y = _newHeight - 10; _barVector.push(bar); addChild(bar); } addChild(_horizontalAxis); _animateInBars(); }
Main.as
, create a second data set called _data2
._chart
to animate in:setTimeout(_chart.animateIn, 1500);
setTimeout(_changeData, 8500); private function _changeData():void { _chart.update(_data2); }
Two tools are going to help us animate the bar chart: the enter frame listener function and the setTimeout
function.
By adding a listener to the event ENTER_FRAME
, we created a function that will be called every time a new frame is created. By updating a value such as alpha
or height
towards a target, we create an animation. Both in Bar.as
and BarChart.as
we use this as a stratagem (see step 1 and step 4).
Now this listener function is divided into two parts. Since we are getting closer to the value that is animated by a fraction, we first need to check if we are close enough to stop (otherwise you keep animating forever and it is not very optimal). If so, we set the value to the target and we stop animating. If not, we calculate the distance left, and we move forward by a fraction of the distance; for example, if we calculate half or a quarter of the distance left, then the smaller the fraction, the slower the animation will play. Eventually, our value is going to be very close to our target and the first condition will trigger.
You could animate differently based on time, instead of based on the distance, but in this way, you could easily get a nice easing, which means that our animation will be fast at first and slow in the end, finishing smoothly.
Another concept of animation is timing/delay. As an example to illustrate this, you may want to play another animation after the first one has played or you would want to play another animation after a certain amount of time. In ActionScript, there is a utility function called setTimeout
that lets you do so. It takes two parameters: the first is a function to be called after some time and the second is that said amount of time in milliseconds (1000 millisecond equals to 1 second).
With those tools in hand we can animate the bar chart. The following is the sequence of events. At 1.5 seconds, we fade in the graph (alpha
from 0 to 1). At 3 seconds, we animate in all the bars by making their heights go from 0 to their target values. At 8.5 seconds, we tell the chart to switch its data, so it will animate out all the bars and after 0.8 seconds, it will animate in the bars to their new heights.
For this recipe we used setTimeout
and the enter frame listener function but we could have just used the TweenLite
animation library.
TweenLite
is a very popular animation library that can be used very easily when animating one property, such as in this case the height of the bars. Here, instead of using the animateIn
and _onEnterFrame
functions, we could have used TweenLite
and it would have been one line instead of 10. Another really useful feature of TweenLite
is the delayedCall
function, which is very similar to setTimeout
but uses seconds instead of milliseconds. It's a small advantage, but it helps reduce confusion in the code. We chose to use TweenLite
in this book as it is the most used and fastest animation library out there.
3.129.13.201