Glitz the Web Pages in Your ASP.NET AJAX Based Applications - Part 2
page 2 of 4
by Xianzhong Zhu
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 22168/ 76

Animation

About Animation

Nifty transitions between pages or elements make for nice eye candy, but they are tricky to implement and are achieved with a variety of transformations. For instance, visual changes in an element's opacity or position can be accomplished by gradual shifts in the number value of the element, thus animating the change. For instance, a number going from 0 to 100 can be used as the opacity value of an element, and used to animate a change in appearance from transparent to opaque.

Luckily, the ASP.NET AJAX Futures CTP comes with several built-in animations. They are all defined in a library called PreviewGlitz.js (which is embedded in the Futures CTP assembly).

Since the animations reside in an external library, the PreviewGlitz.js file must be included manually in any page that uses them. This file also depends on the PreviewScript.js file, the "core" JavaScript library for the CTP.

Author's Notes: For simplicity, all the samples in this installment still use the same project, GlitzTest, with the nearly same configuration for the server control, ScriptManager, in each related web page.

For a clearer overview of the relationships between the animations to be discussed here, let me give a simple sketch in Figure 1.

Figure 1: The hierarchical relationships of the animations supported in Futures CTP

As is seen from Figure 1, Animation is the root of all MS AJAX client-side animations all of which are derived from it.  With the mainly programming mode in this installment being declarative, we only list the descriptor definition for the parent class Animation, PropertyAnimation, and InterpolatedAnimation.

Listing 1: The descriptor blocks for all parent animation classes

//the descriptor block for class Animation
Sys.Preview.UI.Effects.Animation.descriptor={
      properties:[
            {name:"duration",type:Number},
            {name:"fps",type:Number},
            {name:"isActive",type:Boolean,readOnly:true},
            {name:"isPlaying",type:Boolean,readOnly:true},
            {name:"percentComplete",type:Number,readOnly:true},
            {name:"target",type:Object}
      ],
      methods:[
            {name:"play"},
            {name:"pause"},
            {name:"stop"}
      ]
};
//the descriptor block for class <span class=Bold>PropertyAnimation</span>
Sys.Preview.UI.Effects.PropertyAnimation.descriptor={
      properties:[
      {name:"property",type:String},
      {name:"propertyKey"}
      ]
};
//the descriptor block for class <span class=Bold>InterpolatedAnimation</span>
Sys.Preview.UI.Effects.InterpolatedAnimation.descriptor={
      properties:[
      {name:"endValue",type:Object},
      {name:"startValue",type:Object}
      ]
};

Since all the properties and methods in Listing 1 are generally used to control an animation, we will not dwell on them but leave them to be explained in each concrete demo.  There is still one more word to be added that, generally, the three parent classes listed above will not be used alone to render some animating effects as with the common parent class definition in OOP languages.

Now, let us chew upon the derivate sub-animations one by one.

Using FadeAnimation—Example 1

By using FadeAnimation, we can achieve the effect that the opacity of some layer on the web page changes gradually from 1 to 0 or conversely, i.e. the fading in/out effect.

With the project GlitzTest (used in Part 1) still open, you just right-click the project and add a new web page named AjaxFadeAnimation.aspx.  With a little modification, we can get the final design-time snapshot as shown in the following Figure.

Figure 2: The design-time snapshot for fading in/out animation

Now, let us first look into the related HTML code.

Listing 2

<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server">
      <Scripts>
            <asp:ScriptReference Assembly="Microsoft.Web.Preview"
                Name="PreviewGlitz.js" />
            <asp:ScriptReference Assembly="Microsoft.Web.Preview" 
                Name="PreviewScript.js" />
      </Scripts>
</asp:ScriptManager>
      <br />
      <div class="h1">Fading in and out Animation Demo</div><br />
 
      <input id="btnFadeOutAnimate" type="button" value="Fade Out" 
          style="width: 155px; height: 37px" language="javascript" 
          onclick="return FadeUsingFutures(true)" />
      <input id="btnFadeInAnimate" style="width: 135px; height: 37px" 
          type="button" value="Fade In" language="javascript"
          onclick="returnFadeUsingFutures(false)" /><br />
      <div id="animationTarget" 
          style="width: 207px; height: 252px; background-color: #ffcc00">
      <img src="img/lushan_1.jpg" style="width: 208px; height: 258px;" />  
      </div>
</form>

Here, we first add the necessary assemblies and the related *.js files within </asp:ScriptManager> block.  In the debugging process, I find that without either *.js file you would achieve no animating results or run into a lot of error info.  So, this is a MUST-BE step.

Next, we defined two buttons with the ID being btnFadeOutAnimate and btnFadeInAnimate and attached their onclick event handlers respectively. Following these is a simple <img> label for testing the fading in/out effect.  Obviously, this is the crucial hide in the two event handlers.  So, let us hurry into the key JavaScript programming part (here we omit the declarative mode; interested readers can use it as an exercise).

Listing 3

<script language="javascript" type="text/javascript">
      Sys.Application.initialize();
      //Get a handle to the animation target 
      var domElementVar = new Sys.UI.Control( $get("animationTarget")  );
      //Create an instance of the FadeAnimation .
      var fadeAnimation = new Sys.Preview.UI.Effects.FadeAnimation();
      //Set the Duration 
      fadeAnimation.set_duration( 0.3 );
      //Set the Animation Target as a Sys.UI.Control object 
      fadeAnimation.set_target( domElementVar );
      //Set the Maximum Opacity Value
      fadeAnimation.setValue( 70 );
 
      //frames to play per second
      fadeAnimation.set_fps(45);
      function FadeUsingFutures( fadeOut )
      {
            //Decide whether to Fadein or FadeOut
            var fadeEffect = fadeOut ?  
                Sys.Preview.UI.Effects.FadeEffect.FadeOut :
                Sys.Preview.UI.Effects.FadeEffect.FadeIn ;
 
            //Hide / Show the appropriate button(s)
            $get("btnFadeOutAnimate").style.display =  fadeOut  ? "none":"block";
            $get("btnFadeInAnimate").style.display  =  fadeOut  ? "block":"none";
 
            //Set the Animation Effect ( FadeIn / FadeOut )
            fadeAnimation.set_effect( fadeEffect );
            //Play the Animation
            fadeAnimation.play(); 
      }
</script>

In the above code we have provided enough explanations. It seems that everything would become smooth if you better knew the basic animation-related API's.  So, let us save some words for the next discussing topic.

Using LengthAnimation—Example 2

Now comes another kinds of animation—LengthAnimation.  The LengthAnimation can be used to change some property of the target within the values ranging from some start value to a largest value with a typical usage of altering the length/width property of some control.

Note that you can also use this animation to change some property of text data despite merely specifying the start and end values.  The following table lists the common properties supported by this kind of animation.

Table 1: Common properties supported by LengthAnimation

Property

Description

target

Specify the target to apply this animation to.

property

Specify which property of the target to be influenced.

startValue

Specify the start value of the property to be influenced.

endValue

Specify the end value of the property to be influenced.

unit

Specify the changing unit of the animation.

duration

Specify the time duration of the animation with the unit being second.

fps

Gets/sets the fps property of the animation (25 by default).

isActive

Is a boolean value to indicate whether the animation has already started.

isPlaying

Is a boolean value to indicate whether the animation has been playing.

percentComplete

Returns a value ranging from 0 to 100 indicating current progress of the animation.

Now, let us look into a simple demo for this animation.

Right-click project GlitzTest and add another new web page named LengthAnimation.aspx.  With a little modification, the final design-time web page should look like Figure 3.

Figure 3: The design-time snapshot for length animation

The next Figure shows the snapshot in the middle course of the animation.

Figure 4: The run-time snapshot for the middle course length animation

As you can image, the final snapshot will show the largest picture of the girl.

Let us look into the how-to.  Listing 4 gives the HTML code for page LengthAnimation.aspx.

Listing 4

//…omitted
<img id="i" src="img\girl1.jpg" width="100" />
<hr />
<input type="button" id="startButton" value="Start"/>

Note we have created a picture using the <img> label with its initial value of width being 100 instead of using style attribute to specify this property—this is very important for later we will be changing the value of property width of our animation target.

Next, look into the really interesting xml-script programming in Listing 5.

Listing 5

<script type="text/xml-script">
      <page xmlns:script="http://schemas.microsoft.com/xml-script/2005">
      <components>
            <image id="i">
                  <behaviors>
                        <LayoutBehavior id="Label1Style" />
                  </behaviors>
            </image>
 
            <lengthAnimation id="lani"
            target="Label1Style" property="width"
            startValue="100" endValue="480" fps='25'
            duration="5" >
            </lengthAnimation>
 
            <button id="startButton">
                  <click>
                        <InvokeMethodAction target="lani" method="play" />
                  </click>
            </button>
      </components>
      </page>
</script>

Here, we first create an instance of Sys.Preview.UI.Image using <image> label with it pointing to the factual HTML <img> element with ID named "i."  Next, we define a LayoutBehavior with ID named "Label1Style" and then bind it to the image instance.  Note this LayoutBehavior behavior serves as the target of the later defined LengthAnimation.  By continuously changing the width of behavior Label1Style from 100px to 480px, the size of the image will be changed accordingly.  With the value of attribute duration set to smaller value, the changing speed of the image will be increased; otherwise decreased.  Lastly, if value of property startValue is larger than endValue, you will see the converse animating effect.

Author's Notes: If we do not introduce LayoutBehavior as the mediator, clicking the Start button will only result in the picture's sudden disappearance.  Does this seem a bit strange or is it a bug?  In the case of LengthAnimation, we currently have nothing to resort to but to test, test and test…

Using NumberAnimation—Example 3

The features of animation NumberAnimation is quite similar to those of LengthAnimation (with the same properties such as target, property, startValue, endValue, duration, fps, isActive, isPlaying, percentComplete, and so on) except for two differences.  The first difference lies in that the middle value for animation NumberAnimation to change can be decimal fraction through property integralValues.  Thus, in certain scenarios such as dealing with the length unit—meter, proper use of animation NumberAnimation will result in better animating effect.  The second difference lies in that LengthAnimation supports pixel-based change of the animation (through property unit) while NumberAnimation does not.

Take a look at a vivid example to simulate some count down.  Still right-click project GlitzTest and add another new web page named NumberAnimation2.aspx. (Note that in the sample project GlitzTest I have also provided another demo for NumberAnimation using a web page named NumberAnimation.aspx, which is aimed to simulate the fading in/out effect by changing property value of behavior OpacityBehavior.  For more info about it, see the downloadable source code.) The following Figure shows the design-time snapshot of page NumberAnimation2.aspx.

Figure 5: The design-time snapshot for number animation

At the very beginning, an integer 30 is displayed on the screen.  With property integralValues set to false and the continuing of the number animation, there appears decimal fraction on the page as shown in Figure 6.

Figure 6: The run-time snapshot for the number animation in the middle course

Here, on the page we place an <span> element to hold the content to be counted down and a button to trigger the animating process.  For brevity, we still only cover the xml-script part as shown in Listing 6.

Listing 6

//…omitted
<components>
      <label id="mynumber" />
      <numberAnimation id="mynumberAnimation"
      target="mynumber" property="text"
      startValue="30" endValue="0" integralValues="false" duration="30" />
      <button id="startButton">
            <click>
                  <InvokeMethodAction target="mynumberAnimation"
                      method="play" />
            </click>
      </button>
</components>

In the above script, we first associate a <span> element named mynumber with a MS AJAX client-side Label control.  Note control Label provides a property named text the value of which will be shown within the related <span> element.  Next, a node named numberAnimation (with case insensitive) is created with its property target pointing to the label mynumber, property property set to text so that the animating content will be shown inside control mynumber.  Then we set two relevant properties startValue and endValue to 30 and 0, respectively. With property integralValues set to false the web page shows some decimal fraction content; while when set to true, we can vividly simulate a counting down stopwatch.

In a word, by using animation NumberAnimation, we can easily and continuously change some values and associate this process with some page elements on the page.

Using DiscreteAnimation—Example 4

Now, let us discuss another kind of animation—DiscreteAnimation.  On the one hand, there are some similarities with animations LengthAnimation and NumberAnimation, such as within some specific time specifying the values within some range in turn, etc.  On the other hand, there are some dissimilarities between them—in the case of animations LengthAnimation and NumberAnimation, we only need to specify a start value and an end value and let the framework calculating all the middle values. While for DiscreteAnimation, we must enumerate all the values such as a…z, Sunday…Saturday, etc., and then it will play each of them during the animating course.  Here, for clarity and easy comparison, we also list the common properties supported by DiscreteAnimation in the following table.

Table 2: Common properties supported by DiscreteAnimation

Property

Description

target

Specify the target to apply this animation to.

property

Specify which property of the target to be influenced.

values

List all the values to be played in the animation.

duration

Specify the time duration of the animation with the unit being second.

fps

Gets/sets the fps property of the animation (25 by default).

isActive

Is a boolean value to indicate whether the animation has already started.

isPlaying

Is a boolean value to indicate whether the animation has been playing.

percentComplete

Returns a value ranging from 0 to 100 indicating current progress of the animation.

Nothing special here but the property values!

Examine a related example to achieve the discrete animating effect.  Still right-click project GlitzTest and add another new web page named discrete.aspx.  Figure 7 shows the design-time snapshot of page discrete.aspx.

Figure 7: The design-time snapshot for discrete animation

If you press F5 and launch this demo, you will see a discrete animating process—the text of the label is changing from "Sunday" until "Saturday" in discrete mode.  For brevity, we only list the xml-script part.

Listing 7

<script type="text/xml-script">
      <page xmlns:demo="demo">
      <components>
            <label id="sampleLabel" />
            <discreteAnimation id="wordAnimation"
            target="sampleLabel" property="text"
            values="'Sunday', 'Monday', 'Tuesday', 'Wednesday',
                'Thursday', 'Friday', 'Saturday'"
            duration="3" />
 
            <button id="startButton">
                  <click>
                        <invokeMethodAction target="wordAnimation" 
                            method="play" />
                  </click>
            </button>
      </components>
      </page>
</script>

In the above script, we first associate a <span> element named sampleLabel with a MS AJAX client-side Label control which will serve as the target element to play the animation.  Next, a node named discreteAnimation is created with its property target pointing to the label sampleLabel, property property pointing to property text of control sampleLabel.  The most important property should be values, whose form is a string composed of some optional elements separated by commas.  Yes, as you may have doped out, you can easily achieve the stopwatch animating effect as accomplished by animation NumberAnimation by specifying a bunch of numbers.  All the other parameters and controls are quite similar to those of above animations, so we do not chatter much any more.

Using CompositeAnimation—Example 5

From the literal definition, you can guess that this kind of animation is used as a wrapper or holder to create more complex composite animations.  First, look over the source code from file PreviewGlitz.js since it is pretty short.

Listing 8: The complete source code for CompositeAnimation

Sys.Preview.UI.Effects.CompositeAnimation=function(){
      Sys.Preview.UI.Effects.CompositeAnimation.initializeBase(this);
      this._animations=Sys.Component.createCollection(this)
};
Sys.Preview.UI.Effects.CompositeAnimation.prototype={
      get_animations:function(){
            return this._animations},
      getAnimatedValue:function(){
            throw Error.invalidOperation()},
      dispose:function(){
            this._animations.dispose();
            this._animations=null;
            Sys.Preview.UI.Effects.CompositeAnimation.callBaseMethod(this,"dispose")},
      onEnd:function(){
            for(var a=0;a<this._animations.length;a++)
            this._animations[a].onEnd()  },
      onStart:function(){
            for(var a=0;a<this._animations.length;a++)
            this._animations[a].onStart()},
      onStep:function(b){
            for(var a=0;a<this._animations.length;a++)
            this._animations[a].onStep(b)
      }
};
Sys.Preview.UI.Effects.CompositeAnimation.descriptor={
      properties:[{
      name:"animations",type:Array,readOnly:true}]
};
Sys.Preview.UI.Effects.CompositeAnimation.registerClass(
    "Sys.Preview.UI.Effects.CompositeAnimation",Sys.Preview.UI.Effects.Animation);

At the first blush, it performs no functions but to supply an empty framework to hold sub-animations.  However, the really significant and interesting thing just lies in the "framework"—a container to encapsulate any kind of sub-animations!  Thus, method get_animations becomes very important—we can use it to get the "handles" of sub-animations and further to control each sub-animation.  Actions speak louder than words; let us build a demo to appreciate the mighty functions CompositeAnimation holds.

As usual, right-click project GlitzTest and add another new web page named CompositeAnimation2.aspx. Figure 8 shows the final design-time snapshot of page CompositeAnimation2.aspx.

Figure 8: The design-time snapshot for composite animation

Again appears the beautiful girl!?  Yes, surely it is; but here we will make the picture explode until finally disappearing from the surface.  Look into the HTML code of page CompositeAnimation2.aspx, as shown in Listing 9.

Listing 9

<div class="h1">CompositeAnimation Demo</div><br />
<hr />
<div id='imageArea' class='demosample' style="width: 162px; height: 236px">
      <img id="i" src="img/girl1.jpg" onclick="Explode('i');"
          style="position: absolute; left: 16px; top: 131px; width: 157px;
            height: 234px; cursor: hand;" />
</div>
<hr />
<div id='labelArea' class='demosample1' style="width: 265px; height: 21px">
      <label id="Label1" >Click the girl to see what happens!</label>
</div>

Still nothing unusual, right?  We first create a <img> label and then a <label> element wrapped by the common <div> tag, nothing more.  But observant readers may already have figured out the answer to this riddle—the img's click handler  "Explode('i')."  OK, let us see the inner hidings as shown in Listing 10.

Listing 10

<script type="text/javascript">
//modify this number to change the scale factor
var _scaleFactor = 6;
var _image, _animation;
 
function Explode(id)
{
    //to prevent from concurrent animating
    if (_animation != null)
    return;
 
    _image = $get(id);
    var width = parseFloat(_image.style.width);
    var height = parseFloat(_image.style.height);
    var x = parseFloat(_image.style.left);
    var y = parseFloat(_image.style.top);
 
    // Use a CompositeAnimation object to "explode" the target
    // simultaneously with scaling, moving, and fading effect.
    var NumberAnimation1 = new Sys.Preview.UI.Effects.NumberAnimation();
    NumberAnimation1.set_target(_image);
    NumberAnimation1.set_property('style');
    NumberAnimation1.set_propertyKey('width');
    NumberAnimation1.set_startValue(width);
    NumberAnimation1.set_endValue(width * _scaleFactor);
 
    var NumberAnimation2 = new Sys.Preview.UI.Effects.NumberAnimation();
    NumberAnimation2.set_target(_image);
    NumberAnimation2.set_property('style');
    NumberAnimation2.set_propertyKey('height');
    NumberAnimation2.set_startValue(height);
    NumberAnimation2.set_endValue(height * _scaleFactor);
 
    var NumberAnimation3 = new Sys.Preview.UI.Effects.NumberAnimation();
    NumberAnimation3.set_target(_image);
    NumberAnimation3.set_property('style');
    NumberAnimation3.set_propertyKey('left');
    NumberAnimation3.set_startValue(x);
    NumberAnimation3.set_endValue(x - (width * (_scaleFactor - 1)) / 2);
 
    var NumberAnimation4 = new Sys.Preview.UI.Effects.NumberAnimation();
    NumberAnimation4.set_target(_image);
    NumberAnimation4.set_property('style');
    NumberAnimation4.set_propertyKey('top');
    NumberAnimation4.set_startValue(y);
    NumberAnimation4.set_endValue(y - (height * (_scaleFactor - 1)) / 2);
 
    var FadeAnimation1 = new Sys.Preview.UI.Effects.FadeAnimation();
    FadeAnimation1.set_target(new Sys.Preview.UI.Image(_image));
    FadeAnimation1.set_effect (Sys.Preview.UI.Effects.FadeEffect.FadeOut);
 
    _animation = new Sys.Preview.UI.Effects.CompositeAnimation();
    _animation.get_animations().add(NumberAnimation1);
    _animation.get_animations().add(NumberAnimation2);
    _animation.get_animations().add(NumberAnimation3);
    _animation.get_animations().add(NumberAnimation4);
    _animation.get_animations().add(FadeAnimation1);
    _animation.set_duration(0.3);
    _animation.set_fps(35);
    _animation.play();
 
    //
    var timer = new Sys.Preview.Timer();
    timer.initialize();
    timer.set_enabled(true);
    timer.set_interval(500);
    timer.add_tick(dispose);
}
 
function dispose(sender)
{
    if (!_animation.get_isPlaying())
    {
        sender.set_enabled(false);              // Disable the timer
        _image.parentNode.removeChild(_image);  // Remove the image
        _animation = null;
    }
}
</script>

Here, we first define three global variables as the literalness self explained: _scaleFactor to specify the zooming in coefficient, _image to point to the <img> element, and _animation to hold the instance of class Sys.Preview.UI.Effects.CompositeAnimation.  Next, when you click the girl, the click event handler is triggered and function Explode is called.  To prevent concurrent animating, we use an if-condition sentence to avoid multiple instances of class CompositeAnimation.  Then we obtain the required properties of the image.  And then we create four instances of NumberAnimation to achieve the scaling, moving, and fading effects simultaneously.  Next, a CompositeAnimation is created to piece together all the sub-animations defined just now and configure the usual properties needed to play the animation.  At last, we start the animating.  Note here we have defined and invoked an instance of class Sys.Preview.Timer to do some cleaning after the animating is over since the animation classes in PreviewScript.js do not fire end events (please refer to the source code of PreviewGlitz.js).  That is over.  Now you can press F5 to appreciate the exploding result, as shown in Figure 9.

Figure 9: The run-time snapshot for the exploding effect using CompositeAnimation

Pretty good!  And if MS AJAX provided the rotating animation for two-dimensional images, that would be perfect!  However, it did not—it relies on you the readers to realize this!

Author's Notes: Within the ASP.NET AJAX Control Toolkit, there is an Extender control (which is an important kind of approach to expand the Server controls with rich client-side capabilities)—AnimationExtender by which we can more easily add animating effects to Web pages.  However, there is one shortcoming: it depends on the server-side ASP.NET framework.  So, to develop web applications on ASP.NET 2.0 platform you can borrow the animating capacities of AnimationExtender, while to create browser-compatible web applications using MS AJAX framework you will have to resort to the low-level animation classes (covered here) provided in PreviewGlitz.js.


View Entire Article

User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-10-12 11:26:47 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search