The effect is shown in Figure 1:

Canvas ring countdown

Canvas ring countdown is a countdown based on Canvas. It is recommended to use Canvas ring countdown to download the address on the mobile terminal

A, how to use

1. The HTML code

The ID attribute can be arbitrarily named

<canvas id="canvas"></canvas>
Copy the code

2. Import the process.js file

Page reference

<script src="js/process.js"></script>
Copy the code

3. Initialize parameters

Instantiate it

<script>
    window.onload = function () {
        let ctd = new Countdown();
        ctd.init();
    };

</script>
Copy the code

2. Settings Parameter Description

The following parameters are optional and can be set based on site requirements

window.onload = function () {
        let ctd = new Countdown();
        ctd.init({
            id: "canvas", // ID, canvas must have ID attribute size: 130, // draw the maximum size of the circle, width = high borderWidth: 4, // borderWidth borderColor:"#fff"OuterColor:"#fff"// The outer bottom circle color scheduleColor:"#fff"// Progress bar animation color fontColor:"#fff", // Font color ringColor:"#ffc720"// Progress bar innerColor:"#4e84e5",// fontSize: 50, time: 5}); };Copy the code

Three, sample code

html

<! DOCTYPE html> <html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            background: #c2c1ce;
        }
        .container {
            position: absolute;
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%);
            width: 130px;
            height: 130px;
            text-align: center;
        }
    </style>
</head>
<body>
<div class="container">
    <canvas class="canvas" id="canvas"></canvas>
</div>
<script src="js/process.js"></script>
<script>
    window.onload = function () {
        let ctd = new Countdown();
        ctd.init();
    };
</script>
</body>
</html>
Copy the code

js

/** * Created by createcount on 2018/3/15. */function Countdown() {// Set the default parameter this. Settings = {id:"canvas", // ID, canvas must have ID attribute size: 130, // draw the maximum size of the circle, width = high borderWidth: 4, // borderWidth borderColor:"#fff"OuterColor:"#fff"// The outer bottom circle color scheduleColor:"#fff"// Progress bar animation color fontColor:"#fff", // Font color ringColor:"#ffc720"// Progress bar innerColor:"#4e84e5"}} countdown.prototype.init = // countdown.prototype = // countdown.prototype.init =function (opt) {
    this.obj = document.getElementById(this.settings.id);
    this.obj.width = this.settings.size;
    this.obj.height = this.settings.size;
    this.ctx = this.obj.getContext("2d"); extend(this.settings, opt); this.countdown(); }; / / draw the background Countdown. Prototype. DrawBackground =function() { this.drawCircle(0, 360, 0, this.settings.outerColor); }; / / draw the progress bar animation background Countdown. Prototype. DrawProcess =function() { this.drawCircle(0, 360, 4, this.settings.ringColor); }; / / draw the Countdown Countdown. Prototype. DrawInner =function() { this.drawCircle(0, 360, 23, this.settings.innerColor); this.strokeBorder(this.settings.borderWidth); }; / / draw the progress bar animation Countdown. Prototype. DrawAnimate =function() {// Rotation Anglelet deg = Math.PI / 180;
    let v = schedule * 360,
        startAng = -90,
        endAng = -90 + v;

    this.ctx.beginPath();
    this.ctx.moveTo(this.settings.size / 2, this.settings.size / 2);
    this.ctx.arc(this.settings.size / 2, this.settings.size / 2, this.settings.size / 2 -3, startAng * deg, endAng * deg, false); this.ctx.fillStyle = this.settings.scheduleColor; this.ctx.fill(); this.ctx.closePath(); }; / / draw frame Countdown. Prototype. StrokeBorder =function(borderWidth) { this.ctx.lineWidth = borderWidth; this.ctx.strokeStyle = this.settings.borderColor; this.ctx.stroke(); }; / / draw the literal Countdown. Prototype. StrokeText =function (text) {
    this.ctx.textAlign = "center";
    this.ctx.textBaseline = "middle";
    this.ctx.font = this.settings.fontSize+"px"+ " microsoft yahei"; this.ctx.fillStyle = this.settings.fontColor; this.ctx.fillText(text, this.settings.size / 2, this.settings.size / 2); }; / / draw the circle Countdown. Prototype. Methods like drawCircle =function (startAng, endAng, border, fillColor) {
    let deg = Math.PI / 180;
    this.ctx.beginPath();
    this.ctx.arc(this.settings.size / 2, this.settings.size / 2, this.settings.size / 2 -border, startAng * deg, endAng * deg, false); this.ctx.fillStyle = fillColor; this.ctx.fill(); this.ctx.closePath(); }; / / the progress bar animation Countdown. Prototype. Countdown =function () {
    let oldTime = +new Date();
    timer = setInterval(() => {
        letAllMs = this.settings.time *1000, currentTime = +new Date(); // step size = (currentTime - past time)/total seconds schedule = (currenttime-oldtime)/allMs; this.schedule = schedule; this.drawAll(schedule);if(currentTime-oldTime >= allMs) {// Redraw this.drawbackground (); this.drawProcess(); this.drawAnimate(); this.drawInner(); this.strokeText(0); clearInterval(timer); }}, 100); }; / / to draw all the Countdown. Prototype. DrawAll =function (schedule) {
    schedule = schedule >= 1 ? 1 : schedule;
    lettext = parseInt(this.settings.time * (1 - schedule)) + 1; // Clear the canvas this.ctx.clearRect(0, 0, this.settings.size, this.settings.size); this.drawBackground(); this.drawProcess(); this.drawAnimate(); this.drawInner(); this.strokeText(text); }; // Object copyfunction extend(obj1,obj2){
    for(let attr inobj2){ obj1[attr] = obj2[attr]; }}Copy the code

Iv. Additional — Canvas preparation

Canvas is not so mysterious, it is nothing more than an H5 tag, just like other HTML tags:

<canvas id="canvas"></canvas>  
Copy the code

Note that it is better to set the width and height of the canvas at the beginning (if you do not set the width and height, the browser will set the canvas size as 300 pixels wide and 100 pixels high by default), and you cannot use CSS to set it (it will be stretched). It is recommended to write it directly inside the canvas tag:

<canvas id="canvas" width="130" height="130"></canvas>
Copy the code

Canvas itself does not have any drawing ability, all drawing work is realized through JS. We usually use getElementById in JS to get the canvas we want to manipulate (which means we have to give the canvas an ID) :

var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
Copy the code

Circles are concentric circles with different radii. The coordinates of the center of the circle are (size/2,size/2). First draw a circle with the largest white background and the radius is size/2.

letdeg = Math.PI / 180; // beginPath() can be used to isolate the effect of the path drawing and prevent the previous effect from being polluted. ctx.beginPath(); // tcx.arc(center X, center Y, radius, start Angle, end Angle, clockwise); ctx.arc(size / 2, size / 2, size / 2, 0* deg, 360 * deg,false);
ctx.fillStyle = "#fff";
ctx.fill();
ctx.closePath();

Copy the code

(size/2, size/2) (size/2, size/2) (size/2-4)

letdeg = Math.PI / 180; // beginPath() can be used to isolate the effect of the path drawing and prevent the previous effect from being polluted. ctx.beginPath(); // tcx.arc(center X, center Y, radius, start Angle, end Angle, clockwise); ctx.arc(size / 2, size / 2, size / 2-4, 0* deg, 360 * deg,false);
ctx.fillStyle = "#fff";
ctx.fill();
ctx.closePath();

Copy the code

3. Start drawing a blue inner circle with a center of (size/2,size/2) and a radius of (size-23), and add a 4px white border to it.

letdeg = Math.PI / 180; // beginPath() can be used to isolate the effect of the path drawing and prevent the previous effect from being polluted. ctx.beginPath(); // tcx.arc(center X, center Y, radius, start Angle, end Angle, clockwise); ctx.arc(size / 2, size / 2, size / 2-23, 0* deg, 360 * deg,false);
ctx.fillStyle = "#fff"; ctx.fill(); ctx.closePath(); // white border ctx.lineWidth = 4; ctx.strokeStyle =#fff;
ctx.stroke();
Copy the code

4. Draw text vertically centered

ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#fff"; // ctx.fillText(30, size / 2, size / 2); // ctx.filltext (30, size / 2, size / 2);Copy the code

5. How to animate? In fact, it is also the process of drawing the white circle and slowly covering the yellow progress bar, so draw the white circle first, then the blue circle will be covered by the white animation circle, and then draw the blue circle at last.

letdeg = Math.PI / 180; ctx.beginPath(); // tcx.arc(center X, center Y, radius, start Angle, end Angle, clockwise); ctx.arc(size / 2, size / 2, size / 2-4, 0* deg, 360 * deg,false);
ctx.fillStyle = "#fff";
ctx.fill();
ctx.closePath();
Copy the code

6. The relatively simple drawing process is completed, and the next step is to associate the animation with the numbers. Using the current latest time – the beginning time, divide the total time to get a key percentage, which determines the number changes and the Angle of the white animation circle.

Countdown.prototype.countdown = function () {
    letoldTime = +new Date(); // Past time: 1522136419291 timer =setInterval(() => {
        letcurrentTime = +new Date(); // Current time: 1522136419393letallMs = this.settings.time * 1000; // Schedule = (currentTime-oldTime)/allMs; // draw percentage :(1522136419393-1522136419291) /30000=0.0204 this.schedule = schedule; this.drawAll(schedule);if(currentTime-oldTime >= allMs) {// Redraw this.drawbackground (); this.drawProcess(); this.drawAnimate(); this.drawInner(); this.strokeText(0); clearInterval(timer); }}, 10); }; / / to draw all the Countdown. Prototype. DrawAll =function (schedule) {
    schedule = schedule >= 1 ? 1 : schedule;
    lettext = parseInt(this.settings.time * (1 - schedule)) + 1; // Clear the canvas this.ctx.clearRect(0, 0, this.settings.size, this.settings.size); this.drawBackground(); this.drawProcess(); this.drawAnimate(); this.drawInner(); this.strokeText(text); }; / / draw the progress bar animation Countdown. Prototype. DrawAnimate =function() {// Rotation Anglelet deg = Math.PI / 180;
    letV = schedule * 360, startAng = -90, endAng = -90 + v; This.ctx.beginpath (); this.ctx.moveTo(this.settings.size / 2, this.settings.size / 2); this.ctx.arc(this.settings.size / 2, this.settings.size / 2, this.settings.size / 2 - 3, startAng * deg, endAng * deg,false);
    this.ctx.fillStyle = this.settings.scheduleColor;
    this.ctx.fill();
    this.ctx.closePath();
};
Copy the code

Procedural version

/** * Countdown:function() {this.getSystemInfo().then(v => {// adaptiveletwidth = v.windowWidth, size = width >= 414 ? 66/400/414 * 66; size = parseInt(size); size = size % 2 ? size + 1 : size;let maxtime =30,
                sTime = +new Date,

                temp = setInterval(() => {
                    let time = maxtime * 1000,
                        currentTime = +new Date,
                        schedule = (currentTime - sTime) / time;

                    this.drew(schedule, maxtime, size);

                    if(currentTime-stime >= time) {// Draw text this.setData({schedule: 0}); clearInterval(temp); }; }, 100); }); }, /** * draw */ drew:function (schedule, val, size) {
        size = size || 66;
        const _ts = this;
        schedule = schedule >= 1 ? 1 : schedule;

        lettext = parseInt(val - val * schedule), r = size / 2, deg = Math.PI / 180; _ts.setData({ width: size, height: size, schedule: text + 1 }); // Clear the canvas ctx.clearRect(0, 0, size, size); // Draw a white background ctx.beginPath(); ctx.arc(r, r, r, 0 * deg, 360 * deg); ctx.fillStyle ='rgba(255,255,255,1)'; ctx.closePath(); ctx.fill(); // Draw orange ctx.beginPath(); ctx.arc(r, r, r - 2, 0 * deg, 360 * deg); ctx.fillStyle ='rgba(248,200,80,1)'; ctx.closePath(); ctx.fill(); // Draw a white progress barlet v = schedule * 360;

        ctx.beginPath();
        ctx.moveTo(r, r);
        ctx.arc(r, r, r, -90 * deg, (-90 + v) * deg);

        ctx.fillStyle = 'rgba(255,255,255,1)'; ctx.closePath(); ctx.fill(); // Center blue bottom ctx.beginPath(); ctx.arc(r, r, r - 12, 0 * deg, 360 * deg); ctx.fillStyle ='rgba(90,140,220,1)'; ctx.closePath(); ctx.fill(); // Draw the text ctx.stroketext (); // draw ctx.draw(); },Copy the code