# Canvas Draws Dynamic Progress Bar Ring

Time：2019-8-24

Final effect

## Definition of initial variables

``````Let radius = 140 // outer ring radius
Let thickness = 20 // ring thickness
Let start Angle = 90 // start angle
Let endAngle = 180// End Angle
Let x = 0 // center x coordinates
Let y = 0 // center y coordinates
let canvas = document.getElementById('tutorial');
canvas.width = 300;
canvas.height = 300;

let ctx = canvas.getContext('2d');
Ctx.translate (canvas.width/2, canvas.height/2); //Move the drawing origin to the center of the canvas
Ctx. rotate (angle2Radian (225)// Rotate the canvas 225 degrees
Ctx.fillStyle = " f2d7d7";//Initial fill color``````

## II. Tool Approach

``````// Calculating the coordinates of points on a ring
function calcRingPoint(x, y, radius, angle) {
let res = {}
res.x = x + radius * Math.cos(angle * Math.PI / 180)
res.y = y + radius * Math.sin(angle * Math.PI / 180)
return res
}

return 180 * radian / Math.PI
}

return angle * Math.PI / 180
}``````

## 3. Rendering methods

``````// Rendering function
function renderRing(startAngle, endAngle) {
ctx.beginPath();

// Drawing Outer Ring

// Calculate the central coordinates of the first connection between the outer ring and the inner ring
let oneCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, endAngle)

// Drawing Outer Ring与内环第一个连接处的圆环

// Drawing inner rings

// Calculate the central coordinates of the second connection between the outer ring and the inner ring
let twoCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, startAngle)

// Drawing Outer Ring与内环第二个连接处的圆环

ctx.fill()
// ctx.stroke()
}``````

### Specific ideas:

For convenience, all places where radians are used in code change from angles to radians.

1. Draw the outer ring:

This step is the simplest and can be used directly according to the official usage method.

2. Draw the first ring at the junction of the outer ring and the inner ring.

First, the coordinates of the middle point at the end of the outer ring and the beginning of the inner ring are calculated.

The coordinate formulas for calculating points on a ring are as follows:

x = x + radius Math.cos(angle Math.PI / 180)
y = y + radius Math.sin(angle Math.PI / 180)

By substituting the above formulas, the coordinates of any point on the ring can be calculated, and then the ring can be drawn with the center of the ring and the thickness of the ring/2 as the radius.

3. Drawing inner rings

This step only needs to shorten the radius and change the starting and ending angles of the drawing outer ring.

4. Draw the second ring at the junction of the inner ring and the outer ring.

In the same way as the second step, the coordinates of the middle point at the beginning of the outer ring and the end of the inner ring are calculated, and then the circle is drawn with the center of the circle and the thickness of the circle/2 as the radius.

5. Complete filling
At this point, the circle is finished.

## IV. Dynamic Progress Bar

``````// Progress Bar Animation
ctx.fillStyle = "#e87c7c";
let tempAngle = startAngle
let twoEndAngle = 0
let step = (twoEndAngle - startAngle) / 100
let numberSpan = document.querySelector('.number')
let count = 0
let inter = setInterval(() => {
if (tempAngle > twoEndAngle) {
clearInterval(inter)
} else {
count++
numberSpan.innerText = count
tempAngle += step
}
renderRing(startAngle, tempAngle)
}, 16.7)``````

The end angle is calculated dynamically, and then a counter is set to repeat the rendering method.

## V. Complete Code

``````<!DOCTYPE html>
<html lang="cn">

<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>canvas</title>
<style>
.ring {
width: 300px;
height: 300px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
}

.fraction {
position: absolute;
font-size: 30px;
font-weight: bold;
color: red;
}

.small {
font-size: 12px;
font-weight: lighter;
}

.title {
font-size: 20px;
color: red;
bottom: 40px;
position: absolute;
}
</style>

<body>
<div class="ring">
<canvas id="tutorial"></canvas>
<span class="fraction">span class="number">0</span> <span class="small">score</span></span>
<span class="title">service score</span>
</div>

<script>
Let thickness = 20 // ring thickness
Let start Angle = 90 // start angle
Let endAngle = 180// End Angle
Let x = 0 // center x coordinates
Let y = 0 // center y coordinates
let canvas = document.getElementById('tutorial');
canvas.width = 300;
canvas.height = 300;

let ctx = canvas.getContext('2d');
Ctx.translate (canvas.width/2, canvas.height/2); //Move the drawing origin to the center of the canvas
Ctx. rotate (angle2Radian (225)// Rotate the canvas 225 degrees
Ctx.fillStyle = " f2d7d7";//Initial fill color

renderRing(startAngle, endAngle)

// Progress Bar Animation
ctx.fillStyle = "#e87c7c";
let tempAngle = startAngle
let twoEndAngle = 0
let step = (twoEndAngle - startAngle) / 100
let numberSpan = document.querySelector('.number')
let count = 0
let inter = setInterval(() => {
if (tempAngle > twoEndAngle) {
clearInterval(inter)
} else {
count++
numberSpan.innerText = count
tempAngle += step
}
renderRing(startAngle, tempAngle)
}, 16.7)

// Rendering function
function renderRing(startAngle, endAngle) {
ctx.beginPath();

// Drawing Outer Ring

// Calculate the central coordinates of the first connection between the outer ring and the inner ring
let oneCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, endAngle)

// Drawing Outer Ring与内环第一个连接处的圆环

//// Drawing inner rings

// Calculate the central coordinates of the second connection between the outer ring and the inner ring
let twoCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, startAngle)

// Drawing Outer Ring与内环第二个连接处的圆环

ctx.fill()
// ctx.stroke()
}

// Calculating the coordinates of points on a ring
function calcRingPoint(x, y, radius, angle) {
let res = {}
res.x = x + radius * Math.cos(angle * Math.PI / 180)
res.y = y + radius * Math.sin(angle * Math.PI / 180)
return res
}

return 180 * radian / Math.PI
}