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>