Okay, so I'm working on a loading screen and I want to flare it up a bit.
Basically what I am trying to do is animate an object along path geometry data...I emphasize 'along' because keeping a fixed object along the path on a tangent is not what I would like to do
This is the best representation of what I am trying to do:
I can use a matrix transform to send this border element along the path but it winds up coming out as a tangential animation that moves and rotates with the path, but does not bend to fit the shape of the path...Here is an example of that:
<Border Background="Black" BorderBrush="Transparent" Width="20" Height="20">
<Border.RenderTransform>
<MatrixTransform x:Name="MatrixT">
<MatrixTransform.Matrix>
<Matrix/>
</MatrixTransform.Matrix>
</MatrixTransform>
</Border.RenderTransform>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<BeginStoryboard>
<Storyboard>
<MatrixAnimationUsingPath Storyboard.TargetName="MatrixT" Storyboard.TargetProperty="Matrix" DoesRotateWithTangent="True" Duration="0:0:5" RepeatBehavior="Forever">
<MatrixAnimationUsingPath.PathGeometry>
<PathGeometry Figures="M201.1,50.501C201.1,78.138,178.737,100.501,151.1,100.501L150.799,100.501C123.162,100.501,114.933,77.834,100.8,50.501L100.8,50.5C86.666,23.167,78.437,0.5,50.8,0.5L50.5,0.5C22.863,0.5,0.500000000000014,22.863,0.500000000000014,50.5L0.500000000000014,50.501C0.500000000000014,78.138,22.863,100.501,50.5,100.501L50.8,100.501C78.437,100.501,86.666,77.834,100.8,50.501L100.8,50.5C114.933,23.167,123.162,0.5,150.799,0.5L151.1,0.5C178.736,0.5,201.1,22.863,201.1,50.501L201.1,50.501z" PresentationOptions:Freeze="True"/>
</MatrixAnimationUsingPath.PathGeometry>
</MatrixAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
I have come up with an alternative solution that looks really sharp, but I wanted to pitch this question out to the community to see if they have any ideas on how to accomplish this task (or if it is even possible)...I have done some extensive googling on the matter and have come up with nothing on how to accomplish this in an effective means.
The requirements:
If the shape can be tapered and faded out on the trailing side that would be an even bigger plus (see the image above), but that might be more than is possible
EDIT: To clarify what I mean by 'bend'...I mean figure B below...figure A is the standard that I have traditionally seen:
Morphing your shape to a path would be very difficult in WPF. However there is a close approximation possible by animating two separate paths, and also animating two clipping regions at the same time.
Given below is XAML for an approximation of what you want. If you look carefully at the crossing point of the infinity symbol, you will notice a slight discontinuity in the smoothness of the shading during transition. This is because I was a little bit arbitrary in my setting of the Start, End, and Offset points for the LinearGradientBrush
objects. A little work on those will smooth out that transition. You could even choose to animate the properties on the brushes to help with that.
<Window x:Class="AnimationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Background="#FF486CBF">
<Viewbox>
<Grid>
<Canvas Width="50" Height="50"
HorizontalAlignment="Left"
VerticalAlignment="Top">
<Canvas.Clip>
<RectangleGeometry Rect="0,0,50,55">
<RectangleGeometry.Transform>
<TranslateTransform x:Name="_clip1"/>
</RectangleGeometry.Transform>
</RectangleGeometry>
</Canvas.Clip>
<Path StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeThickness="10"
RenderTransformOrigin="0.5,0.8571"
Data="M 5,25 c 0,-25 40,-25 40,0">
<Path.Stroke>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="0.7"/>
</LinearGradientBrush>
</Path.Stroke>
<Path.RenderTransform>
<RotateTransform x:Name="_rot1" />
</Path.RenderTransform>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="360" To="0"
Duration="0:0:3"
RepeatBehavior="Forever"
Storyboard.TargetName="_rot1"
Storyboard.TargetProperty="Angle"/>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="_clip1"
Storyboard.TargetProperty="Y"
RepeatBehavior="Forever">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="0"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.5" Value="25"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:2.8" Value="55"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:4.5" Value="-30"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:5.8" Value="0"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:6" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</Canvas>
<Canvas Width="50" Height="50"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="40,0,0,0">
<Canvas.Clip>
<RectangleGeometry Rect="0,0,50,55">
<RectangleGeometry.Transform>
<TranslateTransform x:Name="_clip2"/>
</RectangleGeometry.Transform>
</RectangleGeometry>
</Canvas.Clip>
<Path StrokeStartLineCap="Round"
StrokeEndLineCap="Round"
StrokeThickness="10"
RenderTransformOrigin="0.5,0.8571"
Data="M 5,25 c 0,-25 40,-25 40,0">
<Path.Stroke>
<LinearGradientBrush StartPoint="1,0" EndPoint="0,0">
<GradientStop Color="#FFFFFFFF" Offset="0"/>
<GradientStop Color="#00FFFFFF" Offset="0.7"/>
</LinearGradientBrush>
</Path.Stroke>
<Path.RenderTransform>
<RotateTransform x:Name="_rot2" />
</Path.RenderTransform>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation From="0" To="360"
Duration="0:0:3"
RepeatBehavior="Forever"
Storyboard.TargetName="_rot2"
Storyboard.TargetProperty="Angle"/>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="_clip2"
Storyboard.TargetProperty="Y"
RepeatBehavior="Forever">
<DiscreteDoubleKeyFrame KeyTime="0:0:0" Value="55"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:1.5" Value="-30"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:2.8" Value="0"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:4.5" Value="25"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:5.8" Value="55"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:6" Value="55"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</Canvas>
</Grid>
</Viewbox>
</Window>
An important point to note is that the clipping regions need to be applied to the Canvas
objects. If they are applied to the Path
objects, like you would normally do for an image, the clipping region then gets rotated along with the Path
by the RenderTrasform
. Not the desired effect.
You could just put a lot of circles on the path and animate their diameters.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With