In this second (but not last) post, we will discuss different techniques for animating the clipping area.
The image is a painting ("The persistence of memory") from Salvador Dali (1904-1989), the famous Spanish (Catalan) surrealist painter.
In this post, we'll animate the clipping area using an old animation technique, ie the timer.
Project / source code
We have two identical images : one, in the background, with an opacity of 0.3 and the other, on top, with a clipping area limited to a growing ellipse that will appear (at random location) at regular interval :
<Image Source="Dali.jpg" Width="500" Height="363" Opacity="0.3" />
<Image Source="Dali.jpg" Width="500" Height="363" >
<Image.Clip>
<EllipseGeometry x:Name="ellGeo" />
</Image.Clip>
</Image>
The animation is here based on the timer, a technique used by veterans of animations in computer programs. Though animation techniques introduced in WPF and Silverlight have to be privileged (see next post), the technique based on the timer is still there (do not throw it away too fast). To use the timer :
using System.Windows.Threading;
.....
DispatcherTimer timer; // outside of function
In the function that handles the Loaded event :
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 50); // 50 millisec
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
The following function is executed at regular interval :
void timer_Tick(object sender, EventArgs e)
{
.....
}
Our timer_Tick function is simple :
- we reinitialize the EllipseGeometry properties every 100 ticks : new Center (at random location) and reduced radius (also a random small value),
- we make this ellipse bigger every tick.
Random rndm;
.....
rndm = new Random();
.....
int N;
void timer_Tick(object sender, EventArgs e)
{
if (N % 100==0)
{
X = rndm.Next(500); Y = rndm.Next(380);
W = rndm.Next(10);
ellGeo.Center = new Point(X, Y);
}
W += 5; ellGeo.RadiusX = ellGeo.RadiusY = W;
N++;
}
Now, let's go a step further : the clipping area is now made from several basic figures, here several growing ellipses, that are dynamically added to the clipping area :
Project / source code
Since the clipping area is build dynamically (in the timer_Tick function), the XAML is just :
<Image Source="Dali.jpg" Width="500" Height="363" Opacity="0.3" />
<Image Source="Dali.jpg" Width="500" Height="363" >
<Image.Clip>
<GeometryGroup x:Name="geoGroup" FillRule="Nonzero" />
</Image.Clip>
</Image>
It's important to specify NonZero in the FillRule property. Otherwise, the intersection of two or several ellipses is not part of the clipping area.
The timer_Tick function becomes :
void timer_Tick(object sender, EventArgs e)
{
if (N % 100 == 0) geoGroup.Children.Clear(); // reset clipping area
if (N % 2 == 0)
{
// create a new hole in the clipping area
EllipseGeometry eg = new EllipseGeometry();
eg.Center = new Point(rndm.Next(0, 500), rndm.Next(0, 360));
eg.RadiusX = eg.RadiusY = rndm.Next(5, 20);
geoGroup.Children.Add(eg);
}
// grow and move slightly each ellipse
foreach (EllipseGeometry g in geoGroup.Children)
{
g.RadiusX += 2; g.RadiusY += 2;
g.Center = new Point(g.Center.X, g.Center.Y - 1);
}
N++;
}
In the next post, we will use the Silverlight animation technique to animate the clipping area.