PROWAREtech

articles » current » blazor » wasm » timer-analog-clock

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

https://youtu.be/9YXVZru1Khw


This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE