Introduction

In this article, I will explain about how to create a clock using Angular.
Prerequisites
  • Angular 7
  • HTML/Bootstrap
In this article we will learn how to create a clock using canvas in Angular.
For this article, I have created an Angular project using Angular 7. For creating an Angular project, we need to follow the following steps:
Step 1
I have created a project using the following command in the Command Prompt.
  1. ng new clockexample
Step 2
Open a project in Visual Studio Code using the following commands.
  1. cd clockexample
  2. code.
Step 3
Create a new component using the following commands.
  1. ng g c clock
Import the following image in Assets folder:
Import the following dependancy in clock.component.ts:
  1. import { Component, ViewChild, ElementRef, Input, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
  2. import { ChangeDetectionStrategy, NgZone } from '@angular/core';
  3. import { Observable, timer, Subscription } from 'rxjs';
  4. import { timeInterval, tap, map } from 'rxjs/operators';
  5. import { TDate } from '../tdate';
  6. import { formatDate } from '@angular/common';
  7. import { DatePipe } from '@angular/common';
clock.component.ts
Add the following code in clock.component.ts:
  1. import { Component, ViewChild, ElementRef, Input, OnInit, AfterViewInit, OnDestroy } from '@angular/core';
  2. import { ChangeDetectionStrategy, NgZone } from '@angular/core';
  3. import { Observable, timer, Subscription } from 'rxjs';
  4. import { timeInterval, tap, map } from 'rxjs/operators';
  5. import { TDate } from '../tdate';
  6. import { formatDate } from '@angular/common';
  7. import { DatePipe } from '@angular/common';
  8. @Component({
  9. selector: 'cs-canvas-clock',
  10. template: '<canvas #mycanvas></canvas>',
  11. styles: [],
  12. changeDetection: ChangeDetectionStrategy.OnPush
  13. })
  14. export class ClockComponent implements OnInit, OnDestroy, AfterViewInit {
  15. @ViewChild('mycanvas', { static: false, read: ElementRef }) canvasRef: ElementRef;
  16. public tdate=new Date();
  17. @Input() public width = 100;
  18. @Input() public height = 100;
  19. canvasContext: CanvasRenderingContext2D;
  20. subscription: Subscription;
  21. constructor(private ngZone: NgZone,private datePipe: DatePipe) {
  22. }
  23. ngOnInit() { }
  24. ngAfterViewInit() {
  25. const canvasEl: HTMLCanvasElement = this.canvasRef.nativeElement;
  26. canvasEl.width = this.width;
  27. canvasEl.height = this.height;
  28. const radius = canvasEl.height / 2;
  29. const innerRadius = radius * 0.89;
  30. this.canvasContext = canvasEl.getContext('2d');
  31. this.canvasContext.translate(radius, radius);
  32. this.ngZone.runOutsideAngular(() => this.draw(innerRadius));
  33. }
  34. ngOnChanges(change) {
  35. if (this.subscription) {
  36. this.subscription.unsubscribe();
  37. }
  38. if (change.tdate) {
  39. this.tdate = change.tdate.currentValue;
  40. if(this.canvasRef)
  41. {
  42. const canvasEl: HTMLCanvasElement = this.canvasRef.nativeElement;
  43. canvasEl.width = this.width;
  44. canvasEl.height = this.height;
  45. const radius = canvasEl.height / 2;
  46. const innerRadius = radius * 0.89;
  47. this.canvasContext = canvasEl.getContext('2d');
  48. this.canvasContext.translate(radius, radius);
  49. this.ngZone.runOutsideAngular(() => this.draw(innerRadius));
  50. }
  51. }
  52. }
  53. ngOnDestroy() {
  54. }
  55. draw(innerRadius: number) {
  56. this.drawBackground(this.canvasContext, innerRadius);
  57. }
  58. drawBackground(canvasContext, innerRadius) {
  59. var background = new Image();
  60. let date =new Date(this.tdate) ;
  61. let dp= this.datePipe;
  62. let am_pm=dp.transform(date,"a");
  63. if(am_pm=='AM' && background.src != "/assets/clockAM.png")
  64. {
  65. background.src = "/assets/clockAM.png";
  66. }
  67. else if(am_pm=='PM' && background.src != "/assets/clockPM.png")
  68. {
  69. background.src = "/assets/clockPM.png";
  70. }
  71. let $this = this;
  72. background.onload = function () {
  73. $this.subscription = timer(0, 1000)
  74. .pipe(
  75. tap(t => {
  76. canvasContext.clearRect($this.width / 2 * -1, $this.height / 2 * -1, $this.height, $this.width);
  77. date=new Date(date.setSeconds(date.getSeconds()+1));
  78. canvasContext.drawImage(background, -50, -50, 100, 100);
  79. $this.drawTime(canvasContext, innerRadius,date);
  80. })
  81. )
  82. .subscribe(s=>{
  83. }
  84. );
  85. }
  86. }
  87. drawFace(ctx, radius) {
  88. ctx.beginPath();
  89. ctx.arc(0, 0, radius, 0, 2 * Math.PI);
  90. ctx.fillStyle = 'white';
  91. ctx.fill();
  92. const grad = ctx.createRadialGradient(0, 0, radius, 0.95, 0, 0, radius, 1.05);
  93. grad.addColorStop(0.5, '#333');
  94. grad.addColorStop(0, '#1ABB9C');
  95. ctx.strokeStyle = grad;
  96. ctx.lineWidth = radius * 0.050;
  97. ctx.stroke();
  98. ctx.beginPath();
  99. ctx.arc(0, 0, radius, 0.1, 0, 2, Math.PI);
  100. ctx.fillStyle = '#333';
  101. ctx.fill();
  102. }
  103. drawNumbers(ctx, radius) {
  104. let ang;
  105. let num;
  106. let dot = '.';
  107. ctx.font = radius * 0.1 + 'px arial';
  108. ctx.font = "10pt Courier";
  109. ctx.textBaseline = 'middle';
  110. ctx.textAlign = 'center';
  111. for (num = 1; num < 13; num++) {
  112. ang = num * Math.PI / 6;
  113. ctx.rotate(ang);
  114. ctx.translate(0, -radius * 0.85);
  115. ctx.rotate(-ang);
  116. ctx.fillText(dot, 0, 0);
  117. ctx.rotate(ang);
  118. ctx.translate(0, radius * 0.85);
  119. ctx.rotate(-ang);
  120. }
  121. }
  122. drawTime(ctx, radius,date) {
  123. const { seconds, minutes, hours } = new TDate(date);
  124. const hourHand =
  125. (hours % 12) * Math.PI / 6 + minutes * Math.PI / (6 * 60) + seconds * Math.PI / (360 * 60);
  126. //this.drawHand(ctx, hourHand, radius * 0.5, radius * 0.07);
  127. this.drawHourHand(ctx, date, radius * 0.6, radius * 0.05);
  128. const minuteHand = minutes * Math.PI / 30 + seconds * Math.PI / (30 * 60);
  129. this.drawMinuteHand(ctx, date, radius * 0.8, radius * 0.04);
  130. //this.drawHand(ctx, minuteHand, radius * 0.8, radius * 0.07);
  131. const secondHand = seconds * Math.PI / 30;
  132. this.drawSecondHand(ctx, date, radius * 0.9, radius * 0.03);
  133. //this.drawHand(ctx, secondHand, radius * 0.9, radius * 0.02);
  134. }
  135. // drawHand(ctx, pos, length, width) {
  136. // ctx.beginPath();
  137. // ctx.lineWidth = width;
  138. // ctx.lineCap = 'round';
  139. // ctx.moveTo(0, 0);
  140. // ctx.rotate(pos);
  141. // ctx.lineTo(0, -length);
  142. // ctx.stroke();
  143. // ctx.rotate(-pos);
  144. // }
  145. degreesToRadians(degrees) {
  146. return (Math.PI / 180) * degrees
  147. }
  148. drawHourHand(ctx, theDate, length, width) {
  149. var hours = theDate.getHours() + theDate.getMinutes() / 60;
  150. var degrees = (hours * 360 / 12) % 360;
  151. ctx.save();
  152. ctx.fillStyle = 'black';
  153. ctx.strokeStyle = '#555';
  154. ctx.rotate(this.degreesToRadians(degrees));
  155. this.drawHand(ctx, length, width, 3);
  156. ctx.restore();
  157. }
  158. drawMinuteHand(ctx, theDate, length, width) {
  159. var minutes = theDate.getMinutes() + theDate.getSeconds() / 60;
  160. ctx.save();
  161. ctx.fillStyle = 'black';
  162. ctx.strokeStyle = '#555';
  163. ctx.rotate(this.degreesToRadians(minutes * 6));
  164. this.drawHand(ctx, length, width, 5);
  165. ctx.restore();
  166. }
  167. drawHand(ctx, size, thickness, shadowOffset) {
  168. thickness = thickness || 4;
  169. // ctx.shadowColor = '#555';
  170. // ctx.shadowBlur = 10;
  171. // ctx.shadowOffsetX = shadowOffset;
  172. // ctx.shadowOffsetY = shadowOffset;
  173. ctx.beginPath();
  174. ctx.moveTo(0, 0); // center
  175. ctx.lineTo(thickness * -1, -10);
  176. ctx.lineTo(0, size * -1);
  177. ctx.lineTo(thickness, -10);
  178. ctx.lineTo(0, 0);
  179. ctx.fill();
  180. ctx.stroke();
  181. }
  182. drawSecondHand(ctx, theDate, length, width) {
  183. var seconds = theDate.getSeconds();
  184. ctx.save();
  185. ctx.fillStyle = '#1ABB9C';
  186. ctx.strokeStyle = "#1ABB9C";
  187. ctx.globalAlpha = 0.8;
  188. ctx.rotate(this.degreesToRadians(seconds * 6));
  189. this.drawHand(ctx, length, width, 0);
  190. ctx.restore();
  191. }
  192. }
App.module.ts
  1. import { BrowserModule } from '@angular/platform-browser';
  2. import { NgModule } from '@angular/core';
  3. import { DatePipe } from '@angular/common';
  4. import { AppRoutingModule } from './app-routing.module';
  5. import { AppComponent } from './app.component';
  6. import { ClockComponent } from './clock/clock.component';
  7. @NgModule({
  8. declarations: [
  9. AppComponent,
  10. ClockComponent
  11. ],
  12. imports: [
  13. BrowserModule,
  14. AppRoutingModule,
  15. ],
  16. providers: [DatePipe],
  17. bootstrap: [AppComponent]
  18. })
  19. export class AppModule { }
App.components.html
  1. <span height="70" align="right" class="float-right" id="canvasClock">
  2. <cs-canvas-clock></cs-canvas-clock>
  3. </span>
Now, run the project using the following command:
  1. ng serve

Summary

In this article, I have discussed how to create a clock using canvas in Angular.