Home >Web Front-end >JS Tutorial >How to create clock animation using Canvas

How to create clock animation using Canvas

一个新手
一个新手Original
2017-10-16 09:51:021776browse

Reviewing the knowledge points from Javascript to Canvas, I saw an example of a static clock drawn using Canvas, and wanted to turn it into a clock animation that dynamically displays the system time. In addition, coupled with a digital display clock, a small clock module was born! The current interface is still relatively rough, with only a simple interface and animation effects.

This clock includes two parts, the animated disc clock and the digital clock. The first is to use the timeout to call the setTimeout() method to create a loop animation effect to display the time. Let’s look at the code of the digital clock first. It is relatively simple. The disc clock is also made to imitate the digital clock.


var ntimeoutId = setTimeout(ntimeOut,0);function ntimeOut() {
    clearTimeout(ntimeoutId);    
    var now = new Date();    
    var hours = now.getHours().toString(),
        minutes = now.getMinutes().toString(),
        seconds = now.getSeconds().toString();    
        var time = hours+" : "+minutes+" : "+seconds;    
        var timep = document.getElementById("time");
    timep.innerHTML = time;
    ntimeoutId = setTimeout(ntimeOut, 1000);
}

  1. First, set a timeout call to display the current system time by calling the method for the first time. The reason why the time is set to 0 , is to display the time without delay.

2. Clear the previous timeout call before each loop (why you need to do this, I don’t know yet??? It may be related to memory performance, commented The program can be executed normally in the future. )

 3. Obtain the current system time and save it in a certain string format.

4. In order to dynamically display it on the page, an empty p element is defined in the Html page to store the time string. Use DOM manipulation to add it to the p element to display it dynamically.

5. By continuously looping the timeout call, the digital clock can be dynamically displayed. You can also see the dynamic changes in the p element through the developer tools.

The next step is to create a disk clock animation. The depiction of the disk and the numerical value is relatively simple. Just use the context.arc() method and context Just use the .fillText() method. The following is its source code:


     context.beginPath();
        context.restore();
        context.translate(0,0);
        context.clearRect(0,0,300,300);        //绘制时钟内外边框
        context.arc(150,150,149,0,2 * Math.PI,false);
        context.moveTo(295,150);
        context.arc(150,150,145,0,2 * Math.PI,false);

        context.font = "bold 18px Arial";
        context.textAlign = "center";        //绘制时钟表盘数值
        context.fillText("12",150,25);
        context.fillText("3",285,150);
        context.fillText("6",150,290);
        context.fillText("9",15,150);
        context.fillText("1",215,45);
        context.fillText("2",265,95);
        context.fillText("4",265,225);
        context.fillText("7",95,275);
        context.fillText("5",215,275);
        context.fillText("8",35,225);
        context.fillText("10",35,95);
        context.fillText("11",75,45);

        context.stroke();
        context.closePath();

 The next step is to draw the pointer. When drawing the pointer, refer to the method in elevation. Use It is much more convenient to use the context.translate() method to change the origin of the transformation operation, and then draw the path as a pointer. Another difficulty in drawing pointers is the calculation of radians. Of course, this is a mathematical problem. Let’s look at the source code first:


     //绘制指针        context.save();
        context.translate(150,150);        //时针
        context.moveTo(0,0);
        hour(hours);        function hour(thour) {
            context.save();            
            var newhour = 0;            
            if(thour>12) {
                newhour = thour-12;
            } else {
                newhour = thour;
            }
            context.rotate((2*Math.PI/12)*newhour);
            context.lineTo(0,-80);
            context.restore();
        }        //分针
        context.moveTo(0,0);
        minute(minutes);        function minute(tminute) {
            context.save();
            context.rotate((2*Math.PI/12)*tminute/5);
            context.lineTo(0,-110);
            context.restore();
        }        //秒针
        context.moveTo(0,0);
        second(seconds);        function second(tsecond) {
            context.save();
            context.fillStyle = "#fff";
            context.rotate((2*Math.PI/12)*tsecond/5);
            context.lineTo(0,-120);
            context.restore();
        }
        
        context.stroke();

In drawing pointers, each type of pointer uses a function to change the arc of each pointer drawing. Animation effect of pointer rotation. For the hour hand, convert the twenty-four-hour clock into the twelve-hour clock and rotate it 30° each time. The minute hand and second hand rotate from 0 to 11. I believe everyone is better at simple math problems than me. I was still struggling for a while. The context.save() method and the context.restore() method are used in each function to save and restore the path during initialization, otherwise the pointer will go off track.

All the work is basically ready. Next, we only need to place the clock dial and pointers in the timeout call. However, there are still some issues that need attention, such as the clock dial and pointers. The origin settings are different, so be careful to use save and restore to restore the path during initialization, otherwise the clock dial and hands will go off track. Another thing to note is that when using Canvas to create animations, each animation cycle must clear the canvas and redraw it, otherwise the pointer will keep spinning and turn into a flower.

The complete disc clock code is as follows:


//显示指针时间var drawing = document.getElementById("drawing");if(drawing.getContext) {    
var context = drawing.getContext("2d");    
var rtimeoutId = setTimeout(roudClock,0);    
function roudClock() {
        clearTimeout(rtimeoutId);

        context.beginPath();
        context.restore();
        context.translate(0,0);
        context.clearRect(0,0,300,300);        //绘制时钟内外边框
                context.arc(150,150,149,0,2 * Math.PI,false);
        context.moveTo(295,150);
        context.arc(150,150,145,0,2 * Math.PI,false);

        context.font = "bold 18px Arial";
        context.textAlign = "center";        //绘制时钟表盘数值
                context.fillText("12",150,25);
        context.fillText("3",285,150);
        context.fillText("6",150,290);
        context.fillText("9",15,150);
        context.fillText("1",215,45);
        context.fillText("2",265,95);
        context.fillText("4",265,225);
        context.fillText("7",95,275);
        context.fillText("5",215,275);
        context.fillText("8",35,225);
        context.fillText("10",35,95);
        context.fillText("11",75,45);

        context.stroke();
        context.closePath();        
        var now = new Date();        
        var hours = now.getHours(),
            minutes = now.getMinutes(),
            seconds = now.getSeconds();        //绘制指针        
            context.save();
        context.translate(150,150);        //时针
                context.moveTo(0,0);
        hour(hours);        
        function hour(thour) {
            context.save();            
            var newhour = 0;            
            if(thour>12) {
                newhour = thour-12;
            } else {
                newhour = thour;
            }
            context.rotate((2*Math.PI/12)*newhour);
                        context.lineTo(0,-80);
            context.restore();
        }        //分针
           context.moveTo(0,0);
        minute(minutes);        
        function minute(tminute) {
            context.save();
            context.rotate((2*Math.PI/12)*tminute/5);
            context.lineTo(0,-110);
            context.restore();
        }        //秒针
                context.moveTo(0,0);
        second(seconds);        
        function second(tsecond) {
            context.save();
            context.fillStyle = "#fff";
            context.rotate((2*Math.PI/12)*tsecond/5);
            context.lineTo(0,-120);
            context.restore();
        }
        
        context.stroke();
        context.restore();
        context.translate(0,0);
        context.save();
        rtimeoutId = setTimeout(roudClock,1000);
    }    
}

Finally summarize my experience in this demo Several problems encountered during the exercise:

1. Canvas redrawing problem

When the pointer animation loops, there is no way to clear the previous path, causing each loop to leave a mark. I tried using the clearRect() method in a small range, but found that it could only clear the contents of the dial and numbers within the range, and the pointer would still leave traces. Later, through searching, the answer I got was that when using Canvas to create animations, it must be redrawn. The canvas content must be cleared before drawing new content, and every animation change must be cleared. For the redraw method, please refer to the link. I use the clearRect() method to clear the entire canvas.

 2. Use of save() method and restore() method

Because the origin settings of my clock dial and pointer are different, Therefore, after redrawing, the origin of the clock dial will change to the origin of the pointer, so the save() method and restore() method must be used to change it. In addition to this place, there are also other places that need to be used. It is suitable for situations where the settings are changed after the operation, but the original settings need to be used for subsequent operations. Note that these two methods will only save and restore settings, not content.

 3. Use of translate() method

The translate() method belongs to the transformation operation and can change the origin of the canvas. The default The origin of the canvas is at the upper left corner of the canvas. Using this method makes it easier to draw the pointer's path. Of course, there are some other uses that I haven't touched yet.

4. Use of setTimeout() method

Using timeout calls is a better method than intermittent calls. Using timeout calls can simulate intermittent calls. transfer. A loop can be simulated nicely by adding a timeout call within the function that the timeout call is passed in. You can also limit the number and time of loops based on some conditions in the function.

5. Corresponding to the current time, how to use radians

This is a mathematical problem. I struggled with this problem for a while, but I didn’t turn. After turning around, it is no longer a technical problem to understand the principle.

 6. Regarding the problem of repeated time acquisition and repeated use methods

 For the situation where there are repeated codes in the code, I haven't thought of a better way to reduce redundancy. For example, in terms of acquisition time, there are repeated definitions in the two timeout calls, but if they are placed globally, there will be no animation effect, and only the static time after the loading is completed will be displayed. Another thing is that there are repeated parts in the function setting of the pointer. Can it be combined into one function method and then called?

Everyone is welcome to put forward ideas, make suggestions for shortcomings, and communicate together.

The above is the detailed content of How to create clock animation using Canvas. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn