1

I can create animation to create an object to move along the motion path. But I wonder, is it doable to have multiple object/path like moving by cloning itself?

Assume this is my map:-

enter image description here

I want to go from current location to the playground. I have a path and assign it to be motion path for my object(navigation arrow) to move alongside the line path. And for the curiosity, I want it to be like below:-

enter image description here

Currently, using the motion path, the arrow can moving in single object:-

enter image description here

UPDATED Code:

<Grid>
        <Path x:Name="SuperPath" Stroke="Black">
            <Path.Data>
                <PathGeometry Figures="M277,66 C277,66 427,87 447,153 466,219 396,241 397,297 399,352 439,376 439,376" />
            </Path.Data>
        </Path>
        <Path
            x:Name="Arrowhead"
            Width="23"
            Height="19.5"
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Data="M94,29 L117,39 95,49 99,38 z"
            Fill="#ff387cc0"
            Stretch="Fill">
            <Path.RenderTransform>
                <TransformGroup>
                    <TranslateTransform X="-10" Y="-10" />
                    <MatrixTransform x:Name="rectangleTransform">
                        <MatrixTransform.Matrix>
                            <Matrix />
                        </MatrixTransform.Matrix>
                    </MatrixTransform>
                </TransformGroup>
            </Path.RenderTransform>
            <Path.Triggers>
                <EventTrigger RoutedEvent="Path.Loaded">
                    <BeginStoryboard>
                        <Storyboard>
                            <MatrixAnimationUsingPath
                                DoesRotateWithTangent="True"
                                RepeatBehavior="Forever"
                                Storyboard.TargetName="rectangleTransform"
                                Storyboard.TargetProperty="Matrix"
                                Duration="00:00:3">
                                <MatrixAnimationUsingPath.PathGeometry>
                                    <PathGeometry PresentationOptions:Freeze="True" Figures="M277,66 C277,66 427,87 447,153 466,219 396,241 397,297 399,352 439,376 439,376" />
                                </MatrixAnimationUsingPath.PathGeometry>
                            </MatrixAnimationUsingPath>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Path.Triggers>
        </Path>
    </Grid>

enter image description here

How do each time arrowhead moving through path, it can leave a copy of the arrow trail like a navigation trail so it will be something for example 30 arrowhead with distance between it along the trail path.

Luiey
  • 843
  • 2
  • 23
  • 50
  • Can you copy/paste code here instead of given link ? Because we have to register and also because maybe you will delete it, and so it will not be avalable for other users – Elikill58 Jul 19 '21 at 16:03
  • I want to add the code. But it had the path data and it has 405 line. Though, let me remove the fancy unneeded object and let the real one in code. – Luiey Jul 19 '21 at 16:15
  • 1
    In WPF you can specify animations using paths. Check [Path Animations Overview](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/graphics-multimedia/path-animations-overview?view=netframeworkdesktop-4.8). Other articles in that section show how key frames, timing, and storyboards can work – Panagiotis Kanavos Jul 19 '21 at 16:19
  • Assuming you are doing this by MatrixAnimationUsingPath, you may at certain times create a copy of the currently animated Matrix value. Then create a copy of the arrow object and use the copied Matrix as its RenderTransform (or whatever transform you are actually using for the animated arrow). – Clemens Jul 19 '21 at 16:20
  • @Clemens, sorry I cannot imagine the process you have mention because I've never done the Matrix part before. I want the arrowhead create a static copy of previous move, as in the end of the motion path, I can see a trail of arrowhead from start to end. – Luiey Jul 19 '21 at 16:29
  • Just replace the TransformGroup by a single MatrixTransform and the two DoubleAnimationUsingPath by a MatrixAnimationUsingPath that animates the Matrix property of the MatrixTransform, i.e. `Storyboard.TargetProperty="RenderTransform.Matrix"`. If you set `DoesRotateWithTangent="True"` on the MatrixAnimationUsingPath , you would get the direction of the arrow for free. – Clemens Jul 19 '21 at 16:39

1 Answers1

2

First of all, simplify the XAML a bit:

<Canvas x:Name="canvas">
    <Canvas.Resources>
        <PathGeometry
            x:Key="pathToFollow"
            Figures="M73.517,48.931 C73.517,48.931 253.690,80.828 245.931,161.000 C238.172,241.172 114.897,261.000 221.793,350.655"/>

        <Storyboard x:Key="arrowheadAnimation">
            <MatrixAnimationUsingPath
                Storyboard.TargetName="arrowhead"
                Storyboard.TargetProperty="RenderTransform.Matrix"
                PathGeometry="{StaticResource pathToFollow}"
                DoesRotateWithTangent="True"
                Duration="0:0:5"/>
        </Storyboard>
    </Canvas.Resources>

    <Path Data="{StaticResource pathToFollow}"
          Stroke="#ff818181" StrokeThickness="6.0" StrokeDashArray="4.33"
          StrokeStartLineCap="Round" StrokeEndLineCap="Round"/>

    <Path x:Name="arrowhead"
          Data="M0,0 L-10,-10 30,0 -10,10 Z"
          Fill="#ff387cc0">
        <Path.RenderTransform>
            <MatrixTransform/>
        </Path.RenderTransform>
    </Path>
</Canvas>

Now there may be the following code behind that starts the animation in a Loaded event handler. In addition, it creates a timer that creates copies of the arrow head at certain times.

private readonly Storyboard storyboard;
private readonly DispatcherTimer timer;

public MainWindow()
{
    InitializeComponent();
    storyboard = (Storyboard)canvas.Resources["arrowheadAnimation"];
    timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.5) };
    timer.Tick += OnTimerTick;
    Loaded += OnWindowLoaded;
}

private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    storyboard = (Storyboard)Resources["arrowheadAnimation"];
    storyboard.Begin();
    timer.Start();
}

private void OnTimerTick(object sender, EventArgs e)
{
    if (storyboard.GetCurrentState() != ClockState.Active)
    {
        timer.Stop();
        return;
    }

    var transform = (MatrixTransform)arrowhead.RenderTransform;

    var arrowheadCopy = new Path
    {
        Data = arrowhead.Data,
        Fill = arrowhead.Fill,
        RenderTransform = new MatrixTransform(transform.Matrix)
    };

    canvas.Children.Add(arrowheadCopy);
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
  • Yes, it did the job! On the XAML, I need to pull out the `Canvas.Resources` to `Page.Resources` as the runtime cannot found the `arrowheadAnimation` on window loaded. – Luiey Jul 19 '21 at 17:57
  • 1
    I also had this in Window.Resources before. After editing, there is now `canvas.Resources["arrowheadAnimation"]` in the Window constructor. Anyway, it doesn't matter where it actually is. – Clemens Jul 19 '21 at 17:59
  • how do you make `arrowhead` that have it rectangle at 0,0 but the arrow object is centering it's center at 0,0? I try to make new one, but cannot make any that look like yours result in the arrow move outside of the line, not center of the line. – Luiey Jul 22 '21 at 03:43
  • Create a path with origin at (0,0), i.e. both positive and negative coordinate values. In order to extend its bounding box to "not drawn" areas, add appropriate "move" (M) statements. – Clemens Jul 22 '21 at 06:21