question

WillPittenger avatar image
0 Votes"
WillPittenger asked WillPittenger commented

WPF tracks that fade way

I'm creating a WPF app where an object is moving across the window, leaving a track behind as it does so. The oldest segments of the track need to fade away to nothing, possibly tapering as it does so. Any suggestions on how to do that? I see how to break the path representing the track into segments, one per step. But that seems heavy handed and slower.

windows-wpf
· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

DaisyTian-1203 avatar image
0 Votes"
DaisyTian-1203 answered WillPittenger commented

I do a test sample to implement what you want base on my understanding, if I misunderstand, please point out.
The Xaml code is:

  <Canvas  Name="paintSurface" >
         <Canvas.Background>
             <SolidColorBrush Color="White" Opacity="0"/>
         </Canvas.Background>
         <Border Grid.Row="1" Name="border">
             <Rectangle Name="rec" Fill="Red" Width="20" Height="20"></Rectangle>
         </Border>
     </Canvas>

The cs code is:

 public partial class MainWindow : Window
     {
         Point currentPoint = new Point();
         private Point origin;
         private Point start;
    
         public MainWindow()
         {
             InitializeComponent();
             Init();
         }
    
         public void Init()
         {
    
             TransformGroup group = new TransformGroup();
    
             ScaleTransform xform = new ScaleTransform();
             group.Children.Add(xform);
    
             TranslateTransform tt = new TranslateTransform();
             group.Children.Add(tt);
    
             rec.RenderTransform = group;
             rec.MouseLeftButtonDown += rec_MouseLeftButtonDown;
             rec.MouseLeftButtonUp += rec_MouseLeftButtonUp;
             rec.MouseMove += rec_MouseMove;
    
         }
    
         private void rec_MouseMove(object sender, MouseEventArgs e)
         {
             if (!rec.IsMouseCaptured) return;
    
             var tt = (TranslateTransform)((TransformGroup)rec.RenderTransform).Children.First(tr => tr is TranslateTransform);
             Vector v = start - e.GetPosition(border);
             tt.X = origin.X - v.X;
             tt.Y = origin.Y - v.Y;
    
            if (e.LeftButton == MouseButtonState.Pressed)
         {
             Line line = new Line();
             line.Stroke = SystemColors.WindowFrameBrush;
             line.X1 = currentPoint.X;
             line.Y1 = currentPoint.Y;
             line.X2 = e.GetPosition(this).X;
             line.Y2 = e.GetPosition(this).Y;
             currentPoint = e.GetPosition(this);
             Storyboard sb = new Storyboard();
             DoubleAnimation doubleAnimation = new DoubleAnimation()
             {
                 From = 1,
                 To = 0,
                 Duration = TimeSpan.FromMilliseconds(1000)
             };
             Storyboard.SetTarget(doubleAnimation, line);
             Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(Line.OpacityProperty));
             sb.Children.Add(doubleAnimation);
             sb.Begin();
             paintSurface.Children.Add(line);
         }
         }
    
         private void rec_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
         {
             rec.ReleaseMouseCapture();
         }
    
         private void rec_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         {
             rec.CaptureMouse();
             var tt = (TranslateTransform)((TransformGroup)rec.RenderTransform).Children.First(tr => tr is TranslateTransform);
             start = e.GetPosition(border);
             origin = new Point(tt.X, tt.Y);
    
             if (e.ButtonState == MouseButtonState.Pressed)
                 currentPoint = e.GetPosition(this);
         }
    
     }

The result picture is:
83492-2.gif


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



2.gif (132.4 KiB)
· 6
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Your sample doesn't fade with distance. As each point in the track ages, it needs to slowly disappear.

0 Votes 0 ·

@WillPittenger
I added a DoubleAnimation to the Line to implement want you want, and updated it in my answer. Please check it and let me know if it doesn't meet your needs.

0 Votes 0 ·

I should note that in my case, the path to follow would always be predetermined. When I start the animation, the entire path will be known. It will always be either an ArcSegment or a Line. The mouse won't be involved. Would that effect things?

Also, are you creating a new DoubleAnimation for each step?

0 Votes 0 ·

Much better.

0 Votes 0 ·

When the entire path has become completely invisible, do the objects involve delete themselves or do I need to do that? I see Timeline objects have a Completed event, but no mention of one for other Animation objects. For the past couple of days, I've been developing a system in my mind of code that would do the same thing using background threads instead of Animation objects. That code would remove completed threads and the associated objects.

0 Votes 0 ·

Ah. Storyboard derives from Timeline. I didn't see that. I was looking at the list of classes in the namespace from the class list tree on https://docs.microsoft.com/en-us/dotnet/api/system.windows.media.animation.storyboard?view=net-5.0 and didn't see any event section. If I had looked on the right side, I would have seen a event list link.

Now to try to adapt your code to my situation.

0 Votes 0 ·