LA.NET [EN]

Jul 18

Another experience I”ve run today was related with compensating direction changes on animations. Here”s the scenario: suppose you”ve got a rectangle and you want it to move from x to y when something happens and then from y to x when another thing happens. 

The main problem is that the change in direction might happen before the previous running animations ends. If you want to have a cool effect, you”ll have to adjust the duration of the animation so that it looks like its moving smoothly and at the same velocity. Let”s start with the XAML:

<Canvas
  xmlns=”http://schemas.microsoft.com/client/2007″
  xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
  x:Name=”parentCanvas”
  Loaded=”Page_Loaded”
  x:Class=”SilverlightProject2.Page11;assembly=ClientBin/SilverlightProject2.dll”
  Width=”640″
  Height=”480″
  Background=”White”>
  <Canvas.Resources>
    <Storyboard x:Name=”moveright”>
       <DoubleAnimation To=”544″ Duration=”0:0:3″ x:Name=”moverightanim”
           Storyboard.TargetName=”rectangle”
           Storyboard.TargetProperty=”(Canvas.Left)” />
   </Storyboard>
   <Storyboard x:Name=”moveleft”>
       <DoubleAnimation To=”16″ Duration=”0:0:3″ x:Name=”moveleftanim”
           Storyboard.TargetName=”rectangle”
           Storyboard.TargetProperty=”(Canvas.Left)” />
   </Storyboard>
  </Canvas.Resources>
  <Rectangle Fill=”#FFE81E1E”
        Stroke=”#FF000000″ x:Name=”rectangle” Width=”56″ Height=”48″
        Canvas.Left=”16″ Canvas.Top=”64″ />
  <TextBlock Canvas.Left=”10″ Canvas.Top=”200″ Text=”Left”    MouseLeftButtonDown=”StartLeft” />
   <TextBlock Canvas.Left=”100″ Canvas.Top=”200″ Text=”Right” MouseLeftButtonDown=”StartRight” />
</Canvas>

As you can see, nothing too fancy is going on here. I”ve just added two storyboards which use a double animation to change the value of the Canvas.Left property of the rectangle. Notice that I”ve only set the To property of each animation. By doing this i know that when an animation begins, it”ll start from the current X coordinate (and this might not be the leftmost or rightmost X coordinate).

The TextBlocks are there just to control direction changes. When you click on the Right textblock, the square starts moving to the right side; clicking on the left one makes it move in the other direction. My first attempt to make direction changes looked something like this:

void StartRight(object sender, EventArgs e)
{
    moveright.Begin();
}

void StartLeft(object sender, EventArgs e)
{
    moveleft.Begin();
}

If you try to do that, you”ll see that the square changes its moving direction like we want. The problem is that it”ll always take 3 seconds to run. This means that if you click right and then left, you”ll see that it takes 3 seconds to move from its small offset till it reaches the starting position. It”s not what we”re looking for! What we need is to dynamically change the duration of the animation so that it”s adjusted to the space that the square needs to cover (in one direction or another).

To achieve this purpose, I”ve started by adding some constants and read only fields:

const double maxPosX = 544;
const double minPosX = 16;
static readonly TimeSpan duration = new TimeSpan(0,0,3);

Then I”ve build an auxiliary method that calculates the percentage of the distance that the square will cover:

double GetCurrentPercentage(Direction dir)
{
   double currentX = (double)rectangle.GetValue(Canvas.LeftProperty);
   double currentDistance = dir == Direction.ToLeft ? currentX – minPosX : maxPosX – currentX;
   double currentPercentage = currentDistance / (maxPosX – minPosX);
   return currentPercentage;
}

As you can see,we need to know the direction that is being followed. Direction is a simple enumeration that looks like this:

enum Direction
{
  ToLeft,
  ToRight
}

Now we just need to apply it to the maximum duration of the animation when the user clicks left or right:

void StartLeft(object sender, EventArgs e)
{
  long adjustedTicks = Convert.ToInt64(duration.Ticks * GetCurrentPercentage(Direction.ToLeft) );
  moveleftanim.Duration = new TimeSpan(adjustedTicks);
  moveleft.Begin();
}

Moving to the right is similar, so I”ll leave it to you :).

2 comments so far

  1. David Lawton
    11:20 am - 7-18-2007

    You are a life saver! This is exaclty what i was looking for here:

    http://silverlight.net/forums/t/2832.aspx

    I have been faffing about with custom event handlers trying to do exactly this!

    Your a champion!

    David Lawton
    Hyperion Technologies Ltd (UK)
    Electric Hornet Design Studios

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>