πŸ“œ ⬆️ ⬇️

HTML5 analog clock with JavaScript logic



For whom and why this article?


When you study a new technology or programming language, the basic concepts are always relatively routine, and therefore, in my opinion, quickly discourage the desire to learn from beginners. The purpose of this article is to interest and captivate the reader by studying programming using the example of developing elementary graphics in a dynamic mode. The article is suitable for novice developers who are familiar with the basics of HTML5 and JavaScript , and who are bored with seeing static text on a page when displaying arrays, objects, results of arithmetic operations, etc. to the browser console. Next, we implement the simplest, but useful animation for understanding the language.

What do we do?


Consider the process of creating the simplest analog clock using HTML5 and JavaScript. Draw the clock will be graphic primitives, not using the CSS . We will recall some geometry for displaying our graphics, recall some mathematics for implementing the logic of displaying our animated clocks. And in general, we will try to reduce the entropy in the knowledge of the JavaScript language. For development we need a text editor like Notepad ++ or Sublime Text 3 .

Digital clock implementation


Create three files in a text editor. (All three files must be in the same folder).
')
index.html - main page
clockscript.js - script with work logic
style.css - style file

First we will display the current time in a normal div- block in the .html file. Even in such a small task there is a pitfall. If you just throw the clock display function into the onload event of the body tag, then the current time will be displayed in the line, but it will remain static. And the div block in which we sent the string with the current time will not be updated by itself.

You can achieve a self-update of the page element by wrapping the time mapping function into an anonymous method, which is assigned to the onload property of the root Window object.

One of the options for implementation may be as follows. Index.html file:

<!DOCTYPE html> <html> <head> <title></title> <meta http-equiv = "Content-Type" content = "text/html; charset = utf-8" > <link rel = "stylesheet" type = "text/css" href = "style.css"> <script src = "clockscript.js"></script> </head> <body>   JavaScript.   : <br> <div id='clock'>   </div> <br> <canvas height='480' width='480' id='myCanvas'></canvas> </body> </html> 

File style.css :

 #clock{ font-family:Tahoma, sans-serif; font-size:20px; font-weight:bold; color:#0000cc; } 

File clockscript.js :

 window.onload = function(){ window.setInterval( function(){ var d = new Date(); document.getElementById("clock").innerHTML = d.toLocaleTimeString(); } , 1000); } 

We will deal with the work of clockscript.js :

We execute the internal JavaScript code by binding to the onload event of the root Window object:

 window.onload = function(){/*--*/} 

A method of the Window object object that executes code at specified intervals (specified in milliseconds):

 window.setInterval(function(){/* ,   ,     1000 */} , 1000); 

The Date object is used to perform various manipulations with the date and time. Using the constructor, create an instance of it and call it d :

 var d = new Date(); 

Find the DOM object by its id. This is exactly the object in which we want to display our time. It can be a paragraph, a heading or some other element. I have this div block. After getting the item by id, use its innerHTML property to get the entire contents of the item along with the markup inside. And we pass there the result of the toLocaleTimeString () method, which returns the formatted time representation:

 document.getElementById("clock").innerHTML = d.toLocaleTimeString(); 

This is what should happen (time dynamically changes every second):



Analog clock implementation


From now on, we will use Canvas (HTML) , which will serve as our canvas for creativity.

To see our canvas in the index.html file inside the body, we need somewhere to place the following tag, immediately determining its size:

 <canvas height='480' width='480' id='myCanvas'></canvas> 

Now in the clockscript.js file, before attempting to draw, you need to get the context of the Canvas object. We do this at the beginning of our watch display function. Then the clockscript.js file will change as follows:

 function displayCanvas(){ var canvasHTML = document.getElementById('myCanvas'); var contextHTML = canvasHTML.getContext('2d'); contextHTML.strokeRect(0,0,canvasHTML.width, canvasHTML.height); //           return; } window.onload = function(){ window.setInterval( function(){ var d = new Date(); document.getElementById("clock").innerHTML = d.toLocaleTimeString(); displayCanvas(); } , 1000); } 

Well, let's remember the math? It is important for us to understand the connection between the divisions of certain hands and the angle of their rotation on the future dial.

The angle of rotation of all the arrows in 1 second:


First problem:

That is, even in 1 second all the arrows must turn, each at a corresponding angle. And if this is not taken into account, then the first pitfall that we get in the display will be an ugly animation. For example, when the time will be 19:30, the hour hand will show exactly at 19 o'clock, although in real life it should already be half close to 20 o'clock. Similarly, the smooth movement of the minute hand will look nicer. Well, let the seconds hand flip through discrete movements, as in most real mechanical watches. The solution to the problem: add to the angles of rotation of the current arrow the angle of rotation of the faster arrow multiplied by the coefficient indicating its share of the angle of the current arrow.

Implementation:

 var t_sec = 6*d.getSeconds(); //    var t_min = 6*(d.getMinutes() + (1/60)*d.getSeconds()); //    var t_hour = 30*(d.getHours() + (1/60)*d.getMinutes()); //    

The second problem:

The angle of the rotating radius vector (clock hand) is measured from the positive direction in the counterclockwise direction. If we do not take this into account in our logic, we will turn the clock back into the past.

And yet, the countdown of hours, minutes and seconds comes from the number 12, the top position. Solution of the problem: in our formulas we must take this into account as a shift of + Ο€ / 2 (90 o ). And before the angle value put the sign "-" so that the clock goes exactly clockwise. And, of course, take into account that the transfer of the angle in degrees to the trigonometric functions of programming languages ​​is carried out with multiplication by the coefficient "Ο€ / 180 o ".

Implementation on the example of the second hand:

 contextHTML.moveTo(xCenterClock, yCenterClock); contextHTML.lineTo(xCenterClock + lengthSeconds*Math.cos(Math.PI/2 - t_sec*(Math.PI/180)), yCenterClock - lengthSeconds*Math.sin(Math.PI/2 - t_sec*(Math.PI/180))); 

Third problem:

In the course of marking the dial marks, you need to somehow allocate the marks opposite the clock. Total Risochek - 60 for seconds and minutes. 12 - for hours. These 12 must somehow stand out from the rest. Also, the symmetry of digitization depends on the width of the numbers. Obviously, the numbers 10, 11 and 12 are wider than 1, 2, 3, etc. Do not forget about it.

The solution to the problem and the option of digitizing the dial:

 for(var th = 1; th <= 12; th++){ contextHTML.beginPath(); contextHTML.font = 'bold 25px sans-serif'; var xText = xCenterClock + (radiusNum - 30) * Math.cos(-30*th*(Math.PI/180) + Math.PI/2); var yText = yCenterClock - (radiusNum - 30) * Math.sin(-30*th*(Math.PI/180) + Math.PI/2); //    ,        //  "10"    (!) if(th <= 9){ contextHTML.strokeText(th, xText - 5 , yText + 10); }else{ contextHTML.strokeText(th, xText - 15 , yText + 10); } contextHTML.stroke(); contextHTML.closePath(); } 

With all this in mind, my version of the execution of the logic code and the display of an analog clock is as follows:

Code clockscript.js
 function displayCanvas(){ var canvasHTML = document.getElementById('myCanvas'); var contextHTML = canvasHTML.getContext('2d'); contextHTML.strokeRect(0,0,canvasHTML.width, canvasHTML.height); //      var radiusClock = canvasHTML.width/2 - 10; var xCenterClock = canvasHTML.width/2; var yCenterClock = canvasHTML.height/2; // . contextHTML.fillStyle = "#ffffff"; contextHTML.fillRect(0,0,canvasHTML.width,canvasHTML.height); //   contextHTML.strokeStyle = "#000000"; contextHTML.lineWidth = 1; contextHTML.beginPath(); contextHTML.arc(xCenterClock, yCenterClock, radiusClock, 0, 2*Math.PI, true); contextHTML.moveTo(xCenterClock, yCenterClock); contextHTML.stroke(); contextHTML.closePath(); //   var radiusNum = radiusClock - 10; //   var radiusPoint; for(var tm = 0; tm < 60; tm++){ contextHTML.beginPath(); if(tm % 5 == 0){radiusPoint = 5;}else{radiusPoint = 2;} //    var xPointM = xCenterClock + radiusNum * Math.cos(-6*tm*(Math.PI/180) + Math.PI/2); var yPointM = yCenterClock - radiusNum * Math.sin(-6*tm*(Math.PI/180) + Math.PI/2); contextHTML.arc(xPointM, yPointM, radiusPoint, 0, 2*Math.PI, true); contextHTML.stroke(); contextHTML.closePath(); } //   for(var th = 1; th <= 12; th++){ contextHTML.beginPath(); contextHTML.font = 'bold 25px sans-serif'; var xText = xCenterClock + (radiusNum - 30) * Math.cos(-30*th*(Math.PI/180) + Math.PI/2); var yText = yCenterClock - (radiusNum - 30) * Math.sin(-30*th*(Math.PI/180) + Math.PI/2); if(th <= 9){ contextHTML.strokeText(th, xText - 5 , yText + 10); }else{ contextHTML.strokeText(th, xText - 15 , yText + 10); } contextHTML.stroke(); contextHTML.closePath(); } //  var lengthSeconds = radiusNum - 10; var lengthMinutes = radiusNum - 15; var lengthHour = lengthMinutes / 1.5; var d = new Date(); //   var t_sec = 6*d.getSeconds(); //    var t_min = 6*(d.getMinutes() + (1/60)*d.getSeconds()); //    var t_hour = 30*(d.getHours() + (1/60)*d.getMinutes()); //    //  contextHTML.beginPath(); contextHTML.strokeStyle = "#FF0000"; contextHTML.moveTo(xCenterClock, yCenterClock); contextHTML.lineTo(xCenterClock + lengthSeconds*Math.cos(Math.PI/2 - t_sec*(Math.PI/180)), yCenterClock - lengthSeconds*Math.sin(Math.PI/2 - t_sec*(Math.PI/180))); contextHTML.stroke(); contextHTML.closePath(); //  contextHTML.beginPath(); contextHTML.strokeStyle = "#000000"; contextHTML.lineWidth = 3; contextHTML.moveTo(xCenterClock, yCenterClock); contextHTML.lineTo(xCenterClock + lengthMinutes*Math.cos(Math.PI/2 - t_min*(Math.PI/180)), yCenterClock - lengthMinutes*Math.sin(Math.PI/2 - t_min*(Math.PI/180))); contextHTML.stroke(); contextHTML.closePath(); //  contextHTML.beginPath(); contextHTML.lineWidth = 5; contextHTML.moveTo(xCenterClock, yCenterClock); contextHTML.lineTo(xCenterClock + lengthHour*Math.cos(Math.PI/2 - t_hour*(Math.PI/180)), yCenterClock - lengthHour*Math.sin(Math.PI/2 - t_hour*(Math.PI/180))); contextHTML.stroke(); contextHTML.closePath(); //   contextHTML.beginPath(); contextHTML.strokeStyle = "#000000"; contextHTML.fillStyle = "#ffffff"; contextHTML.lineWidth = 3; contextHTML.arc(xCenterClock, yCenterClock, 5, 0, 2*Math.PI, true); contextHTML.stroke(); contextHTML.fill(); contextHTML.closePath(); return; } window.onload = function(){ window.setInterval( function(){ var d = new Date(); document.getElementById("clock").innerHTML = d.toLocaleTimeString(); displayCanvas(); } , 1000); } 


The result of the js-script on JSFiddle

Conclusion


Here such hours should turn out as a result. I hope that this article will help you understand the basic animation in JavaScript and will give you an interest in mastering this beautiful programming language. Thanks for attention.

Source: https://habr.com/ru/post/275353/


All Articles