Final effect
Definition of initial variables
let radius = 140 //Outer ring radius let thickness = 20 //Ring thickness let innerRadius = radius - thickness //Inner Ring Radius let startAngle = -90 //Beginning Angle let endAngle = 180 //End Angle let x = 0 //Centroid x coordinates let y = 0 //Centroid 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 } //Radian rotation angle function radian2Angle(radian) { return 180 * radian / Math.PI } //radians function angle2Radian(angle) { return angle * Math.PI / 180 }
3. Rendering methods
//renderer function renderRing(startAngle, endAngle) { ctx.beginPath(); //Drawing Outer Ring ctx.arc(x, y, radius, angle2Radian(startAngle), angle2Radian(endAngle)) //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) //Draw the ring at the first connection between the outer ring and the inner ring ctx.arc(oneCtrlPoint.x, oneCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270)) //Drawing inner rings ctx.arc(x, y, innerRadius, angle2Radian(endAngle), angle2Radian(startAngle), true) //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) //Draw the ring at the second connection between the outer ring and the inner ring ctx.arc(twoCtrlPoint.x, twoCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270)) 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"> <head> <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> </head> <body> <div class="ring"> <canvas id="tutorial"></canvas> <span class="fraction"><span class="number">0</span> <span class="small">branch</span> </span> <span class="title">Service score</span> </div> <script> let radius = 140 //Outer ring radius let thickness = 20 //Ring thickness let innerRadius = radius - thickness //Inner Ring Radius let startAngle = -90 //Beginning Angle let endAngle = 180 //End Angle let x = 0 //Centroid x coordinates let y = 0 //Centroid 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) //renderer function renderRing(startAngle, endAngle) { ctx.beginPath(); //Drawing Outer Ring ctx.arc(x, y, radius, angle2Radian(startAngle), angle2Radian(endAngle)) //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) //Draw the ring at the first connection between the outer ring and the inner ring ctx.arc(oneCtrlPoint.x, oneCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270)) // // Drawing inner rings ctx.arc(x, y, innerRadius, angle2Radian(endAngle), angle2Radian(startAngle), true) //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) //Draw the ring at the second connection between the outer ring and the inner ring ctx.arc(twoCtrlPoint.x, twoCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270)) 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 } //Radian rotation angle function radian2Angle(radian) { return 180 * radian / Math.PI } //radians function angle2Radian(angle) { return angle * Math.PI / 180 } </script> </body> </html>