How To Create a Clock In Angular

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.   
  24.   ngOnInit() { }  
  25.   ngAfterViewInit() { 
  26.     const canvasEl: HTMLCanvasElement = this.canvasRef.nativeElement; 
  27.     canvasEl.width = this.width; 
  28.     canvasEl.height = this.height; 
  29.     const radius = canvasEl.height / 2; 
  30.     const innerRadius = radius * 0.89; 
  31.     this.canvasContext = canvasEl.getContext('2d'); 
  32.     this.canvasContext.translate(radius, radius); 
  33.     this.ngZone.runOutsideAngular(() => this.draw(innerRadius)); 
  34.   }  
  35.   ngOnChanges(change) { 
  36.     if (this.subscription) { 
  37.       this.subscription.unsubscribe(); 
  38.     }  
  39.     if (change.tdate) { 
  40.       this.tdate = change.tdate.currentValue; 
  41.       if(this.canvasRef) 
  42.       { 
  43.         const canvasEl: HTMLCanvasElement = this.canvasRef.nativeElement; 
  44.         canvasEl.width = this.width; 
  45.         canvasEl.height = this.height; 
  46.         const radius = canvasEl.height / 2; 
  47.         const innerRadius = radius * 0.89; 
  48.         this.canvasContext = canvasEl.getContext('2d'); 
  49.         this.canvasContext.translate(radius, radius); 
  50.         this.ngZone.runOutsideAngular(() => this.draw(innerRadius)); 
  51.       }  
  52.     }  
  53.   }  
  54.   ngOnDestroy() { 
  55.   }  
  56.   draw(innerRadius: number) { 
  57.     this.drawBackground(this.canvasContext, innerRadius); 
  58.   }  
  59.     
  60.   drawBackground(canvasContext, innerRadius) { 
  61.     var background = new Image(); 
  62.     let date =new Date(this.tdate) ; 
  63.     let dp= this.datePipe; 
  64.     let am_pm=dp.transform(date,"a"); 
  65.     if(am_pm=='AM' && background.src != "/assets/clockAM.png") 
  66.     { 
  67.       background.src = "/assets/clockAM.png"; 
  68.     }  
  69.     else if(am_pm=='PM' && background.src != "/assets/clockPM.png")  
  70.     { 
  71.       background.src = "/assets/clockPM.png"; 
  72.     }  
  73.     let $this = this;  
  74.     background.onload = function () { 
  75.       $this.subscription = timer(0, 1000)  
  76.         .pipe( 
  77.           tap(t => { 
  78.             canvasContext.clearRect($this.width / 2 * -1, $this.height / 2 * -1, $this.height, $this.width); 
  79.             date=new Date(date.setSeconds(date.getSeconds()+1)); 
  80.             canvasContext.drawImage(background, -50, -50, 100, 100); 
  81.             $this.drawTime(canvasContext, innerRadius,date); 
  82.           })  
  83.         )  
  84.         .subscribe(s=>{ 
  85.         }  
  86.         );  
  87.     }  
  88.   }  
  89.   drawFace(ctx, radius) { 
  90.     ctx.beginPath(); 
  91.     ctx.arc(0, 0, radius, 0, 2 * Math.PI); 
  92.     ctx.fillStyle = 'white'; 
  93.     ctx.fill(); 
  94.     const grad = ctx.createRadialGradient(0, 0, radius, 0.95, 0, 0, radius, 1.05); 
  95.     grad.addColorStop(0.5, '#333'); 
  96.     grad.addColorStop(0, '#1ABB9C'); 
  97.     ctx.strokeStyle = grad; 
  98.     ctx.lineWidth = radius * 0.050; 
  99.     ctx.stroke(); 
  100.     ctx.beginPath(); 
  101.     ctx.arc(0, 0, radius, 0.1, 0, 2, Math.PI); 
  102.     ctx.fillStyle = '#333'; 
  103.     ctx.fill(); 
  104.   }  
  105.   
  106.   drawNumbers(ctx, radius) { 
  107.     let ang; 
  108.     let num; 
  109.     let dot = '.'; 
  110.     ctx.font = radius * 0.1 + 'px arial'; 
  111.     ctx.font = "10pt Courier"; 
  112.     ctx.textBaseline = 'middle'; 
  113.     ctx.textAlign = 'center'; 
  114.     for (num = 1; num < 13; num++) { 
  115.       ang = num * Math.PI / 6; 
  116.       ctx.rotate(ang); 
  117.       ctx.translate(0, -radius * 0.85); 
  118.       ctx.rotate(-ang); 
  119.       ctx.fillText(dot, 0, 0); 
  120.       ctx.rotate(ang); 
  121.       ctx.translate(0, radius * 0.85); 
  122.       ctx.rotate(-ang); 
  123.     }  
  124.   }  
  125.   
  126.   drawTime(ctx, radius,date) { 
  127.     const { seconds, minutes, hours } = new TDate(date);  
  128.     const hourHand =  
  129.       (hours % 12) * Math.PI / 6 + minutes * Math.PI / (6 * 60) + seconds * Math.PI / (360 * 60);  
  130.     //this.drawHand(ctx, hourHand, radius * 0.5, radius * 0.07);  
  131.     this.drawHourHand(ctx, date, radius * 0.6, radius * 0.05);  
  132.     const minuteHand = minutes * Math.PI / 30 + seconds * Math.PI / (30 * 60);  
  133.     this.drawMinuteHand(ctx, date, radius * 0.8, radius * 0.04);  
  134.     //this.drawHand(ctx, minuteHand, radius * 0.8, radius * 0.07);  
  135.     const secondHand = seconds * Math.PI / 30;  
  136.     this.drawSecondHand(ctx, date, radius * 0.9, radius * 0.03);  
  137.     //this.drawHand(ctx, secondHand, radius * 0.9, radius * 0.02);  
  138.   }  
  139.   
  140.   // drawHand(ctx, pos, length, width) {  
  141.   //   ctx.beginPath();  
  142.   //   ctx.lineWidth = width;  
  143.   //   ctx.lineCap = 'round';  
  144.   //   ctx.moveTo(0, 0);  
  145.   //   ctx.rotate(pos);  
  146.   //   ctx.lineTo(0, -length);  
  147.   //   ctx.stroke();  
  148.   //   ctx.rotate(-pos);  
  149.   // }  
  150.   
  151.   degreesToRadians(degrees) { 
  152.     return (Math.PI / 180) * degrees 
  153.   }  
  154.   
  155.   drawHourHand(ctx, theDate, length, width) { 
  156.     var hours = theDate.getHours() + theDate.getMinutes() / 60; 
  157.  
  158.     var degrees = (hours * 360 / 12) % 360; 
  159.  
  160.     ctx.save(); 
  161.     ctx.fillStyle = 'black'; 
  162.     ctx.strokeStyle = '#555'; 
  163.  
  164.     ctx.rotate(this.degreesToRadians(degrees)); 
  165.  
  166.     this.drawHand(ctx, length, width, 3); 
  167.  
  168.     ctx.restore(); 
  169.  
  170.   }  
  171.   
  172.   drawMinuteHand(ctx, theDate, length, width) { 
  173.     var minutes = theDate.getMinutes() + theDate.getSeconds() / 60; 
  174.  
  175.     ctx.save(); 
  176.     ctx.fillStyle = 'black'; 
  177.     ctx.strokeStyle = '#555'; 
  178.     ctx.rotate(this.degreesToRadians(minutes * 6)); 
  179.  
  180.     this.drawHand(ctx, length, width, 5); 
  181.  
  182.     ctx.restore(); 
  183.   }  
  184.   
  185.   drawHand(ctx, size, thickness, shadowOffset) { 
  186.     thickness = thickness || 4; 
  187.  
  188.     // ctx.shadowColor = '#555'; 
  189.     // ctx.shadowBlur = 10; 
  190.     // ctx.shadowOffsetX = shadowOffset; 
  191.     // ctx.shadowOffsetY = shadowOffset; 
  192.  
  193.     ctx.beginPath(); 
  194.     ctx.moveTo(0, 0); // center 
  195.     ctx.lineTo(thickness * -1, -10); 
  196.     ctx.lineTo(0, size * -1); 
  197.     ctx.lineTo(thickness, -10); 
  198.     ctx.lineTo(0, 0); 
  199.     ctx.fill(); 
  200.     ctx.stroke(); 
  201.   }  
  202.   
  203.   drawSecondHand(ctx, theDate, length, width) { 
  204.     var seconds = theDate.getSeconds(); 
  205.     ctx.save(); 
  206.     ctx.fillStyle = '#1ABB9C'; 
  207.     ctx.strokeStyle = "#1ABB9C"; 
  208.     ctx.globalAlpha = 0.8; 
  209.     ctx.rotate(this.degreesToRadians(seconds * 6)); 
  210.  
  211.     this.drawHand(ctx, length, width, 0); 
  212.  
  213.     ctx.restore(); 
  214.   }  
  215.   
  216. }  
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.   
  8. @NgModule({ 
  9.   declarations: [ 
  10.     AppComponent, 
  11.     ClockComponent 
  12.   ], 
  13.   imports: [ 
  14.     BrowserModule, 
  15.     AppRoutingModule, 
  16.      
  17.   ], 
  18.   providers: [DatePipe], 
  19.   bootstrap: [AppComponent] 
  20. })  
  21. 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.