Rotating Graphic with Parallel Timelines

Sometimes Expression Blend does not even help you and you have to get down to the “wire” and edit the XAML directly. I came across this point when designing a rotating graphic similar to one done in Flash that I found on one of my customer’s intranet portal. The graphic had to concentric ¾ circles rotating on opposite direction along with two arcs doing something similar but at a different speed. Although this graphic was very irritating on the eye, I wondered if I could manage to copy this annoying using Expression Blend. It turned out rather simpler than expected and I had no need to drop into code in VS2010 – something that always makes the design a little dirty J.

I needed very little in the end, just a circle and a rectangle. Firstly I used the ellipse functionality in Expression Design to draw a circle. I set the internal fill to be transparent and set the required colour on the stroke as well as setting the stroke width to 15 pixels. Using a rectangle with one of its corners set to the middle of the circle I proceeded to cut away one of the circle’s quadrants using the rectangle. The result I then copied using XAML to Expression Blend. Within Blend I copied the circle and reduced the size to fit within the original one. After setting the stoke colour I ended up with the following in Blend

Once complete I returned to Design and built an Arc using similar techniques as to get the ¾ circle, i.e. I defined a circle with Fill and Strike to the same colour and progressively cut away most of the circle until I was left with the arc I required. I copied the XAML to Blend and made a second copy of the arc and placed it opposing the first about the circles’ centre. I ended up with the following:

Now all I had to do was define the dynamic rotation of the graphic. Switching to the Animation Workspace within Blend and selecting the RotateStoryboard the following timeline is shown:

   

 

Within the 1.5 seconds assigned to the storyboard I defined that the arcs should rotate three times, i.e. 3 x 360˚, and the concentric ¾ circles at twice, i.e. 2 x 360˚. This then gave the desired rotating effect, however I needed to define that the storyboard was to proceed in parallel as well as endlessly repeating itself. The resultant XAML is as follows:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d"
    x:Class="RotatingSpinControl.MainWindow"
    x:Name="Window"
    Title="MainWindow"
    Width="640" Height="270">
    <Window.Resources>
        <Storyboard x:Key="RotateStoryboard" RepeatBehavior="Forever">
            <ParallelTimeline>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" 
                Storyboard.TargetName="OuterCircle">
                   <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="360"/>
                </DoubleAnimationUsingKeyFrames>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" 
                Storyboard.TargetName="InnerCircle">
                <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="-360"/>
              </DoubleAnimationUsingKeyFrames>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" 
                Storyboard.TargetName="FirstArc">
                   <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="765"/>
              </DoubleAnimationUsingKeyFrames>
              <DoubleAnimationUsingKeyFrames 
                Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" 
                Storyboard.TargetName="SecondArc">
                <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="-855"/>
              </DoubleAnimationUsingKeyFrames>
            </ParallelTimeline> 
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="ButtonBase.Click" SourceName="btnStart">
            <BeginStoryboard x:Name="RotateStoryboard_BeginStoryboard" Storyboard="{StaticResource RotateStoryboard}"/>
        </EventTrigger>
    </Window.Triggers>

    <Grid x:Name="LayoutRoot" Margin="0,0,112,0">
        <Button x:Name="btnStart" Content="Start Animation" HorizontalAlignment="Left" Height="48.949" Margin="48,39.051,0,0" 
            VerticalAlignment="Top" Width="110"/>
        <Canvas x:Name="RotatingGraphic" Margin="240,39.051,112,71.595">
            <Path x:Name="OuterCircle" Stretch="Fill" StrokeThickness="15" StrokeLineJoin="Round" Stroke="#FF0096FF" 
                Data="M 650,440C 650,467.614 627.614,490 600,490C 572.386,490 550,467.614 550,440C 550,412.386 572.386,390 600,390" 
                Height="115" VerticalAlignment="Top" RenderTransformOrigin="0.5,0.5" Canvas.Left="16" Width="115">
                <Path.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Path.RenderTransform>
            </Path>
            <Path x:Name="InnerCircle" Stretch="Fill" StrokeThickness="12" StrokeLineJoin="Round" Stroke="#FF0096FF" 
                Data="M 650,440C 650,467.614 627.614,490 600,490C 572.386,490 550,467.614 550,440C 550,412.386 572.386,390 600,390" 
                RenderTransformOrigin="0.5,0.5" Height="55" VerticalAlignment="Top" d:LayoutOverrides="Height" 
                Canvas.Left="46" Canvas.Top="29.949" Width="55">
                <Path.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform ScaleY="1" ScaleX="-1"/>
                        <SkewTransform AngleY="0" AngleX="0"/>
                        <RotateTransform Angle="0"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Path.RenderTransform>
            </Path>
            <Path x:Name="FirstArc" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FFFF4600" Fill="#FFFF4600" 
                Data="F1 M 210,100L 410,100L 410,100.371L 217.001,152.646C 212.436,135.872 210,118.22 210,100 Z " 
                Height="17.646" VerticalAlignment="Top" Width="72" RenderTransformOrigin="1,0" Canvas.Top="56.949">
                <Path.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform Angle="45"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Path.RenderTransform>
            </Path>
            <Path x:Name="SecondArc" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FFFF4600" Fill="#FFFF4600" 
                Data="F1 M 210,100L 410,100L 410,100.371L 217.001,152.646C 212.436,135.872 210,118.22 210,100 Z " 
                Height="17.646" VerticalAlignment="Top" Width="72" RenderTransformOrigin="1,0" Canvas.Top="56.949">
                <Path.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform Angle="225"/>
                        <TranslateTransform/>
                    </TransformGroup>
                </Path.RenderTransform>
            </Path>
        </Canvas>
    </Grid>
</Window>

That’s all Folks…

Advertisements

~ by Intelligence4 on April 7, 2011.

 
%d bloggers like this: