none
Animation for drawing lines in WPF

    Question

  • Hello,

     

    I have a PathGeometry that consists of a single PathFigure that is made of several ArcSergments and LineSegments.

    I'd like to create animation that will display how this PathGeometry is drawn by an invisible pencil.

    I mean that this PathGeometry should not be displayed in the window at once. It should appear gradually pixel-by-pixel or segment-by-segment from its beginning point to the end point instead.

     

    I can explain the problem in other words. It is possible to animate the movement of the point along some Path. I need this point to leave the trace as it moves from the start point of the Path to its finish point.

     

    Is it possible to create an animation for this scenario?

    If not - what workaround could you suggest?

     

    Thank you

    Wednesday, January 16, 2008 9:27 AM

Answers

  • You can animate the StrokeDashOffset to get this effect somewhat. Here's an example i found:

     

     

    Code Block

    <Page
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           x:Name="Window"
           Title="Window1"
           Width="640" Height="480" xmlns:System="clr-namespace:System;assembly=mscorlib">

           <Page.Resources>
                  <Storyboard x:Key="Timeline1">
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="15"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path1" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:01.2000000" Value="15"/>
                                <SplineDoubleKeyFrame KeyTime="00:00:02" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path2" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="30"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:03" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path3" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:03.1000000" Value="25"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:04" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path4" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:04.1000000" Value="20"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:05" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path5" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:05.1000000" Value="10"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:06" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                  </Storyboard>
           </Page.Resources>
           <Page.Triggers>
                  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                         <BeginStoryboard Storyboard="{StaticResource Timeline1}"/>
                  </EventTrigger>
           </Page.Triggers>

           <Grid x:Name="LayoutRoot">
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="33.5,80.449,0,0" x:Name="path" VerticalAlignment="Top" Width="155" Height="35.051" Data="M34,115 C45,106 91,119 105,112 119,105 172,75.004352 188,82.003591">
                         <Path.StrokeDashArray>
                               <System:Double>15</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="94,110,0,184" x:Name="path1" Width="21.11" Data="M99,115 C109,140 112,211 109,255">
                         <Path.StrokeDashArray>
                               <System:Double>15</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="142.642,154.283,0,186.176" x:Name="path2" Width="76.358" Data="M158,202 C158,202 207,204 211,187 215,170 186,150.00109 169,164.00068 152,178.00027 129.99983,261.99837 171.00008,251.99857 212.00033,241.99877 214.00037,221.99946 214.00037,221.99946">
                         <Path.StrokeDashArray>
                               <System:Double>30</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="228,145.336,0,188.972" x:Name="path3" Width="71" Data="M294,171 C289,162 283,147 268,151 253,155 244,164.99992 244,177.00008 244,189.00024 284,196.00033 287,207.00047 290,218.00062 286,249.00103 259,250.00104 232,251.00105 235,225.00071 233,219.00063">
                         <Path.StrokeDashArray>
                               <System:Double>25</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Right" Margin="0,115,242.243,193.054" x:Name="path4" Width="58.064" Data="M339,120 C337,137 312,263 348,244 384,225 376.0005,210.99973 376.0005,210.99973">
                         <Path.StrokeDashArray>
                               <System:Double>20</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" Margin="301,133,235,0" x:Name="path5" VerticalAlignment="Top" Height="24.187" Data="M306,151 C306,151 351,158 384,138">
                         <Path.StrokeDashArray>
                               <System:Double>10</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
           </Grid>
    </Page>

     

     

    Wednesday, January 16, 2008 6:15 PM

All replies

  • You can animate the StrokeDashOffset to get this effect somewhat. Here's an example i found:

     

     

    Code Block

    <Page
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           x:Name="Window"
           Title="Window1"
           Width="640" Height="480" xmlns:System="clr-namespace:System;assembly=mscorlib">

           <Page.Resources>
                  <Storyboard x:Key="Timeline1">
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:00.1000000" Value="15"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path1" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:01.2000000" Value="15"/>
                                <SplineDoubleKeyFrame KeyTime="00:00:02" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path2" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:02.1000000" Value="30"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:03" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path3" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:03.1000000" Value="25"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:04" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path4" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:04.1000000" Value="20"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:05" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                         <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="path5" Storyboard.TargetProperty="(Shape.StrokeDashOffset)">
                               <SplineDoubleKeyFrame KeyTime="00:00:05.1000000" Value="10"/>
                               <SplineDoubleKeyFrame KeyTime="00:00:06" Value="0"/>
                         </DoubleAnimationUsingKeyFrames>
                  </Storyboard>
           </Page.Resources>
           <Page.Triggers>
                  <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                         <BeginStoryboard Storyboard="{StaticResource Timeline1}"/>
                  </EventTrigger>
           </Page.Triggers>

           <Grid x:Name="LayoutRoot">
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="33.5,80.449,0,0" x:Name="path" VerticalAlignment="Top" Width="155" Height="35.051" Data="M34,115 C45,106 91,119 105,112 119,105 172,75.004352 188,82.003591">
                         <Path.StrokeDashArray>
                               <System:Double>15</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="94,110,0,184" x:Name="path1" Width="21.11" Data="M99,115 C109,140 112,211 109,255">
                         <Path.StrokeDashArray>
                               <System:Double>15</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="142.642,154.283,0,186.176" x:Name="path2" Width="76.358" Data="M158,202 C158,202 207,204 211,187 215,170 186,150.00109 169,164.00068 152,178.00027 129.99983,261.99837 171.00008,251.99857 212.00033,241.99877 214.00037,221.99946 214.00037,221.99946">
                         <Path.StrokeDashArray>
                               <System:Double>30</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Left" Margin="228,145.336,0,188.972" x:Name="path3" Width="71" Data="M294,171 C289,162 283,147 268,151 253,155 244,164.99992 244,177.00008 244,189.00024 284,196.00033 287,207.00047 290,218.00062 286,249.00103 259,250.00104 232,251.00105 235,225.00071 233,219.00063">
                         <Path.StrokeDashArray>
                               <System:Double>25</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" HorizontalAlignment="Right" Margin="0,115,242.243,193.054" x:Name="path4" Width="58.064" Data="M339,120 C337,137 312,263 348,244 384,225 376.0005,210.99973 376.0005,210.99973">
                         <Path.StrokeDashArray>
                               <System:Double>20</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
                  <Path Stretch="Fill" Stroke="#FF000000" StrokeDashOffset="1000" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="10" Margin="301,133,235,0" x:Name="path5" VerticalAlignment="Top" Height="24.187" Data="M306,151 C306,151 351,158 384,138">
                         <Path.StrokeDashArray>
                               <System:Double>10</System:Double>
                               <System:Double>1000</System:Double>
                         </Path.StrokeDashArray>
                  </Path>
           </Grid>
    </Page>

     

     

    Wednesday, January 16, 2008 6:15 PM
  • I did something with growing animated lines in a blog entry way back:

     

    http://www.charlespetzold.com/blog/2006/08/150351.html

     

    and with arcs in a blog entry just now:

     

    http://www.charlespetzold.com/blog/2008/01/Progressive-Arcs-in-XAML.html

     

     

    Wednesday, January 16, 2008 10:13 PM
  • Thank you Steve and Charles

     

    The first approach suits my needs better so I chose it and it's working perfectly. 

    Monday, January 21, 2008 8:22 AM
  • I definitely see some strange artifacts on the leading edge of the curve in the Progressive-Arcs-in-XAML sample.

    They appear and disappear as the line goes forward.

    Does someone have the same problem?
    Monday, January 21, 2008 10:06 AM
  • It is not just you - I see it too. We will be tracking it from our end.

     

     

    Monday, January 21, 2008 7:37 PM
  • I saw the artifiacts as well, but I'm using such a crappy machine at the moment that I was hoping they wouldn't show up on anyone else's box!

     

    In a real application, I think I'd supplement the whole thing with code that progressively adds the arcs to the complete figure besides just animating them.

     

     

    Monday, January 21, 2008 9:14 PM