Random animated clock
I have done some code samples in Silverlight 2.0, but nothing worth sharing. So over the weekend, I saw an pretty impressive clock written in Flash and had to try to emulate some of its functionality in Silverlight 2.0.
The clock can be seen here and I just loved the creativity, attention to detail and the smooth motion of the digits.
For my experiment, I am only trying to (somewhat) reproduce the gyration of the number cluster, based on their location and individual rotation.
Eventually, I will have more time to do it with all the digits and get it as smooth as in the Flash clock, with the subtle movements.
For now, this is just a quick attempt at recreating the concept and will hopefully do… 🙂
mainpage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightRandomClock_Fixed
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
this.animateSeconds.Begin();
}
private void myStoryboard_Completed(object sender, EventArgs e)
{
///sets the current time and if minutes is single digit,
///it adds a "0" for aesthetics
///and also eliminates last digit of seconds, whether 1 or 2 digits
currentTime.Text=DateTime.Now.Hour.ToString()+
":"+((DateTime.Now.Minute<10)?
"0"+DateTime.Now.Minute.ToString():DateTime.Now.Minute.ToString()).ToString()+
":"+((DateTime.Now.Second<10)?
"0":DateTime.Now.Second.ToString().Substring(0,1)).ToString();
TextBlock selectedDigit = new TextBlock();
if (DateTime.Now.Second > 9)
{
selectedDigit=Canvas_Digits.FindName(
"digit_"+DateTime.Now.Second.ToString().Substring(1, 1)) as TextBlock;
}
else
{
selectedDigit=Canvas_Digits.FindName(
"digit_" + DateTime.Now.Second.ToString().Substring(0, 1)) as TextBlock;
}
///reset all digits dimmer and smaller...
foreach (UIElement element in this.Canvas_Digits.Children)
{
if (element.GetType() == typeof(TextBlock))
{
TextBlock digit = element as TextBlock;
digit.FontSize = 48;
digit.Opacity = 0.2;
}
}
///turn selected digit brighter and bigger
selectedDigit.Opacity = 1.0;
selectedDigit.FontSize = 72;
///obtains the position of the Canvas_Digits
double distCanvasDigits_Left=
(double)Canvas_Digits.GetValue(Canvas.LeftProperty);
double distCanvasDigits_Top=
(double)Canvas_Digits.GetValue(Canvas.TopProperty);
///obtains the position of the selected digit
double distSelectedDigit_Left=
(double)selectedDigit.GetValue(Canvas.LeftProperty);
double distSelectedDigit_Top=
(double)selectedDigit.GetValue(Canvas.TopProperty);
///obtains the position of where the digit needs to fall
double distRectangle_Left=
(double)this.currentTime.GetValue(Canvas.LeftProperty)
+ this.currentTime.ActualWidth;
double distRectangle_Top=
(double)this.currentTime.GetValue(Canvas.TopProperty);
///translates the relative position to where the canvas needs to be moved
double digitTranslatedLeft =
distCanvasDigits_Left - distSelectedDigit_Left + distRectangle_Left;
double digitTranslatedTop =
distCanvasDigits_Top - distSelectedDigit_Top + distRectangle_Top;
///There has got to be a better way of finding this value... (revisit)
double digitRotation =
Convert.ToDouble(((RotateTransform)
((TransformGroup)selectedDigit.RenderTransform).Children[0]).Angle);
///change the renderTransformOrigin to the digit, so that when the
///Canvas rotates, it rotates around the digit
Canvas_Digits.RenderTransformOrigin =
new Point( distSelectedDigit_Left/Canvas_Digits.Width,
distSelectedDigit_Top/Canvas_Digits.Height);
///to values
this.splineDoubleTranslate_1s_x.Value = digitTranslatedLeft;
this.splineDoubleTranslate_1s_y.Value = digitTranslatedTop;
this.splineDoubleRotate_1s.Value = digitRotation * (-1);
this.animateSeconds.Begin();
}
}
}
mainpage.xaml
<UserControl
x:Class="SilverlightRandomClock_Fixed.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="UserControl" >
<Canvas x:Name="Canvas_Root" Height="400" Width="400" Background="#336699" >
<Image Source="tunnel-background (400 x 400).jpg" Canvas.ZIndex="-100" />
<TextBlock x:Name="currentTime" Canvas.Top="160" Canvas.Left="20"
Width="Auto" Height="Auto" FontFamily="aberatn.ttf#Aberration" FontSize="72" />
<Canvas x:Name="Canvas_Digits" Height="300" Width="300"
Canvas.Left="0" Canvas.Top="0" RenderTransformOrigin="0.5,0.5">
<TextBlock x:Name="digit_0" Text="0" FontSize="24"
Canvas.Top="93" Canvas.Left="144"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_0_Angle" Angle="-53"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_1" Text="1" FontSize="24"
Canvas.Top="121" Canvas.Left="55"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_1_Angle" Angle="51"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_2" Text="2" FontSize="24"
Canvas.Top="118" Canvas.Left="155"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_2_Angle" Angle="-35"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_3" Text="3" FontSize="24"
Canvas.Top="169" Canvas.Left="86"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_3_Angle" Angle="34"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_4" Text="4" FontSize="24"
Canvas.Top="61" Canvas.Left="96"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_4_Angle" Angle="98"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_5" Text="5" FontSize="24"
Canvas.Top="84" Canvas.Left="129"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_5_Angle" Angle="227"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_6" Text="6" FontSize="24"
Canvas.Top="169" Canvas.Left="151"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_6_Angle" Angle="43"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_7" Text="7" FontSize="24"
Canvas.Top="92" Canvas.Left="80"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_7_Angle" Angle="75"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_8" Text="8" FontSize="24"
Canvas.Top="145" Canvas.Left="65"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_8_Angle" Angle="-63"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<TextBlock x:Name="digit_9" Text="9" FontSize="24"
Canvas.Top="149" Canvas.Left="178"
FontFamily="aberatn.ttf#Aberration"
RenderTransformOrigin="0.5,0.5">
<TextBlock.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="digit_9_Angle" Angle="-27"/>
</TransformGroup>
</TextBlock.RenderTransform>
</TextBlock>
<Path x:Name="line_0" Opacity="0.2" Width="14" Height="42" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="4" Canvas.Left="138"
Canvas.Top="111" Data="M139,152 L151.42417,110.75304" />
<Path x:Name="line_1" Opacity="0.2" Width="80.5" Height="20.5" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="4" Canvas.Left="59"
Canvas.Top="132" Data="M232.39732,257.0378 L151.8293,237.98684" />
<Path x:Name="line_2" Opacity="0.2" Width="26.5" Height="14.5" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="3" Canvas.Left="138"
Canvas.Top="137.5" Data="M293.46481,392.45413 L318.61025,379.58186" />
<Path x:Name="line_3" Opacity="0.2" Width="46" Height="27.5" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="5" Canvas.Left="94"
Canvas.Top="149.5" Data="M386.34898,506.75993 L340.98988,532.65591" />
<Path x:Name="line_4" Opacity="0.2" Width="37.5" Height="75" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="7" Canvas.Left="102.5"
Canvas.Top="76" Data="M511.81077,575.34668 L548.51143,650.92936" />
<Path x:Name="line_5" Opacity="0.2" Width="5" Height="50.5" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="2" Canvas.Left="133.5"
Canvas.Top="102.5" Data="M650.63264,686.45684 L653.71166,736.40125" />
<Path x:Name="line_6" Opacity="0.2" Width="22" Height="35" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="6" Canvas.Left="136"
Canvas.Top="147.5" Data="M674.40959,767.68403 L652.51429,731.99329" />
<Path x:Name="line_7" Opacity="0.2" Width="48" Height="49" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="2" Canvas.Left="92.5"
Canvas.Top="105" Data="M608.55253,689.0313 L655.76435,737.43103" />
<Path x:Name="line_8" Opacity="0.2" Width="64.5" Height="8" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="2" Canvas.Left="76.5"
Canvas.Top="150.5" Data="M592.13103,742.06504 L656.27752,735.88636" />
<Path x:Name="line_9" Opacity="0.2" Width="40" Height="6.5" Fill="#FFFFFFFF"
Stretch="Fill" Stroke="#FF000000" StrokeThickness="1" Canvas.Left="138.5"
Canvas.Top="151" Data="M694.76541,741.03526 L655.76435,736.40125" />
<Canvas.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="SecondsRotationTransform" />
<TranslateTransform x:Name="SecondsTranslationTransform" />
<ScaleTransform x:Name="secondsScaleTransform" />
</TransformGroup>
</Canvas.RenderTransform>
</Canvas>
<Canvas.Resources>
<Storyboard x:Name="animateSeconds"
Completed="animateSeconds_Completed" >
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="SecondsRotationTransform"
Storyboard.TargetProperty="Angle" Duration="0:0:1" >
<SplineDoubleKeyFrame x:Name="splineDoubleRotate_1s"
KeyTime="00:00:00.50" KeySpline="0.25,0.50 0.75,1.00" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
x:Name="doubleAnimationUsingKeyFramesTranslate_X"
Storyboard.TargetName="SecondsTranslationTransform"
Storyboard.TargetProperty="X" Duration="0:0:1" >
<SplineDoubleKeyFrame x:Name="splineDoubleTranslate_1s_x"
KeyTime="00:00:00.50" KeySpline="0.25,0.50 0.75,1.00" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
x:Name="doubleAnimationUsingKeyFramesTranslate_Y"
Storyboard.TargetName="SecondsTranslationTransform"
Storyboard.TargetProperty="Y" Duration="0:0:1" >
<SplineDoubleKeyFrame x:Name="splineDoubleTranslate_1s_y"
KeyTime="00:00:00.50" KeySpline="0.25,0.50 0.75,1.00" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="secondsScaleTransform"
Storyboard.TargetProperty="ScaleX" Duration="00:00:01.00" >
<SplineDoubleKeyFrame KeyTime="00:00:00.80"
KeySpline="0.25,0.50 0.75,1.00" Value="1.00"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.90"
KeySpline="0.25,0.50 0.75,1.00" Value="0.98"/>
<SplineDoubleKeyFrame KeyTime="00:00:01.00"
KeySpline="0.25,0.50 0.75,1.00" Value="1.00"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="secondsScaleTransform"
Storyboard.TargetProperty="ScaleY" Duration="00:00:01.00" >
<SplineDoubleKeyFrame KeyTime="00:00:00.80"
KeySpline="0.25,0.50 0.75,1.00" Value="1.00"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.90"
KeySpline="0.25,0.50 0.75,1.00" Value="0.98"/>
<SplineDoubleKeyFrame KeyTime="00:00:01.00"
KeySpline="0.25,0.50 0.75,1.00" Value="1.00"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Canvas.Resources>
</Canvas>
</UserControl>


