PROWAREtech
Blazor: Timer Example - Analog Clock
A Blazor WebAssembly (WASM) example using the Timer class to create and set an analog clock.
This code is compatible with .NET Core 3.1, .NET 5, .NET 6 and .NET 8.
Here is an example that uses the timer (System.Threading.Timer
) to set an analog clock. It runs as client-side Blazor WASM code. For a server-side SignalR version, see this article.
All measurements are based off of percentages so it will scale to practically any size.
For an example of the Timer
class refreshing data from a WebApi on the screen, see this article.
Here is the clock specific CSS code that should be added to the Blazor WASM app.
.clock-container {
background-color: midnightblue;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
min-height: 75vmin;
}
.clock {
position: relative;
overflow: hidden;
background-color: inherit;
height: 70vmin;
width: 70vmin;
border-radius: 50%;
box-shadow: 0 -12px 12px rgba(255,255,255,.1),
inset 0 -12px 12px rgba(255,255,255,.1),
0 12px 12px rgba(0,0,0,.1),
inset 0 12px 12px rgba(0,0,0,.1);
}
.clock div {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-color: transparent;
}
.clock div div {
left: 50%;
width: 0;
}
.clock span {
position: absolute;
font-family: Arial;
font-size: 5vmin;
font-weight: bold;
color: lime;
}
.clock .h12 {
left: 50%;
top: 3%;
transform: translateX(-50%);
}
.clock .h12::before {
content: "12";
}
.clock .h3 {
left: 97%;
top: 50%;
transform: translate(-100%, -50%);
}
.clock .h3::before {
content: "3";
}
.clock .h6 {
left: 50%;
top: 97%;
transform: translate(-50%, -100%);
}
.clock .h6::before {
content: "6";
}
.clock .h9 {
left: 3%;
top: 50%;
transform: translateY(-50%);
}
.clock .h9::before {
content: "9";
}
.clock .ctr {
width: 3%;
height: 3%;
border-radius: 50%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: wheat;
}
.clock .hour div {
top: 20%;
height: 30%;
border: 2px solid wheat;
margin-left: -2px;
}
.clock .minute div {
top: 10%;
height: 40%;
border: 2px solid wheat;
margin-left: -2px;
}
.clock .second div {
top: 5%;
height: 65%;
border: 1px solid red;
margin-left: -1px;
}
Here is the Index.razor (Home.razor on .NET 8) page that uses the Timer
class. It needs to call StateHasChanged()
because there is no user-fired event.
@page "/"
<div class="clock-container">
<div class="clock">
<span class="h12"></span>
<span class="h3"></span>
<span class="h6"></span>
<span class="h9"></span>
<div class="hour" style="transform:rotate(@(hr)deg);"><div></div></div>
<div class="minute" style="transform:rotate(@(min)deg);"><div></div></div>
<div class="second" style="transform:rotate(@(sec)deg);"><div></div></div>
<span class="ctr"></span>
</div>
</div>
@code {
System.Threading.Timer timer;
double hr, min, sec;
// NOTE: this math can be simplified!!!
private void SetClock(object stateInfo)
{
var time = DateTime.Now;
hr = 360.0 * time.Hour / 12 + 30.0 * time.Minute / 60.0;
min = 360.0 * time.Minute / 60 + 6.0 * time.Second / 60.0;
sec = 360.0 * time.Second / 60 + 6.0 * time.Millisecond / 1000.0;
StateHasChanged(); // MUST CALL StateHasChanged() BECAUSE THIS IS TRIGGERED BY A TIMER INSTEAD OF A USER EVENT
}
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
SetClock(null);
timer = new System.Threading.Timer(SetClock, new System.Threading.AutoResetEvent(false), 10, 10); // 10 milliseconds
}
}
Coding Video
Comment