Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object the follow the cursor of the mouse

Tags:

c#

wpf

i am doing a Wpf Application and i create a Control with the shape of an eye ,i put a Ellipse(eye) in a Canvas and my purpose is when the cursor of the mouse enter in the Canvas the Ellipse follow the cursor of mouse. Do you have any suggestion how perform this task? Thanks so much for your attention.

Cheers

EDIT

I have update my code in Xaml:

<Window Height="480" Title="Window2" Width="640" x:Class="WpfApplication5.Window2"
   x:Name="Window" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Window.Resources>
    <Storyboard x:Key="OnLoaded1">
      <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ctrCircle" 
        Storyboard.TargetProperty="(UIElement.RenderTransform).( TransformGroup.Children)[3].(TranslateTransform.X)">
        <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1">
          <EasingDoubleKeyFrame.EasingFunction>
            <ExponentialEase EasingMode="EaseOut" />
          </EasingDoubleKeyFrame.EasingFunction>
      </EasingDoubleKeyFrame>
      </DoubleAnimationUsingKeyFrames>
      <DoubleAnimationUsingKeyFrames Storyboard.TargetName="ctrCircle" 
          Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)">
        <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1">
        <EasingDoubleKeyFrame.EasingFunction>
            <ExponentialEase EasingMode="EaseOut" />
          </EasingDoubleKeyFrame.EasingFunction>
        </EasingDoubleKeyFrame>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
    <Style TargetType="Ellipse">
      <Setter Property="RenderTransform">
        <Setter.Value>
          <ScaleTransform ScaleX="1" ScaleY="1"/>
        </Setter.Value>
      </Setter>
      <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
    </Style>
  </Window.Resources>

  <Canvas MouseMove="mov" x:Name="LayoutRoot">
    <Border ackground="Black" B="" Canvas.Left="178" Canvas.Top="103" 
      CornerRadius="250" Height="255.5" Width="290" x:Name="border_eye">
      <Ellipse Fill="#FFFFC600" Height="12" HorizontalAlignment="Left" 
        Margin="0" RenderTransformOrigin="0.5,0.5" Stroke="{x:Null}" 
        VerticalAlignment="Center" Visibility="Visible" Width="12" x:Name="ctrCircle">
        <Ellipse.RenderTransform>
          <TransformGroup>
            <ScaleTransform />
            <SkewTransform />
            <RotateTransform />
            <TranslateTransform />                 
          </TransformGroup>
        </Ellipse.RenderTransform>
      </Ellipse>
    </Border>
  </Canvas>
</Window>

and in the code behind :

private void mov(object sender, MouseEventArgs e)
    {
 System.Windows.Point pt = e.GetPosition((Canvas)sender);
      Storyboard invokeStoryboard = this.Resources["OnLoaded1"] as Storyboard;
        ((DoubleAnimationUsingKeyFrames)invokeStoryboard.Children[0]).KeyFrames[0].Value = pt.X;
        ((DoubleAnimationUsingKeyFrames)invokeStoryboard.Children[1]).KeyFrames[0].Value = pt.Y;
        invokeStoryboard.Begin();
    }

now my purpose is when i move the mouse in the Canvas area(LayoutRoot) the Ellipse(ctrCircle) move only inside the Border(border_eye) and don't overcome the area of the "border_eye" this effect is similar an eye.

Do you have any input to work out this step?

Thanks so much

Have a nice day.

Cheers

like image 382
JayJay Avatar asked Nov 04 '10 02:11

JayJay


1 Answers

Here is an example of how to do an eye in a WPF canvas using the Rx framework. Using Rx instead of attaching to the mouse move event directly allows you to buffer the events and only update the Pupil position every 10 milliseconds reducing the overall CPU load.

The Xaml

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="namespace.EyeDemo"
    x:Name="UserControl"
    d:DesignWidth="640" d:DesignHeight="480">

    <Canvas x:Name="LayoutRoot" Background="GreenYellow">
        <Ellipse Fill="Black" Width="120" Height="70" Canvas.Left="90" Canvas.Top="115"/>
        <Ellipse x:Name="Eye" Fill="Black" Width="100" Height="50" Canvas.Left="100" Canvas.Top="125"/>
        <Ellipse x:Name="Pupil" Fill="Red" Height="20" Canvas.Left="139" Canvas.Top="138" Width="20"/>
    </Canvas>
</UserControl>

and the code behind

/// <summary>
/// Interaction logic for EyeDemo.xaml
/// </summary>
public partial class EyeDemo : UserControl
{
    public EyeDemo()
    {
        this.InitializeComponent();

        double majorRadius = Eye.Width / 2d;
        double minorRadius = Eye.Height / 2d;
        Point center = new Point( Canvas.GetLeft( Eye ) + majorRadius, Canvas.GetTop( Eye ) + minorRadius );

        // create event streams for mouse down/up/move using reflection
        // to keep taking mouse move events and return the X, Y positions
        var mouseMove = from evt in Observable.FromEvent<MouseEventArgs>( LayoutRoot, "PreviewMouseMove" )
                        select (Point?)evt.EventArgs.GetPosition( this );

        // subscribe to the stream of position changes and modify the Canvas.Left and Canvas.Top
        // use the bound by elipse function to restrain the pupil to with the eye.
        mouseMove.BufferWithTime( TimeSpan.FromMilliseconds( 10 ) ).Select( p => BoundByElipse( majorRadius, minorRadius, center, p.LastOrDefault() ) )
            .ObserveOnDispatcher().Subscribe( pos =>
              {
                  if( pos.HasValue )
                  {
                      Canvas.SetLeft( Pupil, pos.Value.X - Pupil.Width / 2d );
                      Canvas.SetTop( Pupil, pos.Value.Y - Pupil.Height / 2d );
                  }
              } );
    }

    private Point? BoundByElipse( double majorRadius, double minorRadius, Point center, Point? point )
    {
        if( point.HasValue )
        {
            // Formular for an elipse is  x^2 / a^2 + y^2 / b^2 = 1
            // where a = majorRadius and b = minorRadius
            // Using this formular we can work out if the point is with in the elipse 
            // or find the boundry point closest to the point

            // Find the location of the point relative to the center.
            Point p = new Point( point.Value.X - center.X, point.Value.Y - center.Y );
            double a = majorRadius;
            double b = minorRadius;

            double f = p.X * p.X / (a * a) + p.Y * p.Y / (b * b);
            if( f <= 1 )
            {
                // the point is with in the elipse;
                return point;
            }
            else
            {
                // the point is outside the elipse, therefore need to find the closest location on the boundry.
                double xdirection = point.Value.X > center.X ? 1 : -1;
                double ydirection = point.Value.X > center.X ? 1 : -1;

                double r = p.X / p.Y;

                double x = p.Y != 0 ? Math.Sqrt( r * r * a * a * b * b / (r * r * b * b + a * a) ) : a;
                double y = r != 0 ? x / r : (point.Value.Y > center.Y ? -b : b);

                return new Point( center.X + xdirection * x, center.Y + ydirection * y );
            }
        }
        else
        {
            return null;
        }
    }
}
like image 195
bstoney Avatar answered Oct 01 '22 22:10

bstoney