Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Here is an example of how to do an eye in a WPF canvas using the <a href="http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx" rel="noreferrer">Rx framework</a>. 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.</p> <p>The Xaml</p> <pre><code>&lt;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"&gt; &lt;Canvas x:Name="LayoutRoot" Background="GreenYellow"&gt; &lt;Ellipse Fill="Black" Width="120" Height="70" Canvas.Left="90" Canvas.Top="115"/&gt; &lt;Ellipse x:Name="Eye" Fill="Black" Width="100" Height="50" Canvas.Left="100" Canvas.Top="125"/&gt; &lt;Ellipse x:Name="Pupil" Fill="Red" Height="20" Canvas.Left="139" Canvas.Top="138" Width="20"/&gt; &lt;/Canvas&gt; &lt;/UserControl&gt; </code></pre> <p>and the code behind</p> <pre><code>/// &lt;summary&gt; /// Interaction logic for EyeDemo.xaml /// &lt;/summary&gt; 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&lt;MouseEventArgs&gt;( 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 =&gt; BoundByElipse( majorRadius, minorRadius, center, p.LastOrDefault() ) ) .ObserveOnDispatcher().Subscribe( pos =&gt; { 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 &lt;= 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 &gt; center.X ? 1 : -1; double ydirection = point.Value.X &gt; 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 &gt; center.Y ? -b : b); return new Point( center.X + xdirection * x, center.Y + ydirection * y ); } } else { return null; } } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload