Binding a line to the edge of an ellipse - wpf

On a canvas I have an ellipse rotated by a RotateTransform through animation. I wish to add a line with one end attached to a point on the ellipse. Can I somehow bind to a point on the ellipse?

You can animate both the Ellipse and the line together, like so:
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Canvas.Resources>
<PathGeometry x:Key="lineEndPath">
<PathFigure StartPoint="25,50">
<ArcSegment IsLargeArc="True" Point="100,50" Size="25,25" SweepDirection="Clockwise"/>
<ArcSegment IsLargeArc="True" Point="25,50" Size="25,25" SweepDirection="Clockwise"/>
</PathFigure>
</PathGeometry>
</Canvas.Resources>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Duration="0:0:5" From="0" RepeatBehavior="Forever" Storyboard.TargetName="rotTF" Storyboard.TargetProperty="Angle" To="360"/>
<PointAnimationUsingPath Duration="0:0:5" PathGeometry="{StaticResource lineEndPath}" RepeatBehavior="Forever" Storyboard.TargetName="lineEndPoint" Storyboard.TargetProperty="Point"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<Ellipse Width="75" Height="50" Canvas.Left="25" Canvas.Top="25" Stroke="Black">
<Ellipse.RenderTransform>
<RotateTransform x:Name="rotTF" CenterX="37.5" CenterY="25"/>
</Ellipse.RenderTransform>
</Ellipse>
<Path Stroke="Black" StrokeThickness="1.0">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0,0">
<LineSegment x:Name="lineEndPoint"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Data="{StaticResource lineEndPath}" Stroke="Black" StrokeDashArray="2,0,0" StrokeThickness="1.0"/>
</Canvas>
We animate one end of a LineSegment with a PointAnimationUsingPath, and set the path to a circle (shown by the dotted line).

I'm not sure what the problem is. You can add another element into your Canvas that lines up correctly and apply the transform to the canvas which will rotate both elements?
If you're asking if there's any way to say "line up with this" on the line then no, you can't do that as far as I now. For complicated layouts like this you can either trial and error with KaXaml/Bland, or use Illustrator to lay it out and then export to XAML.

Assuming I understand correctly, you're going to have to figure out the math to change your line's end point. Sorry, don't know the formula offhand, but you'll basically find your point on the ellipse, then figure out it's position given the angle of the rotation, and then change your line's end point using that information.

In order to connect two elements at their edges by a Line, I use a bounding box method as explained in Connecting two WPF canvas elements by a line, without using anchors?.

Related

How to make a Path spin in place?

Microsoft gives a nice example of a button spinning in place when clicked. I want to achieve the same effect with a path but following the same approach does not have the same result.
For instance this path bellow,
<Path x:Name="path"
Stretch="None"
Stroke="Black"
Fill="Blue"
RenderTransformOrigin="0.5,0.5"
Margin="100">
<Path.Data>
<PathGeometry Figures="M10,0 A10,10 0 0 1 7,7 L71,71 A100,100 0 0 0 100,0Z" />
</Path.Data>
<Path.RenderTransform>
<RotateTransform x:Name="MyPathTransform"
Angle="0" />
</Path.RenderTransform>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MyPathTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0.0"
To="360"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
Invoking a click to that path does not make the latter spin in place, like the button does. Why does this happen and how may I fix it?
From your follow up comment, I understand the issue is that it does animate, but it does not spin in place like the button did in the tutorial you followed.
The rotation is very dependent on whatever your RenderTransformOrigin is set to, and this value is a percentage of the animating control's width and height. In your case, your Pathboundaries are actually somewhat large. The Path is filling the container except for the 100 Marign. Your animation origin is set to 0.5, 0.5 (the center). So it's in effect rotating around the center on the window. You can play around with that origin until you get in the center of your geometry, but an easier way to get and what you want would be to put your path in a Canvas. That way the Canvas will take up all the space and your Path will only be as large as your geometry. Then using a 0.5, 0.5 origin will do what you want.
<Canvas Margin="100">
<Path x:Name="path"
Stretch="None"
Stroke="Black"
Fill="Blue"
RenderTransformOrigin="0.5,0.5">
<Path.Data>
<PathGeometry Figures="M10,0 A10,10 0 0 1 7,7 L71,71 A100,100 0 0 0 100,0Z" />
</Path.Data>
<Path.RenderTransform>
<RotateTransform x:Name="MyPathTransform"
Angle="0" />
</Path.RenderTransform>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="MyPathTransform"
Storyboard.TargetProperty="(RotateTransform.Angle)"
From="0.0"
To="360"
Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</Canvas>
Animate the Transform property of the Geometry. Thus you have more precise control over the pivot point of the rotation.
<Path x:Name="path" Stretch="None" Stroke="Black" Margin="100">
<Path.Data>
<PathGeometry Figures="M10,0 A10,10 0 0 1 7,7 L71,71 A100,100 0 0 0 100,0Z">
<PathGeometry.Transform>
<RotateTransform x:Name="rotateTransform"/>
</PathGeometry.Transform>
</PathGeometry>
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="rotateTransform"
Storyboard.TargetProperty="Angle"
To="360" FillBehavior="Stop" Duration="0:0:1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>

Animate an Object Along a Path

I strted to play around with shapes in wpf, I need the following: I have an image and I draw some shape, I want the the image would walk on the lines of this shape.
I mean like:
For example with the shape:
<Path Stroke="Black" StrokeThickness="5" Fill="Goldenrod">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="100,50" IsClosed="True">
<LineSegment Point="140,60"/>
<LineSegment Point="150,100"/>
<LineSegment Point="125,120"/>
<LineSegment Point="90,110"/>
<LineSegment Point="80,80"/>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
And here is the moving image:
<UserControl ...
xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options" ..>
<UserControl.Resources>
<PathGeometry x:Key="AnimationPath"
Figures="M 10,100 C 40,0 300,0 300,300 0,300 285,200 300,300 "
PresentationOptions:Freeze="True" />
</UserControl.Resources>
<Image
Source="/Resources/Myimage.png"
Width="200" >
<Image.RenderTransform>
<TranslateTransform x:Name="AnimatedTranslateTransform" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<!-- Animates the rectangle horizotally along the path. -->
<DoubleAnimationUsingPath
Storyboard.TargetName="AnimatedTranslateTransform"
Storyboard.TargetProperty="X"
PathGeometry="{StaticResource AnimationPath}"
Source="X"
Duration="0:0:5"
AutoReverse="True"
/>
<!-- Animates the rectangle vertically along the path. -->
<DoubleAnimationUsingPath
Storyboard.TargetName="AnimatedTranslateTransform"
Storyboard.TargetProperty="Y"
PathGeometry="{StaticResource AnimationPath}"
Source="Y"
Duration="0:0:5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
Related links: link1, link2
I have tried like:
Figures="M 10,100 C 100,50 140,60 150,100 125,120 90,110 80,80 "
i.e start at point 100,50 --> 140,60 and so on...
but it doesnt go exactly on this path
Your sketch seems to indicate that you want to animate kind of a red arrow along the path, including a rotation to the tangent angle of the current path segment.
You could achieve this by animating the Matrix property of a MatrixTransform with a MatrixAnimationUsingPath. The example below uses an additional TranslateTransform to center the image. As there is a DrawingImage in the Source property of the Image element, you may as well use another Path instead of an Image.
<Window.Resources>
<PathGeometry x:Key="AnimationPath"
Figures="M100,50 L140,60 150,100 125,120 90,110 80,80Z"/>
</Window.Resources>
<Canvas>
<Path Stroke="Black" StrokeThickness="5" Fill="Goldenrod"
Data="{StaticResource AnimationPath}"/>
<Image>
<Image.Source>
<DrawingImage>
<DrawingImage.Drawing>
<GeometryDrawing Geometry="M0,0 L10,8 0,16">
<GeometryDrawing.Pen>
<Pen Thickness="3" Brush="Red"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
</DrawingImage.Drawing>
</DrawingImage>
</Image.Source>
<Image.RenderTransform>
<TransformGroup>
<TranslateTransform X="-5" Y="-8"/>
<MatrixTransform x:Name="AnimatedTransform"/>
</TransformGroup>
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Loaded">
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<MatrixAnimationUsingPath
Storyboard.TargetName="AnimatedTransform"
Storyboard.TargetProperty="Matrix"
Duration="0:0:5"
DoesRotateWithTangent="True"
PathGeometry="{StaticResource AnimationPath}"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
</Canvas>

WPF XAML Move/reposition a point in a Path using Storyboard

So I have a project where I am making a list of items that can be expanded to reveal additional information. So far I have come up with a way to rotate the angles 180 degrees to indicate if the information panel is open or closed, but I feel it looks a little bit artificial.
Gif demonstration here. Ideally, I would like my angle (<) to morph into pointing the opposite way. So let's say the coordinates are -5,0 0,5 and 5,0 (Red) I would like to animate them going to -5,5 0,0 and 5,5 (Blue).
I have been googling about this for a while, using keywords like animation / path / morph / storyboard. My theory now is that there could be a way where you could name each point in the Path data individually and add styles to them where they will move positions based on a common data trigger. Currently, it's all connected like shown below, and it's all linked up to a style that is attached to the Path. I would prefer to do all of this in XAML, so any help is appreciated.
<DataTrigger Binding="{Binding RevealAdditionalInformation}" Value="False">
<DataTrigger.EnterActions>
<StopStoryboard BeginStoryboardName="ArrowPointUp"/>
<BeginStoryboard Name="ArrowPointDown">
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="(LayoutTransform).(RotateTransform.Angle)" From="180" To="0" Duration="0:0:0.6"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
Update:
I've been trying to find a new way to draw up my Path rather than just
<Path Data="m 0 0 5 5 5 -5">. So now I have the same shape written in a different way. Perhaps this would be easier to manipulate each point separately. What's problematic here is that I am not allowed to name any of these points with Name="Something", so they will be hard to access.
<Path Stroke="Black" StrokeThickness="1" Grid.Column="1">
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigureCollection>
<PathFigure IsClosed="False" StartPoint="0,0">
<PathFigure.Segments>
<PathSegmentCollection>
<LineSegment Point="5,5" />
<LineSegment Point="10,0" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
</PathFigureCollection>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
Update 2:
<DataTrigger Binding="{Binding RevealAdditionalInformation}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard Name="AnimateTrue">
<Storyboard>
<PointAnimationUsingPath Duration="0:0:0.5" Storyboard.TargetProperty="Figures">
<PointAnimationUsingPath.PathGeometry>
<PathGeometry Figures="m -5 0 0 5 5 0"/>
</PointAnimationUsingPath.PathGeometry>
</PointAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
This is another take I've been experimenting with, the problem here seems to be The Storyboard.Target property, not perhaps a different sort of Animation is needed. The path I am experimenting with this on is this, where FiguresTest is the Style that uses the above Data Trigger.
<Path x:Name="_testPath" Stroke="Black" StrokeThickness="1" Style="{StaticResource FiguresTest}">
<Path.Data>
<PathGeometry Figures="m -5 5 0 0 5 5"/>
</Path.Data>
</Path>
You can animate individual points on the Path. In order to do that, you need to define your Path in a manner in which each point you want to animate is a property of a named element. This of course results in more verbose definition, but gets you what you're after. For example:
<Path Stroke="Black" StrokeThickness="1">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="Figure" StartPoint="-5,5">
<LineSegment x:Name="Line1" Point="0,0" />
<LineSegment x:Name="Line2" Point="5,5" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Then the animation could look like this:
<BeginStoryboard Name="AnimateTrue">
<Storyboard>
<PointAnimation To="-5,0" Duration="0:0:0.5"
Storyboard.TargetName="Figure"
Storyboard.TargetProperty="StartPoint" />
<PointAnimation To="0,5" Duration="0:0:0.5"
Storyboard.TargetName="Line1"
Storyboard.TargetProperty="Point" />
<PointAnimation To="5,0" Duration="0:0:0.5"
Storyboard.TargetName="Line2"
Storyboard.TargetProperty="Point" />
</Storyboard>
</BeginStoryboard>
EDIT
Since you're struggling with getting things working, below is an example in which the Path is part of ToggleButton template. It seems to be a good choice given it will be used to toggle expansion state.
<ToggleButton>
<ToggleButton.Template>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<ControlTemplate.Resources>
<Duration x:Key="AnimationDuration">0:0:0.2</Duration>
</ControlTemplate.Resources>
<Border Background="Transparent">
<Path Stroke="Black" StrokeThickness="1" Width="10" Height="5">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="Figure" StartPoint="0,0">
<LineSegment x:Name="Line1" Point="5,5" />
<LineSegment x:Name="Line2" Point="10,0" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="ToggleOn">
<Storyboard>
<PointAnimation To="0,5" Duration="{StaticResource AnimationDuration}"
Storyboard.TargetName="Figure"
Storyboard.TargetProperty="StartPoint" />
<PointAnimation To="5,0" Duration="{StaticResource AnimationDuration}"
Storyboard.TargetName="Line1"
Storyboard.TargetProperty="Point" />
<PointAnimation To="10,5" Duration="{StaticResource AnimationDuration}"
Storyboard.TargetName="Line2"
Storyboard.TargetProperty="Point" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Name="ToggleOff">
<Storyboard>
<PointAnimation Duration="{StaticResource AnimationDuration}"
Storyboard.TargetName="Figure"
Storyboard.TargetProperty="StartPoint" />
<PointAnimation Duration="{StaticResource AnimationDuration}"
Storyboard.TargetName="Line1"
Storyboard.TargetProperty="Point" />
<PointAnimation Duration="{StaticResource AnimationDuration}"
Storyboard.TargetName="Line2"
Storyboard.TargetProperty="Point" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
Note that the animations are triggered only by ToggleButton.IsChecked property (as opposed to data triggers bound to view-model properties), so this control is potentially reusable (I suggest you move the template to a style first though). The only thing to do is to properly bind the ToggleButton.IsChecked property.

Animate line to rotate clockwise in WPF

I'm trying to rotate a line clockwise, to simulate the loading animations we can usually find in internet, but I want to do it by myself.
I want to simulate something similar to this:
But I can't even move a simple line... This is my code trying to rotate a line:
<Canvas>
<Line
Name="LineTransformation"
X1="50" Y1="50"
X2="50" Y2="0"
Stroke="Red"
StrokeThickness="2">
<Line.RenderTransform>
<RotateTransform Angle="0" CenterX="{Binding ElementName=LineTransformation.X2}" CenterY="{Binding ElementName=LineTransformation.Y2}"></RotateTransform>
</Line.RenderTransform>
</Line>
</Canvas>
How can I make something similar? I can't even get how to rotate that line! :_(
The line is not being rotated. Your image is not even working correctly. This effect is achieved by drawing all 12 lines. Then, instead of animating the position of the lines, you animate the Opacity of each line from 1.0 to 0.0 in 12 steps and then jump straight back to 1.0.
This animation should run on each line in turn and slightly after the previous line so that there is this delayed effect which makes it look like the lines are moving around. You can do this animation using a DoubleAnimationUsingKeyFrames and 12 DiscreteDoubleKeyFrame elements with equally spaced KeyTime values.
To accurately reproduce exactly what your image is doing, you'd only need two different opacity levels, but it would still be achieved in the same way.
Try popping this code into a Window and taking a look at what I have done to demonstrate how this can be achieved...
<Window.Resources>
<Storyboard x:Key="SpinStoryboard">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="LineTransformation">
<EasingDoubleKeyFrame KeyTime="0" Value="-180"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="180"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource SpinStoryboard}"/>
</EventTrigger>
</Window.Triggers>
<Grid>
<Canvas Width="50" Height="50">
<Line
Name="LineTransformation"
X1="25" Y1="50"
X2="25" Y2="0"
Stroke="Red"
StrokeThickness="2" RenderTransformOrigin="1,0.5">
<Line.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Line.RenderTransform>
</Line>
</Canvas>
</Grid>
Essentially using RotateTransform and a storyboard to spin the line, the tigger is simply there to start the animation for demonstration purposes!

WPF - How do I make a UI element animate along a path of an ellipse?

I have a canvas that contains a couple other elements. I need this canvas to animate continuously along a circular (elliptical) path.
How can I do this in XAML?
not sure if this is doing it the hard way or not but this works...
<Canvas>
<Rectangle Height="30" Width="30" Fill="Blue">
<Rectangle.RenderTransform>
<MatrixTransform x:Name="elementMatrixTransform">
<MatrixTransform.Matrix >
<Matrix />
</MatrixTransform.Matrix>
</MatrixTransform>
</Rectangle.RenderTransform>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.Loaded">
<BeginStoryboard>
<Storyboard>
<MatrixAnimationUsingPath
Storyboard.TargetName="elementMatrixTransform"
Storyboard.TargetProperty="Matrix"
Duration="0:0:10"
RepeatBehavior="Forever">
<MatrixAnimationUsingPath.PathGeometry>
<PathGeometry>
<PathFigure StartPoint="0,50">
<ArcSegment Point="50,0" Size="50,50" SweepDirection="Clockwise"></ArcSegment>
<ArcSegment Point="100,50" Size="50,50" SweepDirection="Clockwise"></ArcSegment>
<ArcSegment Point="50,100" Size="50,50" SweepDirection="Clockwise"></ArcSegment>
<ArcSegment Point="0,50" Size="50,50" SweepDirection="Clockwise"></ArcSegment>
</PathFigure>
</PathGeometry>
</MatrixAnimationUsingPath.PathGeometry>
</MatrixAnimationUsingPath>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>

Resources