Pages Menu
TwitterRssFacebook
Categories Menu

Posted by on 14th December, 2008

Random animated clock

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>