<!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>html5 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: #00ABEB;
}
.small {
font-size: 12px;
font-weight: lighter;
}
.title {
font-size: 20px;
color: #00ABEB;
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">%</span> </span>
<span class="title">已領優惠券</span>
</div>
<script>
let radius = 95 //外環半徑
let thickness = 10 //圓環厚度
let innerRadius = radius - thickness //內環半徑
let startAngle = -90 //開始角度
let endAngle = 180 //結束角度
let x = 0 //圓心x坐標
let y = 0 //圓心y坐標
let canvas = document.getElementById('tutorial');
canvas.width = 300;
canvas.height = 300;
let ctx = canvas.getContext('2d');
ctx.translate(canvas.width / 2, canvas.height / 2); //將繪圖原點移到畫布中央
ctx.rotate(angle2Radian(225)) //將畫布旋轉225度
ctx.fillStyle = "#eee"; //初始填充顏色
renderRing(startAngle, endAngle)
//渲染函數
function renderRing(startAngle, endAngle) {
ctx.beginPath();
//繪制外環
ctx.arc(x, y, radius, angle2Radian(startAngle), angle2Radian(endAngle))
//計算外環與內環第一個連接處的中心坐標
let oneCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, endAngle)
//繪制外環與內環第一個連接處的圓環
ctx.arc(oneCtrlPoint.x, oneCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270))
// //繪制內環
ctx.arc(x, y, innerRadius, angle2Radian(endAngle), angle2Radian(startAngle), true)
//計算外環與內環第二個連接處的中心坐標
let twoCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, startAngle)
//繪制外環與內環第二個連接處的圓環
ctx.arc(twoCtrlPoint.x, twoCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270))
ctx.fill()
// ctx.stroke()
}
//計算圓環上點的坐標
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
}
//弧度轉角度
function radian2Angle(radian) {
return 180 * radian / Math.PI
}
//角度轉弧度
function angle2Radian(angle) {
return angle * Math.PI / 180
}
//進度條顏色
var lingrad = ctx.createLinearGradient(0, 0, 150, 0);
lingrad.addColorStop(0, '#00ABEB');
lingrad.addColorStop(1, '#fff');
ctx.fillStyle = lingrad
//開始繪畫
let tempAngle = startAngle
let total = 1000 //總分
let now = 900 //當前分數
let percent = now / total //百分比
let twoEndAngle = percent * 270 + startAngle
let step = (twoEndAngle - startAngle) / 80
let numberSpan = document.querySelector('.number')
let inter = setInterval(() => {
if (tempAngle > twoEndAngle) {
clearInterval(inter)
} else {
numberSpan.innerText = percent * 100
tempAngle += step
}
renderRing(startAngle, tempAngle)
}, 20)
</script>
</body>
</html>

<!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>html5 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: #00ABEB;
}
.small {
font-size: 12px;
font-weight: lighter;
}
.title {
font-size: 20px;
color: #00ABEB;
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">%</span> </span>
</div>
<script>
let radius = 95 //外環半徑
let thickness = 10 //圓環厚度
let innerRadius = radius - thickness //內環半徑
let startAngle = 0 //開始角度
let endAngle = 360 //結束角度
let x = 0 //圓心x坐標
let y = 0 //圓心y坐標
let canvas = document.getElementById('tutorial');
canvas.width = 300;
canvas.height = 300;
let ctx = canvas.getContext('2d');
ctx.translate(canvas.width / 2, canvas.height / 2); //將繪圖原點移到畫布中央
ctx.rotate(angle2Radian(225)) //將畫布旋轉225度
ctx.fillStyle = "#eee"; //初始填充顏色
renderRing(startAngle, endAngle)
//渲染函數
function renderRing(startAngle, endAngle) {
ctx.beginPath();
//繪制外環
ctx.arc(x, y, radius, angle2Radian(startAngle), angle2Radian(endAngle))
//計算外環與內環第一個連接處的中心坐標
let oneCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, endAngle)
//繪制外環與內環第一個連接處的圓環
ctx.arc(oneCtrlPoint.x, oneCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270))
// //繪制內環
ctx.arc(x, y, innerRadius, angle2Radian(endAngle), angle2Radian(startAngle), true)
//計算外環與內環第二個連接處的中心坐標
let twoCtrlPoint = calcRingPoint(x, y, innerRadius + thickness / 2, startAngle)
//繪制外環與內環第二個連接處的圓環
ctx.arc(twoCtrlPoint.x, twoCtrlPoint.y, thickness / 2, angle2Radian(-90), angle2Radian(270))
ctx.fill()
// ctx.stroke()
}
//計算圓環上點的坐標
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
}
//弧度轉角度
function radian2Angle(radian) {
return 180 * radian / Math.PI
}
//角度轉弧度
function angle2Radian(angle) {
return angle * Math.PI / 180
}
//進度條顏色
var lingrad = ctx.createLinearGradient(0, 0, 150, 0);
lingrad.addColorStop(0, '#00ABEB');
lingrad.addColorStop(1, '#fff');
ctx.fillStyle = lingrad
//開始繪畫
let tempAngle = startAngle
let total = 1000 //總分
let now = 1000 //當前分數
let percent = now / total //百分比
let twoEndAngle = percent * 360 + startAngle
let step = (twoEndAngle - startAngle) / 80
let numberSpan = document.querySelector('.number')
let inter = setInterval(() => {
if (tempAngle > twoEndAngle) {
clearInterval(inter)
} else {
numberSpan.innerText = percent * 100
tempAngle += step
}
renderRing(startAngle, tempAngle)
}, 20)
</script>
</body>
</html>

